Second release

This commit is contained in:
Diogo Cordeiro 2018-04-03 09:13:42 +00:00
parent 742b86edbb
commit 11a998dd3b
24 changed files with 1157 additions and 4077 deletions

102
INSTALL Normal file
View File

@ -0,0 +1,102 @@
TABLE OF CONTENTS
=================
* Installation
- Getting the offline mode up and running
- Getting the online mode up and running
* Settings
- Number of Leds
- Show labels
- Easter Egg
- Change leds image and theme
Installation
============
Getting the offline mode up and running
---------------------------------------
Installing the basic Fun with Binary in offline mode is relatively easy.
1. Unpack the tarball you downloaded on your Web server. Usually a
command like this will work:
tar zxf funwithbinary-*.tar.gz
...which will make a funwithbinary-x.y.z subdirectory in your current
directory. (If you don't have shell access on your Web server, you
may have to unpack the tarball on your local computer and FTP the
files to the server.)
2. Move the tarball to a directory of your choosing in your Web root
directory. Usually something like this will work:
mv funwithbinary-x.y.z /var/www/funwithbinary
This will often make your Fun with Binary copy available in the funwithbinary
path of your server, like "http://example.net/funwithbinary". If you know how
to configure virtual hosts on your web server, you can try setting up
"http://funwithbinary.example.net/" or the like.
3. You should now be able to navigate to your funwithbinary site's main
directory and play :)
Getting the online mode up and running
--------------------------------------
Installing the basic Fun with Binary in offline mode is relatively easy.
1. Unpack the tarball you downloaded on your computer. Usually a
command like this will work:
tar zxf funwithbinary-*.tar.gz
...which will make a funwithbinary-x.y.z subdirectory in your current
directory.
2. Minify the style.css with https://css.github.io/csso/csso.html and replace
the line after <!-- CSS --> in the index.html with the result inside the tags
<style>*result*</style>
3. In the script.js file enable the online mode in the Game Settings section,
by changing "ONLINE_MODE = false; " to "ONLINE_MODE = true;"
4. Minify the script.js with http://lisperator.net/uglifyjs/ and replace the
line after <!-- JS --> in the index.html with the result inside the tags
<script>*result*</script>
5. Make the resulting HTM usable with the following tool:
https://github.com/CytronTechnologies/ESP8266-WiFi-Module/raw/master/convertHtml/convertHtml.jar
6. Upload the resulting code to the arduino board
7. You should now be able to play :)
Settings
========
Number of Leds
--------------
You can change the number of leds by editing the N_LEDS constant in the
Game Settings section of the script.js file. If you are using the Online Mode
you should also change the constant of the same name in the section of same name
in the server.ino file as well as adjust the LED GPIO array.
Show labels
-----------
You can change the default value of this option by editing the "show_labels"
variable in the Game Settings section of the script.js file. You can also
completely disable this feature by changing the value of HAVE_LABELS constant.
Easter Egg
----------
You can disable the easter egg by editing the EASTER_EGG constant in the
Game Settings section of the script.js file.
Change leds image and theme
---------------------------
You can change the LED_OFF and LED_ON paths in the Game Settings section of the
script.js file.

View File

@ -11,31 +11,21 @@ Further information about Fun with Binary can be found in the project home page:
## Getting Started
Fun with Binary is divided in three components, the Client, the Server, the Output.
Fun with Binary has two different modes:
- Online: Which has a little body to make everything more interactive.
- Offline: Which is more independent and can be used right away without any further technicality by accessing: [https://www.diogo.site/projects/fun_with_binary/offlinev2.html](https://www.diogo.site/projects/fun_with_binary/offlinev2.html)
### Prerequisites
### Server
### Offline Mode
For the server you need a webserver with PHP support (it can be localhost).
There are no special prerequisites for the offline mode.
### Client
### Online Mode
You can run it in the same server's webserver, although a ready to use live client was made avaiable in the folowing address:
At least: Arduino Uno with ESP8266-01, 6 leds (and 6 resistors), wires, breadboard.
```
http://diogo.site/projects/fun_with_binary/client/
```
Despite that, it might be interesting to convert it in an actual mobile app :)
### Output
For the Arduino based output you obviously need an arduino, 6 leds (from which three of them must be red and the other three of another color).
## Built With
* [Ratchet](https://github.com/twbs/ratchet) - The mobile targeted web framework used in the client
Some instruction of how to build it can be found on my blog post about this project: [https://blog.diogo.site/posts/fun-with-binary](https://blog.diogo.site/posts/fun-with-binary)
## Versioning
@ -43,7 +33,7 @@ I use [SemVer](http://semver.org/) for versioning. For the versions available, s
## Authors
* **Diogo Cordeiro** - *Initial work* - [Fun with Binary](https://gitlab.com/up201705417/fun-with-binary)
* **Diogo Cordeiro**
## License
@ -69,8 +59,22 @@ License along with this program, in the file "COPYING". If not, see
of using the software, and if you do not wish to share your
modifications, *YOU MAY NOT INSTALL FUN WITH BINARY*.
Additional library software has been made available (and were referenced
in the "Built With" section). All of it is Free Software and can be
distributed under liberal terms, but those terms may differ in detail
from the AGPL's particulars. See each package's license file in their
official repository for additional terms.
Additional library software has been made available. All of it is Free Software
and can be distributed under liberal terms, but those terms may differ in detail
from the AGPL's particulars. See each package's license file in their official
repository for additional terms.
## New this version
This is version 2.0 of Fun with Binary and includes the following (key) changes
from the previous one:
- Client <-> Server <-> Arduino was replaced by a Client <-> Arduino structure
- ESP8266 is now required for Access Point purposes
- Both modes have become PHP independent (mostly relevant in the offline one)
The last release, 2.0, gave us these improvements:
- Significant visual improvement
- 2 Powers Label switch functionality
- Offline mode is now lighter and more portable (no computer with webserver required anymore)

View File

@ -1,5 +0,0 @@
.slider,
.slider img {
margin-bottom: 0;
height: 150px;
}

View File

@ -1,622 +0,0 @@
/*!
* =====================================================
* Ratchet v2.0.2 (http://goratchet.com)
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
*
* v2.0.2 designed by @connors.
* =====================================================
*/
body {
font-family: "Roboto", sans-serif;
font-size: 18px;
line-height: 22px;
color: #222;
}
a {
color: #33b5e5;
}
a:active {
color: #1a9bcb;
}
.content {
background-color: #f2f2f2;
}
.bar-nav ~ .content {
padding-top: 50px;
}
.bar-header-secondary ~ .content {
padding-top: 100px;
}
.bar-tab ~ .content {
padding-top: 50px;
padding-bottom: 0;
}
.bar-footer ~ .content {
padding-bottom: 50px;
}
.bar-footer-secondary ~ .content {
padding-bottom: 100px;
}
.btn {
padding: 8px 15px;
font-size: 14px;
color: #222;
background-color: #cecece;
border: 0;
border-radius: 2px;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .2), inset 0 1px 0 rgba(255, 255, 255, .2), 0 1px 1px rgba(0, 0, 0, .25);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .2), inset 0 1px 0 rgba(255, 255, 255, .2), 0 1px 1px rgba(0, 0, 0, .25);
}
.btn:active, .btn.active {
color: #222;
background-color: #999;
border: 0;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .2), inset 0 1px 0 rgba(255, 255, 255, .2);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .2), inset 0 1px 0 rgba(255, 255, 255, .2);
}
.btn-primary {
color: #fff;
background-color: #33b5e5;
border: 0;
}
.btn-primary:active, .btn-primary.active {
color: #fff;
background-color: #1a9bcb;
border: 0;
}
.btn-positive {
color: #fff;
background-color: #9c0;
border: 0;
}
.btn-positive:active, .btn-positive.active {
color: #fff;
background-color: #739900;
border: 0;
}
.btn-negative {
color: #fff;
background-color: #f44;
border: 0;
}
.btn-negative:active, .btn-negative.active {
color: #fff;
background-color: #f11;
border: 0;
}
.btn-outlined {
background-color: transparent;
border: 1px solid #999;
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-outlined.btn-primary {
color: #33b5e5;
border: 1px solid #33b5e5;
}
.btn-outlined.btn-primary:active {
background-color: #33b5e5;
border: 1px solid #33b5e5;
}
.btn-outlined.btn-positive {
color: #9c0;
border: 1px solid #9c0;
}
.btn-outlined.btn-positive:active {
background-color: #9c0;
border: 1px solid #9c0;
}
.btn-outlined.btn-negative {
color: #f44;
border: 1px solid #f44;
}
.btn-outlined.btn-negative:active {
background-color: #f44;
border: 1px solid #f44;
}
.btn-outlined:active {
background-color: #999;
border: 1px solid #999;
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-outlined.btn-primary:active, .btn-outlined.btn-positive:active, .btn-outlined.btn-negative:active {
color: #fff;
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-link {
color: #33b5e5;
background-color: transparent;
border: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-link:active, .btn-link.active {
color: #1a9bcb;
background-color: transparent;
-webkit-box-shadow: none;
box-shadow: none;
}
.btn-block {
padding: 15px 0;
font-size: 18px;
}
.btn .badge {
background-color: rgba(0, 0, 0, .15);
}
.btn .badge.badge-inverted {
background-color: transparent;
}
.btn:active .badge {
color: #fff;
}
.bar {
height: 50px;
background-color: #ddd;
border-bottom: 1px solid #b1b1b1;
-webkit-box-shadow: inset 0 -2px 0 #d2d2d2, 0 3px 3px rgba(0, 0, 0, .07);
box-shadow: inset 0 -2px 0 #d2d2d2, 0 3px 3px rgba(0, 0, 0, .07);
}
.bar.bar-header-secondary {
top: 50px;
}
.bar.bar-footer-secondary {
bottom: 50px;
}
.bar.bar-footer-secondary-tab {
bottom: 50px;
}
.bar .bar-footer,
.bar .bar-footer-secondary,
.bar .bar-footer-secondary-tab {
border-top: 1px solid #b1b1b1;
border-bottom: 0;
-webkit-box-shadow: inset 0 -2px 0 #33b5e5;
box-shadow: inset 0 -2px 0 #33b5e5;
}
.bar-tab {
top: 0;
bottom: auto;
height: 50px;
border-top: 0;
}
.bar-tab .tab-item {
color: #929292;
}
.bar-tab .tab-item.active {
color: #33b5e5;
-webkit-box-shadow: inset 0 -2px 0 #33b5e5;
box-shadow: inset 0 -2px 0 #33b5e5;
}
.bar-tab .tab-item:active {
color: #929292;
background-color: #78c6e3;
}
.bar-tab .tab-item .icon {
top: 3px;
padding-top: 0;
padding-bottom: 0;
}
.title {
position: static;
padding-left: 15px;
font-size: 18px;
line-height: 49px;
text-align: left;
}
.bar .btn {
top: 7px;
padding-top: 10px;
padding-bottom: 10px;
}
.bar .btn-link {
top: 0;
padding: 0;
font-size: 18px;
line-height: 49px;
color: #33b5e5;
}
.bar .btn-link:active, .bar .btn-link.active {
color: #1a9bcb;
}
.bar .btn-link .icon {
top: 2px;
padding: 0;
}
.bar .btn-block {
top: 4px;
}
.bar .segmented-control {
top: 7px;
}
.bar .icon {
padding-top: 13px;
padding-bottom: 13px;
}
.bar .title .icon {
padding: 0;
}
.bar .title .icon.icon-caret {
top: 10px;
color: #777;
}
.bar input[type="search"] {
height: 35px;
}
.badge.badge-inverted {
color: #999;
background-color: transparent;
}
.badge-primary {
color: #fff;
background-color: #33b5e5;
}
.badge-primary.badge-inverted {
color: #33b5e5;
background-color: transparent;
}
.badge-positive {
color: #fff;
background-color: #9c0;
}
.badge-positive.badge-inverted {
color: #9c0;
background-color: transparent;
}
.badge-negative {
color: #fff;
background-color: #f44;
}
.badge-negative.badge-inverted {
color: #f44;
background-color: transparent;
}
.card {
background-color: transparent;
border-color: #d9d9d9;
border-radius: 2px;
}
.table-view {
background-color: transparent;
}
.table-view .table-view-cell {
border-bottom: 1px solid #d9d9d9;
}
.table-view .table-view-cell:last-child {
background-image: none;
}
.table-view .table-view-cell > a:not(.btn):active {
color: inherit;
background-color: #e0e0e0;
}
.table-view .table-view-cell > a:not(.btn):active .icon {
color: #fff;
}
.table-view .table-view-divider {
padding-top: 25px;
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
background-color: transparent;
border-top: 0;
border-bottom: 2px solid #a9a9a9;
}
.table-view-cell .navigate-left > .btn,
.table-view-cell .navigate-left > .badge,
.table-view-cell .navigate-left > .toggle,
.table-view-cell .navigate-right > .btn,
.table-view-cell .navigate-right > .badge,
.table-view-cell .navigate-right > .toggle,
.table-view-cell .push-left > .btn,
.table-view-cell .push-left > .badge,
.table-view-cell .push-left > .toggle,
.table-view-cell .push-right > .btn,
.table-view-cell .push-right > .badge,
.table-view-cell .push-right > .toggle,
.table-view-cell > a .navigate-left > .btn,
.table-view-cell > a .navigate-left > .badge,
.table-view-cell > a .navigate-left > .toggle,
.table-view-cell > a .navigate-right > .btn,
.table-view-cell > a .navigate-right > .badge,
.table-view-cell > a .navigate-right > .toggle,
.table-view-cell > a .push-left > .btn,
.table-view-cell > a .push-left > .badge,
.table-view-cell > a .push-left > .toggle,
.table-view-cell > a .push-right > .btn,
.table-view-cell > a .push-right > .badge,
.table-view-cell > a .push-right > .toggle {
right: 15px;
}
select,
textarea,
input[type="text"],
input[type="search"],
input[type="password"],
input[type="datetime"],
input[type="datetime-local"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="week"],
input[type="number"],
input[type="email"],
input[type="url"],
input[type="tel"],
input[type="color"],
.input-group {
height: 40px;
padding: 10px 15px;
border: 1px solid rgba(0, 0, 0, .2);
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .1);
box-shadow: 0 1px 1px rgba(0, 0, 0, .1);
}
input[type="search"] {
border-radius: 2px;
}
select,
textarea,
.input-group {
height: auto;
}
.input-group {
padding: 0;
border: 0;
}
.input-group input {
border: 0;
border-bottom: 1px solid #d9d9d9;
-webkit-box-shadow: none;
box-shadow: none;
}
.input-group input:last-child {
background-image: none;
}
.input-row {
height: 40px;
border-bottom: 1px solid #d9d9d9;
}
.input-row label {
padding-top: 10px;
padding-bottom: 10px;
}
.input-row label + input {
background-image: none;
border-bottom: 0;
}
.segmented-control {
font-size: 14px;
background-color: #cecece;
border: 0;
border-radius: 2px;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .25);
box-shadow: 0 1px 1px rgba(0, 0, 0, .25);
}
.segmented-control .control-item {
padding-top: 10px;
padding-bottom: 10px;
color: #222;
border-left: 1px solid #999;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .2), inset 0 1px 0 rgba(255, 255, 255, .2);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .2), inset 0 1px 0 rgba(255, 255, 255, .2);
}
.segmented-control .control-item:first-child {
border-left-width: 0;
}
.segmented-control .control-item:active, .segmented-control .control-item.active {
background-color: #999;
}
.segmented-control-primary {
border: 0;
}
.segmented-control-primary .control-item {
color: #fff;
border-color: inherit;
}
.segmented-control-primary .control-item:active, .segmented-control-primary .control-item.active {
color: #fff;
background-color: #33b5e5;
}
.segmented-control-positive {
border: 0;
}
.segmented-control-positive .control-item {
color: #fff;
border-color: inherit;
}
.segmented-control-positive .control-item:active, .segmented-control-positive .control-item.active {
color: #fff;
background-color: #9c0;
}
.segmented-control-negative {
border: 0;
}
.segmented-control-negative .control-item {
color: #fff;
border-color: inherit;
}
.segmented-control-negative .control-item:active, .segmented-control-negative .control-item.active {
color: #fff;
background-color: #f44;
}
.popover {
top: 47px;
left: 15px;
width: 200px;
margin-left: 0;
border: 1px solid #9b9b9b;
border-radius: 0;
-webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .2);
box-shadow: 0 0 3px rgba(0, 0, 0, .2);
-webkit-transition: -webkit-transform .1s ease-in-out, opacity .2s ease-in-out;
-moz-transition: -moz-transform .1s ease-in-out, opacity .2s ease-in-out;
transition: transform .1s ease-in-out, opacity .2s ease-in-out;
-webkit-transform: scale(.75);
-ms-transform: scale(.75);
transform: scale(.75);
}
.popover:before {
display: none;
}
.popover.visible {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
.backdrop {
background-color: transparent;
}
.popover .bar {
border-radius: 0;
}
.popover .bar-nav ~ .table-view {
padding-top: 50px;
}
.popover .table-view {
border-radius: 12px;
}
.toggle {
width: 104px;
height: 28px;
background-color: #d7d7d7;
border: 2px solid #d7d7d7;
border-radius: 0;
}
.toggle .toggle-handle {
top: 0;
left: 0;
width: 50px;
height: 24px;
background-color: #bebebe;
border: 1px solid #b5b5b5;
border-radius: 2px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3), inset 0 -1px 0 rgba(0, 0, 0, .1);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3), inset 0 -1px 0 rgba(0, 0, 0, .1);
}
.toggle:before {
top: 1px;
right: auto;
left: 11px;
z-index: 3;
color: #fff;
}
.toggle.active {
background-color: #d7d7d7;
border: 2px solid #d7d7d7;
}
.toggle.active .toggle-handle {
margin-right: 2px;
background-color: #33b5e5;
border-color: #33b5e5;
-webkit-transform: translate3d(50px, 0, 0);
-ms-transform: translate3d(50px, 0, 0);
transform: translate3d(50px, 0, 0);
}
.toggle.active:before {
right: 14px;
left: auto;
color: #fff;
}
.navigate-left:after,
.push-left:after {
content: '';
}
.navigate-right:after,
.push-right:after {
content: '';
}
.icon-caret:before {
content: '\e800';
}
.icon-down:before,
.icon-down-nav:before {
content: '\e801';
}
.icon-download:before {
content: '\e802';
}
.icon-left:before,
.icon-left-nav:before {
content: '\e803';
}
.icon-more-vertical:before {
content: '\e804';
}
.icon-more:before {
content: '\e805';
}
.icon-right:before,
.icon-right-nav:before {
content: '\e806';
}
.icon-search:before {
content: '\e807';
}
.icon-share:before {
content: '\e808';
}
.icon-up:before,
.icon-up-nav:before {
content: '\e809';
}

File diff suppressed because one or more lines are too long

View File

@ -1,471 +0,0 @@
/*!
* =====================================================
* Ratchet v2.0.2 (http://goratchet.com)
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
*
* v2.0.2 designed by @connors.
* =====================================================
*/
a {
color: #007aff;
}
a:active {
color: #0062cc;
}
.content {
background-color: #efeff4;
}
.h5, h5,
.h6, h6,
p {
color: #8f8f94;
}
.h5, h5,
.h6, h6 {
font-weight: normal;
text-transform: uppercase;
}
.btn {
color: #929292;
background-color: rgba(247, 247, 247, .98);
border: 1px solid #929292;
-webkit-transition: all;
-moz-transition: all;
transition: all;
-webkit-transition-timing-function: linear;
-moz-transition-timing-function: linear;
transition-timing-function: linear;
-webkit-transition-duration: .2s;
-moz-transition-duration: .2s;
transition-duration: .2s;
}
.btn:active, .btn.active {
color: #fff;
background-color: #929292;
}
.btn-primary {
color: #fff;
background-color: #007aff;
border: 1px solid #007aff;
}
.btn-primary:active, .btn-primary.active {
background-color: #0062cc;
border: 1px solid #0062cc;
}
.btn-positive {
color: #fff;
background-color: #4cd964;
border: 1px solid #4cd964;
}
.btn-positive:active, .btn-positive.active {
background-color: #2ac845;
border: 1px solid #2ac845;
}
.btn-negative {
color: #fff;
background-color: #dd524d;
border: 1px solid #dd524d;
}
.btn-negative:active, .btn-negative.active {
background-color: #cf2d28;
border: 1px solid #cf2d28;
}
.btn-outlined {
background-color: transparent;
}
.btn-outlined.btn-primary {
color: #007aff;
}
.btn-outlined.btn-positive {
color: #4cd964;
}
.btn-outlined.btn-negative {
color: #dd524d;
}
.btn-outlined.btn-primary:active, .btn-outlined.btn-positive:active, .btn-outlined.btn-negative:active {
color: #fff;
}
.btn-link {
color: #007aff;
background-color: transparent;
border: none;
}
.btn-link:active, .btn-link.active {
color: #0062cc;
background-color: transparent;
}
.btn .badge {
background-color: rgba(0, 0, 0, .15);
}
.btn .badge.badge-inverted {
background-color: transparent;
}
.btn:active .badge {
color: #fff;
}
.bar {
background-color: rgba(247, 247, 247, .98);
border-bottom: 0;
-webkit-box-shadow: 0 0 1px rgba(0, 0, 0, .85);
box-shadow: 0 0 1px rgba(0, 0, 0, .85);
}
.bar.bar-header-secondary {
top: 44px;
}
.bar.bar-footer-secondary {
bottom: 44px;
}
.bar.bar-footer-secondary-tab {
bottom: 50px;
}
.bar.bar-footer, .bar.bar-footer-secondary, .bar.bar-footer-secondary-tab {
border-top: 0;
}
.bar-tab {
border-top: 0;
}
.tab-item {
color: #929292;
}
.tab-item.active, .tab-item:active {
color: #007aff;
}
.bar-nav .btn-link {
color: #007aff;
}
.bar-nav .btn-link:active {
color: #007aff;
opacity: .6;
}
.badge.badge-inverted {
color: #929292;
background-color: transparent;
}
.badge-primary {
color: #fff;
background-color: #007aff;
}
.badge-primary.badge-inverted {
color: #007aff;
background-color: transparent;
}
.badge-positive {
color: #fff;
background-color: #4cd964;
}
.badge-positive.badge-inverted {
color: #4cd964;
background-color: transparent;
}
.badge-negative {
color: #fff;
background-color: #dd524d;
}
.badge-negative.badge-inverted {
color: #dd524d;
background-color: transparent;
}
.card .table-view {
background-image: none;
}
.card .table-view-cell:last-child {
background-image: none;
}
.table-view {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>"), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>");
background-repeat: no-repeat;
background-position: 0 100%, 0 0;
border-top: 0;
border-bottom: 0;
}
.table-view .table-view-cell {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>");
background-repeat: no-repeat;
background-position: 15px 100%;
border-bottom: 0;
}
.table-view .table-view-cell:last-child {
background-image: none;
}
.table-view .table-view-cell > a:not(.btn):active {
color: inherit;
}
.table-view .table-view-divider {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>"), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>");
background-repeat: no-repeat;
background-position: 0 100%, 0 0;
border-top: 0;
border-bottom: 0;
}
select,
textarea,
input[type="text"],
input[type="search"],
input[type="password"],
input[type="datetime"],
input[type="datetime-local"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="week"],
input[type="number"],
input[type="email"],
input[type="url"],
input[type="tel"],
input[type="color"],
.input-group {
height: 40px;
padding: 10px 15px;
border: 1px solid rgba(0, 0, 0, .2);
}
input[type="search"] {
height: 34px;
text-align: center;
background-color: rgba(0, 0, 0, .1);
border: 0;
border-radius: 6px;
}
input[type="search"]:focus {
text-align: left;
}
select,
textarea,
.input-group {
height: auto;
}
.input-group {
padding: 0;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>"), url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>");
background-repeat: no-repeat;
background-position: 0 100%, 0 0;
border: 0;
}
.input-group input {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>");
background-repeat: no-repeat;
background-position: 15px 100%;
border: 0;
}
.input-group input:last-child {
background-image: none;
}
.input-row {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%' height='1'><rect fill='#c8c7cc' x='0' y='0' width='100%' height='0.5'/></svg>");
background-repeat: no-repeat;
background-position: 15px 100%;
border-bottom: 0;
}
.input-row:last-child,
.input-row label + input {
background-image: none;
}
.segmented-control {
background-color: transparent;
border: 1px solid #929292;
}
.segmented-control .control-item {
color: #929292;
border-color: #929292;
-webkit-transition: background-color .1s linear;
-moz-transition: background-color .1s linear;
transition: background-color .1s linear;
}
.segmented-control .control-item:active {
background-color: #ebebeb;
}
.segmented-control .control-item.active {
color: #fff;
background-color: #929292;
}
.segmented-control-primary {
border: 1px solid #007aff;
}
.segmented-control-primary .control-item {
color: #007aff;
border-color: inherit;
}
.segmented-control-primary .control-item:active {
background-color: #b3d7ff;
}
.segmented-control-primary .control-item.active {
color: #fff;
background-color: #007aff;
}
.segmented-control-positive {
border: 1px solid #4cd964;
}
.segmented-control-positive .control-item {
color: #4cd964;
border-color: inherit;
}
.segmented-control-positive .control-item:active {
background-color: #dff8e3;
}
.segmented-control-positive .control-item.active {
color: #fff;
background-color: #4cd964;
}
.segmented-control-negative {
border: 1px solid #dd524d;
}
.segmented-control-negative .control-item {
color: #dd524d;
border-color: inherit;
}
.segmented-control-negative .control-item:active {
background-color: #fae4e3;
}
.segmented-control-negative .control-item.active {
color: #fff;
background-color: #dd524d;
}
.popover {
border-radius: 12px;
-webkit-transition: -webkit-transform .2s ease-in-out, opacity .2s ease-in-out;
-moz-transition: -webkit-transform .2s ease-in-out, opacity .2s ease-in-out;
transition: -webkit-transform .2s ease-in-out, opacity .2s ease-in-out;
}
.popover:before {
border-bottom: 15px solid rgba(247, 247, 247, .98);
}
.popover .bar {
-webkit-box-shadow: none;
box-shadow: none;
}
.popover .bar-nav {
border-bottom: 1px solid rgba(0, 0, 0, .15);
}
.popover .table-view {
background-image: none;
border-radius: 12px;
}
.modal {
-webkit-transition-timing-function: cubic-bezier(.1, .5, .1, 1);
-moz-transition-timing-function: cubic-bezier(.1, .5, .1, 1);
transition-timing-function: cubic-bezier(.1, .5, .1, 1);
}
.modal.active {
-webkit-transition-timing-function: cubic-bezier(.1, .5, .1, 1);
-moz-transition-timing-function: cubic-bezier(.1, .5, .1, 1);
transition-timing-function: cubic-bezier(.1, .5, .1, 1);
}
.toggle {
width: 47px;
border: 2px solid #e6e6e6;
-webkit-box-shadow: inset 0 0 0 0 #e1e1e1;
box-shadow: inset 0 0 0 0 #e1e1e1;
-webkit-transition-duration: .2s;
-moz-transition-duration: .2s;
transition-duration: .2s;
-webkit-transition-property: box-shadow, border;
-moz-transition-property: box-shadow, border;
transition-property: box-shadow, border;
}
.toggle .toggle-handle {
border: 1px solid rgba(0, 0, 0, .2);
-webkit-box-shadow: 0 3px 3px rgba(0, 0, 0, .08);
box-shadow: 0 3px 3px rgba(0, 0, 0, .08);
-webkit-transition-property: -webkit-transform, border, width;
-moz-transition-property: -moz-transform, border, width;
transition-property: transform, border, width;
}
.toggle:before {
display: none;
}
.toggle.active {
background-color: transparent;
border: 2px solid #4cd964;
-webkit-box-shadow: inset 0 0 0 13px #4cd964;
box-shadow: inset 0 0 0 13px #4cd964;
}
.toggle.active .toggle-handle {
-webkit-transform: translate3d(17px, 0, 0);
-ms-transform: translate3d(17px, 0, 0);
transform: translate3d(17px, 0, 0);
}
.toggle.active .toggle-handle {
border-color: #4cd964;
}
.content.fade {
-webkit-transition: opacity .2s ease-in-out;
-moz-transition: opacity .2s ease-in-out;
transition: opacity .2s ease-in-out;
}
.content.sliding {
-webkit-transition-timing-function: cubic-bezier(.1, .5, .1, 1);
-moz-transition-timing-function: cubic-bezier(.1, .5, .1, 1);
transition-timing-function: cubic-bezier(.1, .5, .1, 1);
}
.content.sliding.sliding-in, .content.sliding.right:not([class*="sliding-in"]) {
-webkit-animation-name: fadeOverlay;
-moz-animation-name: fadeOverlay;
animation-name: fadeOverlay;
-webkit-animation-duration: .4s;
-moz-animation-duration: .4s;
animation-duration: .4s;
}
.content.sliding.right:not([class*="sliding-in"]) {
-webkit-animation-direction: reverse;
-moz-animation-direction: reverse;
animation-direction: reverse;
}
.content.sliding.left {
-webkit-transform: translate3d(-20%, 0, 0);
-ms-transform: translate3d(-20%, 0, 0);
transform: translate3d(-20%, 0, 0);
}
@-webkit-keyframes fadeOverlay {
from {
-webkit-box-shadow: 0 0 10px transparent, -320px 0 0 transparent;
box-shadow: 0 0 10px transparent, -320px 0 0 transparent;
}
to {
-webkit-box-shadow: 0 0 10px rgba(0, 0, 0, .3), -320px 0 0 rgba(0, 0, 0, .1);
box-shadow: 0 0 10px rgba(0, 0, 0, .3), -320px 0 0 rgba(0, 0, 0, .1);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,61 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2014 by original authors @ fontello.com</metadata>
<defs>
<font id="ratchicons" horiz-adv-x="1000" >
<font-face font-family="ratchicons" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="and-caret" unicode="&#xe800;" d="m313 225l375 0v376" horiz-adv-x="1000" />
<glyph glyph-name="up-nav" unicode="&#xe81f;" d="m65 146l81-83l354 372l353-372l81 83l-434 456l-435-456z" horiz-adv-x="1000" />
<glyph glyph-name="and-download" unicode="&#xe802;" d="m875 38h-750v62h750v-62z m-312 375v250h-125v-250h-125l187-250l188 250h-125z" horiz-adv-x="1000" />
<glyph glyph-name="and-left" unicode="&#xe803;" d="m306 349l325 373l67-59l-273-314l273-315l-67-59l-325 373l0 1z" horiz-adv-x="1000" />
<glyph glyph-name="and-more-vertical" unicode="&#xe804;" d="m406-25v188h188v-188h-188z m0 563h188v188h-188v-188z m188-281v188h-188v-188h188z" horiz-adv-x="1000" />
<glyph glyph-name="and-more" unicode="&#xe805;" d="m125 444h188v-187h-188v187z m563 0v-187h187v187h-187z m-281-187h187v187h-187v-187z" horiz-adv-x="1000" />
<glyph glyph-name="and-right" unicode="&#xe806;" d="m698 348l-325-373l-67 59l274 315l-274 314l68 59l324-373l0-1z" horiz-adv-x="1000" />
<glyph glyph-name="and-search" unicode="&#xe807;" d="m928 51l-167 167c-17 17-47 15-66-4l-3-3l-69 69c42 54 67 121 67 194c0 173-140 313-314 313s-313-140-313-313s140-314 313-314c71 0 137 24 190 64l69-70c-18-19-19-48-2-65l166-166c17-17 47-16 66 4l59 58c19 19 21 49 4 66z m-801 423c0 137 112 249 249 249s249-112 249-249s-111-249-249-249s-249 111-249 249z" horiz-adv-x="1000" />
<glyph glyph-name="and-share" unicode="&#xe808;" d="m728 215c-33 0-63-14-84-36l-263 153c1 6 2 12 2 18c0 6-1 12-2 18l263 152c21-23 51-37 84-37c62 0 113 51 113 113s-51 114-113 114s-114-51-114-114c0-7 1-14 2-21l-261-150c-21 23-51 38-85 38c-63 0-114-50-114-113s51-113 114-113c33 0 64 15 85 38l261-151c-1-7-2-14-2-22c0-62 51-113 114-113s113 51 113 113s-51 113-113 113z" horiz-adv-x="1000" />
<glyph glyph-name="and-up" unicode="&#xe809;" d="m500 548l374-325l-59-67l-315 273l-314-273l-59 67l373 325l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="back" unicode="&#xe80a;" d="m500 174l-313 176l313 176m312-352l-312 176l312 176" horiz-adv-x="1000" />
<glyph glyph-name="down" unicode="&#xe820;" d="m941 479l-124 127l-317-315l-318 315l-124-127l442-441l441 441z" horiz-adv-x="1000" />
<glyph glyph-name="gear" unicode="&#xe821;" d="m820 274l118 40l0 72l-118 40c-8 34-22 67-40 97l55 111l-51 51l-111-55c-30 18-62 32-97 40l-39 118l-73 0l-40-118c-34-8-67-22-97-40l-111 55l-51-51l55-111c-18-30-32-62-40-97l-117-39l0-73l117-40c9-34 22-67 41-96l-56-111l52-52l111 56c29-19 62-32 96-40l40-119l73 0l39 119c35 8 67 21 97 40l111-56l51 52l-55 111c18 29 32 62 40 96z m-320-174c-139 0-251 112-251 251s112 250 251 250s250-112 250-250s-112-251-250-251z" horiz-adv-x="1000" />
<glyph glyph-name="left" unicode="&#xe822;" d="m628-91l127 123l-314 318l314 318l-127 124l-441-442l441-441z" horiz-adv-x="1000" />
<glyph glyph-name="list" unicode="&#xe823;" d="m1000 632h-750v-62l750-1v63z m0-314v63h-750v-63h750z m-750-187v-61h750v61h-750z m-250 406l125 1v125l-125 0v-126z m0-249h125v125h-125v-125z m0-250h125v125h-125v-125z" horiz-adv-x="1000" />
<glyph glyph-name="pages" unicode="&#xe824;" d="m63 601v-689h687l0 688l-687 1z m625-63v-563h-563v563h563z m-500 250v-125h62v62h625v-625l-62 0v-62h125v750h-750z" horiz-adv-x="1000" />
<glyph glyph-name="refresh" unicode="&#xe825;" d="m813 288c-28-145-161-250-313-250c-172 0-312 139-312 312c0 173 141 312 312 313v-98l221 129l-221 128v-95c0-2 0-2 0-2c-206 0-375-167-375-375s169-375 375-375c187 0 347 133 375 313h-62z" horiz-adv-x="1000" />
<glyph glyph-name="right" unicode="&#xe826;" d="m372 792l-127-124l314-318l-314-318l127-123l441 441l-441 442z" horiz-adv-x="1000" />
<glyph glyph-name="sound" unicode="&#xe827;" d="m825-22c-2 0-3 0-5 0l-16 7c0 0 0 0 0 1c-5 1-8 3-10 6c-1 3-1 7 1 12c1 1 22 40 43 101c20 58 44 147 44 244c0 98-24 186-44 243c-21 61-42 100-43 102c-4 11-2 15 8 21l17 8c2 1 5 2 7 2c7 0 12-5 17-16c1-2 2-4 4-8c10-19 32-63 52-125c25-78 37-156 37-232c0-94-24-182-44-240c-22-63-44-104-45-104l-1-2c-5-11-9-20-22-20c0 0 0 0 0 0z m-574 248c0 0-1 0-1 0h-186v248h186c0 0 1 0 1 0l248 173v-595l-248 174z m474-124c-2 0-4 0-6 0l-16 8c0 0 0 0 0 0c-5 1-8 3-9 6c-2 3-2 7 0 12c1 1 16 26 30 64c14 37 30 94 30 157c0 65-16 121-30 157c-14 38-29 62-30 63c-4 11-2 15 9 21l15 8c3 1 5 2 8 2c6 0 12-5 17-16c1-3 3-6 5-11c17-31 61-115 61-229c0-63-16-120-30-156c-16-39-31-64-31-64c0 0 0 0 0 0l-1-2c-6-11-10-20-22-20c0 0 0 0 0 0z m-84 127c-2 0-4 0-6 0l-15 7c0 1 0 1 0 1c-5 1-8 3-9 6c-2 3-2 7 0 12c0 0 20 43 20 94c0 53-20 91-21 93c-4 11-2 16 9 21l15 8c3 1 5 2 8 2c6 0 12-5 17-16c1-3 3-6 4-9c10-19 23-45 23-104c0-33-21-91-22-93l-1-2c-6-11-10-20-22-20c0 0 0 0 0 0z" horiz-adv-x="1000" />
<glyph glyph-name="sound2" unicode="&#xe828;" d="m251 226c0 0-1 0-1 0h-186v248h186c0 0 1 0 1 0l248 173v-595l-248 174z m474-124c-2 0-4 0-6 0l-16 8c0 0 0 0 0 0c-5 1-8 3-9 6c-2 3-2 7 0 12c1 1 16 26 30 64c14 37 30 94 30 157c0 65-16 121-30 157c-14 38-29 62-30 63c-4 11-2 15 9 21l15 8c3 1 5 2 8 2c6 0 12-5 17-16c1-3 3-6 5-11c17-31 61-115 61-229c0-63-16-120-30-156c-16-39-31-64-31-64c0 0 0 0 0 0l-1-2c-6-11-10-20-22-20c0 0 0 0 0 0z m-84 127c-2 0-4 0-6 0l-15 7c0 1 0 1 0 1c-5 1-8 3-9 6c-2 3-2 7 0 12c0 0 20 43 20 94c0 53-20 91-21 93c-4 11-2 16 9 21l15 8c3 1 5 2 8 2c6 0 12-5 17-16c1-3 3-6 4-9c10-19 23-45 23-104c0-33-21-91-22-93l-1-2c-6-11-10-20-22-20c0 0 0 0 0 0z" horiz-adv-x="1000" />
<glyph glyph-name="sound3" unicode="&#xe80b;" d="m251 226c0 0-1 0-1 0h-186v248h186c0 0 1 0 1 0l248 173v-595l-248 174z m390 3c-2 0-4 0-6 0l-15 7c0 1 0 1 0 1c-5 1-8 3-9 6c-2 3-2 7 0 12c0 0 20 43 20 94c0 53-20 91-21 93c-4 11-2 16 9 21l15 8c3 1 5 2 8 2c6 0 12-5 17-16c1-3 3-6 4-9c10-19 23-45 23-104c0-33-21-91-22-93l-1-2c-6-11-10-20-22-20c0 0 0 0 0 0z" horiz-adv-x="1000" />
<glyph glyph-name="sound4" unicode="&#xe80c;" d="m251 226c0 0-1 0-1 0h-186v248h186c0 0 1 0 1 0l248 173v-595l-248 174z" horiz-adv-x="1000" />
<glyph glyph-name="up" unicode="&#xe80d;" d="m58 222l124-126l318 314l317-314l124 126l-441 441l-442-441z" horiz-adv-x="1000" />
<glyph glyph-name="bars" unicode="&#xe80e;" d="m875 632h-750v-62l750-1l0 63l0 0z m0-314v63h-750v-63h750z m-750-187v-61h750v61h-750z" horiz-adv-x="1000" />
<glyph glyph-name="caret" unicode="&#xe80f;" d="m438 475h-125l187-250l188 250h-125" horiz-adv-x="1000" />
<glyph glyph-name="and-down" unicode="&#xe801;" d="m500 156l-373 325l59 67l314-273l315 273l59-67l-374-325l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="close" unicode="&#xe811;" d="m213 593l530-530l43 44l-529 530l-44-44l0 0z m530 44l-530-530l43-44l531 530l-44 44l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="code" unicode="&#xe812;" d="m680 608l-74-72l184-186l-184-185l74-73l257 258l-257 258z m-360-516l74 72l-184 186l184 186l-74 72l-258-258l258-258z" horiz-adv-x="1000" />
<glyph glyph-name="compose" unicode="&#xe813;" d="m890 651l-405-404l-110-22l22 110l404 405l17-17l-405-404l56-56l404 405l17-17z m15 16l20 20c14 13 14 35 0 48l-40 40c-13 14-35 14-48 0l-20-20m-4-272v-445h-625v625h440l63 62h-566v-750h750v570l-62-62z" horiz-adv-x="1000" />
<glyph glyph-name="down-nav" unicode="&#xe814;" d="m934 537l-81 83l-354-372l-353 372l-81-83l435-455l434 455z" horiz-adv-x="1000" />
<glyph glyph-name="download" unicode="&#xe815;" d="m875 538h-187v-63h125v-500h-625v500h125v63h-188v-626h750v626z m-344-323v635l-62 0v-635l-115 112l-41-39l187-188l188 188l-42 40l-115-113z" horiz-adv-x="1000" />
<glyph glyph-name="edit" unicode="&#xe829;" d="m749 511l-404-404l-110-22l22 110l404 404l16-16l-404-405l56-55l404 404l16-16z m16 16l20 20c14 13 14 35 0 48l-40 40c-13 14-35 14-48 0l-20-20" horiz-adv-x="1000" />
<glyph glyph-name="forward" unicode="&#xe82a;" d="m500 526l313-176l-313-176m-312 352l312-176l-312-176" horiz-adv-x="1000" />
<glyph glyph-name="home" unicode="&#xe82b;" d="m939 350l-438 438l0 0l0 0l-438-438l48-47l54 54v-444h16h51h168h47h109h46h168h55h12v444l54-54l48 47z m-501-370v245h125v-245h-125z m332 444v-444h-161v291h-16h-30h-125h-34h-12v-291h-160v444h0l269 269l269-269h0z" horiz-adv-x="1000" />
<glyph glyph-name="info" unicode="&#xe82c;" d="m500 725c-207 0-375-168-375-375s168-375 375-375s375 168 375 375s-168 375-375 375z m63-625h-125v313h125v-313z m-63 375c-34 0-62 28-62 63c0 34 28 62 62 62s63-28 63-62c0-35-28-63-63-63z" horiz-adv-x="1000" />
<glyph glyph-name="left-nav" unicode="&#xe82d;" d="m663-84l83 81l-372 354l372 354l-83 81l-455-435l455-435z" horiz-adv-x="1000" />
<glyph glyph-name="more-vertical" unicode="&#xe82e;" d="m500 163c52 0 94-42 94-94c0-52-42-94-94-94s-94 42-94 94c0 52 42 94 94 94z m-94 468c0-51 42-93 94-93s94 42 94 93s-42 94-94 94s-94-42-94-94z m0-281c0-52 42-94 94-94s94 42 94 94s-42 94-94 94s-94-42-94-94z" horiz-adv-x="1000" />
<glyph glyph-name="more" unicode="&#xe82f;" d="m313 350c0-52-42-94-94-94s-94 42-94 94s42 94 94 94s94-42 94-94z m468 94c-52 0-93-42-93-94s41-94 93-94s94 42 94 94s-42 94-94 94z m-281 0c-52 0-94-42-94-94c0-52 42-94 94-94s94 42 94 94c0 52-42 94-94 94z" horiz-adv-x="1000" />
<glyph glyph-name="pause" unicode="&#xe830;" d="m438 37h-188v625h188v-625z m312 1h-187v625h187v-625z" horiz-adv-x="1000" />
<glyph glyph-name="person" unicode="&#xe832;" d="m501 847c-275 0-497-222-497-497s222-496 497-496s496 222 496 496s-222 497-496 497z m315-801c-25 11-53 26-79 28c-149 12-152 43-152 106c0 47 30 8 52 118c8 36 15 29 36 95c13 47-12 41-12 41s8 35 12 72c10 96-32 187-175 187c-64 0-94-27-133-57c-41-32-55-76-44-130c7-39 21-77 12-72c0 0-22 6-12-41c21-59 32-59 38-95c18-107 47-70 53-118c6-63-7-94-148-106c-25-2-55-16-79-27c-76 79-123 186-123 303c0 242 197 439 439 439s438-197 438-439c0-118-47-226-123-304z" horiz-adv-x="1000" />
<glyph glyph-name="play" unicode="&#xe816;" d="m250 663l567-313l-567-312" horiz-adv-x="1000" />
<glyph glyph-name="plus" unicode="&#xe817;" d="m469 725v-750h61l1 750l-62 0l0 0z m406-344h-750v-61l750-1l0 62l0 0z" horiz-adv-x="1000" />
<glyph glyph-name="right-nav" unicode="&#xe818;" d="m291 786l-83-81l372-354l-372-354l83-81l455 435l-455 435z" horiz-adv-x="1000" />
<glyph glyph-name="search" unicode="&#xe819;" d="m935-10l-279 279c39 54 62 120 62 191c0 181-147 328-328 328s-327-147-327-328s147-327 327-327c71 0 136 22 190 61l279-280l76 76z m-808 470c0 146 118 263 263 263s264-117 264-263s-118-263-264-263s-263 118-263 263z" horiz-adv-x="1000" />
<glyph glyph-name="share" unicode="&#xe81a;" d="m875 538h-187v-63h125v-500h-625v500h125v63h-188v-626h750v626z m-406 197v-572h62v572l115-112l42 40l-188 187l-187-187l41-41l115 113z" horiz-adv-x="1000" />
<glyph glyph-name="star-filled" unicode="&#xe81b;" d="m500 812l116-354l371 0l-300-218l115-353l-301 218l-300-218l114 353l-300 218l371 0l114 354z" horiz-adv-x="1000" />
<glyph glyph-name="star" unicode="&#xe81c;" d="m987 458l-372 0l-115 354l-114-354l-371 0l301-218l-115-353l301 218l299-218l-115 353l301 218z m-252-478l-234 174l-234-174l99 274l-252 171l295 0l92 290l91-290l296 0l-253-175l100-270z" horiz-adv-x="1000" />
<glyph glyph-name="stop" unicode="&#xe81d;" d="m812 37h-625v625h625v-625z" horiz-adv-x="1000" />
<glyph glyph-name="trash" unicode="&#xe81e;" d="m875 725h-250c0 22 0 50 0 62c0 18-15 34-34 34h-182c-19 0-34-16-34-34c0-14 0-41 0-62h-250v-63h69l57-715c0-19 16-34 34-34h432c19 0 34 15 34 34l58 715h66v63z m-459 33c0 14 11 25 24 25h120c13 0 24-11 24-25c0-6 0-20 0-33h-168c0 12 0 26 0 33z m287-757c0-15-11-26-26-26h-355c-14 0-25 11-25 26l-42 661h490l-42-661z m-273 37h-47l-39 562l46 0l40-562z m187 0l-46 0l39 562l47 0l-40-562z m-94 0h-47v562h47v-562z" horiz-adv-x="1000" />
<glyph glyph-name="check" unicode="&#xe810;" d="m857 537l-81 83l-354-372l-135 128l-81-83l216-211l435 455z" horiz-adv-x="1000" />
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,164 +0,0 @@
<!--
Fun with Binary - a fun way of introducing binary
Copyright (C) 2018, Diogo Cordeiro.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fun with Binary</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<!-- Roboto -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,500,700">
<link rel="stylesheet" href="css/ratchet.min.css">
<link rel="stylesheet" href="css/ratchet-theme-android.min.css">
<link rel="stylesheet" href="css/app.css">
<script src="js/ratchet.min.js"></script>
</head>
<body onload="start_game()">
<header class="bar bar-nav">
<a class="icon icon-compose pull-right" href="#networkModal"></a>
<h1 class="title">
Have fun with Binary
</h1>
</header>
<div class="content">
<style>
.led {
width: auto;
height: auto;
max-width: 50%;
max-height: 50%;
}
</style>
<div id="statement"></div>
<img class="led" id="led0" onclick="change_state(0)" src="pic_bulboff.gif">
<img class="led" id="led1" onclick="change_state(1)" src="pic_bulboff.gif">
<img class="led" id="led2" onclick="change_state(2)" src="pic_bulboff.gif">
<img class="led" id="led3" onclick="change_state(3)" src="pic_bulboff.gif">
<img class="led" id="led4" onclick="change_state(4)" src="pic_bulboff.gif">
<img class="led" id="led5" onclick="change_state(5)" src="pic_bulboff.gif">
<div id="result"></div>
<input type="button" onclick="end_game()" value="That's it!" id="play_button">
<p>Made with love by <a href="https://www.diogo.site/">Diogo Cordeiro</a></p>
</div>
<script>
// URL for server communication
URL = "http://localhost";
/**
* Turn current answer bits accordingly
*/
function change_state(led_id)
{
let image = document.getElementById("led"+led_id);
if (image.src.match("bulbon"))
image.src = "pic_bulboff.gif";
else
image.src = "pic_bulbon.gif";
let xhttp = new XMLHttpRequest();
xhttp.open("GET", URL+"?change_state="+led_id+"&t=" + Math.random(), true);
xhttp.send();
}
/**
* Starts game
*/
function start_game()
{
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function()
{
if (this.readyState == 4 && this.status == 200)
document.getElementById("statement").innerHTML = "Write "+this.responseText+" in binary :)";
};
xhttp.open("GET", URL+"?start&t=" + Math.random(), true);
xhttp.send();
}
/**
* Prepares everything for a new game
*/
function restart_game()
{
document.getElementById("result").innerHTML = "";
start_game();
for (let led_id = 0; led_id <= 5; led_id++)
{
let image = document.getElementById("led"+led_id);
image.src = "pic_bulboff.gif";
}
document.getElementById("play_button").onclick=end_game;
document.getElementById("play_button").value="That's it!";
}
/**
* Compares the given answer with the right answer and tells the result
*/
function end_game()
{
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function()
{
if (this.readyState == 4 && this.status == 200)
document.getElementById("result").innerHTML = this.responseText;
};
xhttp.open("GET", URL+"?end&t=" + Math.random(), true);
xhttp.send();
document.getElementById("play_button").onclick=restart_game;
document.getElementById("play_button").value="Play again!";
}
/**
* Sets the URL for server communication
*/
function setURL()
{
URL = document.getElementById("new_url").value;
}
</script>
<!-- Network modal -->
<div id="networkModal" class="modal">
<header class="bar bar-nav">
<a class="icon icon-left pull-left" href="#networkModal"></a>
<h1 class="title">Settings</h1>
</header>
<div class="content">
<form class="content-padded">
<label for="new_url">Insert the URL for server communication</label>
<input type="text" value="http://localhost" id="new_url">
<a class="btn btn-positive btn-block" href="#networkModal" onclick="setURL()">Save</a>
</form>
</div>
</div><!-- /.modal -->
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -1,944 +0,0 @@
/*!
* =====================================================
* Ratchet v2.0.2 (http://goratchet.com)
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
*
* v2.0.2 designed by @connors.
* =====================================================
*/
/* ========================================================================
* Ratchet: modals.js v2.0.2
* http://goratchet.com/components#modals
* ========================================================================
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
* ======================================================================== */
!(function () {
'use strict';
var findModals = function (target) {
var i;
var modals = document.querySelectorAll('a');
for (; target && target !== document; target = target.parentNode) {
for (i = modals.length; i--;) {
if (modals[i] === target) {
return target;
}
}
}
};
var getModal = function (event) {
var modalToggle = findModals(event.target);
if (modalToggle && modalToggle.hash) {
return document.querySelector(modalToggle.hash);
}
};
window.addEventListener('click', function (event) {
var modal = getModal(event);
if (modal) {
if (modal && modal.classList.contains('modal')) {
modal.classList.toggle('active');
}
event.preventDefault(); // prevents rewriting url (apps can still use hash values in url)
}
});
}());
/* ========================================================================
* Ratchet: popovers.js v2.0.2
* http://goratchet.com/components#popovers
* ========================================================================
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
* ======================================================================== */
!(function () {
'use strict';
var popover;
var findPopovers = function (target) {
var i;
var popovers = document.querySelectorAll('a');
for (; target && target !== document; target = target.parentNode) {
for (i = popovers.length; i--;) {
if (popovers[i] === target) {
return target;
}
}
}
};
var onPopoverHidden = function () {
popover.style.display = 'none';
popover.removeEventListener('webkitTransitionEnd', onPopoverHidden);
};
var backdrop = (function () {
var element = document.createElement('div');
element.classList.add('backdrop');
element.addEventListener('touchend', function () {
popover.addEventListener('webkitTransitionEnd', onPopoverHidden);
popover.classList.remove('visible');
popover.parentNode.removeChild(backdrop);
});
return element;
}());
var getPopover = function (e) {
var anchor = findPopovers(e.target);
if (!anchor || !anchor.hash || (anchor.hash.indexOf('/') > 0)) {
return;
}
try {
popover = document.querySelector(anchor.hash);
}
catch (error) {
popover = null;
}
if (popover === null) {
return;
}
if (!popover || !popover.classList.contains('popover')) {
return;
}
return popover;
};
var showHidePopover = function (e) {
var popover = getPopover(e);
if (!popover) {
return;
}
popover.style.display = 'block';
popover.offsetHeight;
popover.classList.add('visible');
popover.parentNode.appendChild(backdrop);
};
window.addEventListener('touchend', showHidePopover);
}());
/* ========================================================================
* Ratchet: push.js v2.0.2
* http://goratchet.com/components#push
* ========================================================================
* inspired by @defunkt's jquery.pjax.js
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
* ======================================================================== */
/* global _gaq: true */
!(function () {
'use strict';
var noop = function () {};
// Pushstate caching
// ==================
var isScrolling;
var maxCacheLength = 20;
var cacheMapping = sessionStorage;
var domCache = {};
var transitionMap = {
slideIn : 'slide-out',
slideOut : 'slide-in',
fade : 'fade'
};
var bars = {
bartab : '.bar-tab',
barnav : '.bar-nav',
barfooter : '.bar-footer',
barheadersecondary : '.bar-header-secondary'
};
var cacheReplace = function (data, updates) {
PUSH.id = data.id;
if (updates) {
data = getCached(data.id);
}
cacheMapping[data.id] = JSON.stringify(data);
window.history.replaceState(data.id, data.title, data.url);
domCache[data.id] = document.body.cloneNode(true);
};
var cachePush = function () {
var id = PUSH.id;
var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]');
var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]');
cacheBackStack.push(id);
while (cacheForwardStack.length) {
delete cacheMapping[cacheForwardStack.shift()];
}
while (cacheBackStack.length > maxCacheLength) {
delete cacheMapping[cacheBackStack.shift()];
}
window.history.pushState(null, '', cacheMapping[PUSH.id].url);
cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack);
cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack);
};
var cachePop = function (id, direction) {
var forward = direction === 'forward';
var cacheForwardStack = JSON.parse(cacheMapping.cacheForwardStack || '[]');
var cacheBackStack = JSON.parse(cacheMapping.cacheBackStack || '[]');
var pushStack = forward ? cacheBackStack : cacheForwardStack;
var popStack = forward ? cacheForwardStack : cacheBackStack;
if (PUSH.id) {
pushStack.push(PUSH.id);
}
popStack.pop();
cacheMapping.cacheForwardStack = JSON.stringify(cacheForwardStack);
cacheMapping.cacheBackStack = JSON.stringify(cacheBackStack);
};
var getCached = function (id) {
return JSON.parse(cacheMapping[id] || null) || {};
};
var getTarget = function (e) {
var target = findTarget(e.target);
if (!target ||
e.which > 1 ||
e.metaKey ||
e.ctrlKey ||
isScrolling ||
location.protocol !== target.protocol ||
location.host !== target.host ||
!target.hash && /#/.test(target.href) ||
target.hash && target.href.replace(target.hash, '') === location.href.replace(location.hash, '') ||
target.getAttribute('data-ignore') === 'push') { return; }
return target;
};
// Main event handlers (touchend, popstate)
// ==========================================
var touchend = function (e) {
var target = getTarget(e);
if (!target) {
return;
}
e.preventDefault();
PUSH({
url : target.href,
hash : target.hash,
timeout : target.getAttribute('data-timeout'),
transition : target.getAttribute('data-transition')
});
};
var popstate = function (e) {
var key;
var barElement;
var activeObj;
var activeDom;
var direction;
var transition;
var transitionFrom;
var transitionFromObj;
var id = e.state;
if (!id || !cacheMapping[id]) {
return;
}
direction = PUSH.id < id ? 'forward' : 'back';
cachePop(id, direction);
activeObj = getCached(id);
activeDom = domCache[id];
if (activeObj.title) {
document.title = activeObj.title;
}
if (direction === 'back') {
transitionFrom = JSON.parse(direction === 'back' ? cacheMapping.cacheForwardStack : cacheMapping.cacheBackStack);
transitionFromObj = getCached(transitionFrom[transitionFrom.length - 1]);
} else {
transitionFromObj = activeObj;
}
if (direction === 'back' && !transitionFromObj.id) {
return (PUSH.id = id);
}
transition = direction === 'back' ? transitionMap[transitionFromObj.transition] : transitionFromObj.transition;
if (!activeDom) {
return PUSH({
id : activeObj.id,
url : activeObj.url,
title : activeObj.title,
timeout : activeObj.timeout,
transition : transition,
ignorePush : true
});
}
if (transitionFromObj.transition) {
activeObj = extendWithDom(activeObj, '.content', activeDom.cloneNode(true));
for (key in bars) {
if (bars.hasOwnProperty(key)) {
barElement = document.querySelector(bars[key]);
if (activeObj[key]) {
swapContent(activeObj[key], barElement);
} else if (barElement) {
barElement.parentNode.removeChild(barElement);
}
}
}
}
swapContent(
(activeObj.contents || activeDom).cloneNode(true),
document.querySelector('.content'),
transition
);
PUSH.id = id;
document.body.offsetHeight; // force reflow to prevent scroll
};
// Core PUSH functionality
// =======================
var PUSH = function (options) {
var key;
var xhr = PUSH.xhr;
options.container = options.container || options.transition ? document.querySelector('.content') : document.body;
for (key in bars) {
if (bars.hasOwnProperty(key)) {
options[key] = options[key] || document.querySelector(bars[key]);
}
}
if (xhr && xhr.readyState < 4) {
xhr.onreadystatechange = noop;
xhr.abort();
}
xhr = new XMLHttpRequest();
xhr.open('GET', options.url, true);
xhr.setRequestHeader('X-PUSH', 'true');
xhr.onreadystatechange = function () {
if (options._timeout) {
clearTimeout(options._timeout);
}
if (xhr.readyState === 4) {
xhr.status === 200 ? success(xhr, options) : failure(options.url);
}
};
if (!PUSH.id) {
cacheReplace({
id : +new Date(),
url : window.location.href,
title : document.title,
timeout : options.timeout,
transition : null
});
}
if (options.timeout) {
options._timeout = setTimeout(function () { xhr.abort('timeout'); }, options.timeout);
}
xhr.send();
if (xhr.readyState && !options.ignorePush) {
cachePush();
}
};
// Main XHR handlers
// =================
var success = function (xhr, options) {
var key;
var barElement;
var data = parseXHR(xhr, options);
if (!data.contents) {
return locationReplace(options.url);
}
if (data.title) {
document.title = data.title;
}
if (options.transition) {
for (key in bars) {
if (bars.hasOwnProperty(key)) {
barElement = document.querySelector(bars[key]);
if (data[key]) {
swapContent(data[key], barElement);
} else if (barElement) {
barElement.parentNode.removeChild(barElement);
}
}
}
}
swapContent(data.contents, options.container, options.transition, function () {
cacheReplace({
id : options.id || +new Date(),
url : data.url,
title : data.title,
timeout : options.timeout,
transition : options.transition
}, options.id);
triggerStateChange();
});
if (!options.ignorePush && window._gaq) {
_gaq.push(['_trackPageview']); // google analytics
}
if (!options.hash) {
return;
}
};
var failure = function (url) {
throw new Error('Could not get: ' + url);
};
// PUSH helpers
// ============
var swapContent = function (swap, container, transition, complete) {
var enter;
var containerDirection;
var swapDirection;
if (!transition) {
if (container) {
container.innerHTML = swap.innerHTML;
} else if (swap.classList.contains('content')) {
document.body.appendChild(swap);
} else {
document.body.insertBefore(swap, document.querySelector('.content'));
}
} else {
enter = /in$/.test(transition);
if (transition === 'fade') {
container.classList.add('in');
container.classList.add('fade');
swap.classList.add('fade');
}
if (/slide/.test(transition)) {
swap.classList.add('sliding-in', enter ? 'right' : 'left');
swap.classList.add('sliding');
container.classList.add('sliding');
}
container.parentNode.insertBefore(swap, container);
}
if (!transition) {
complete && complete();
}
if (transition === 'fade') {
container.offsetWidth; // force reflow
container.classList.remove('in');
var fadeContainerEnd = function () {
container.removeEventListener('webkitTransitionEnd', fadeContainerEnd);
swap.classList.add('in');
swap.addEventListener('webkitTransitionEnd', fadeSwapEnd);
};
var fadeSwapEnd = function () {
swap.removeEventListener('webkitTransitionEnd', fadeSwapEnd);
container.parentNode.removeChild(container);
swap.classList.remove('fade');
swap.classList.remove('in');
complete && complete();
};
container.addEventListener('webkitTransitionEnd', fadeContainerEnd);
}
if (/slide/.test(transition)) {
var slideEnd = function () {
swap.removeEventListener('webkitTransitionEnd', slideEnd);
swap.classList.remove('sliding', 'sliding-in');
swap.classList.remove(swapDirection);
container.parentNode.removeChild(container);
complete && complete();
};
container.offsetWidth; // force reflow
swapDirection = enter ? 'right' : 'left';
containerDirection = enter ? 'left' : 'right';
container.classList.add(containerDirection);
swap.classList.remove(swapDirection);
swap.addEventListener('webkitTransitionEnd', slideEnd);
}
};
var triggerStateChange = function () {
var e = new CustomEvent('push', {
detail: { state: getCached(PUSH.id) },
bubbles: true,
cancelable: true
});
window.dispatchEvent(e);
};
var findTarget = function (target) {
var i;
var toggles = document.querySelectorAll('a');
for (; target && target !== document; target = target.parentNode) {
for (i = toggles.length; i--;) {
if (toggles[i] === target) {
return target;
}
}
}
};
var locationReplace = function (url) {
window.history.replaceState(null, '', '#');
window.location.replace(url);
};
var extendWithDom = function (obj, fragment, dom) {
var i;
var result = {};
for (i in obj) {
if (obj.hasOwnProperty(i)) {
result[i] = obj[i];
}
}
Object.keys(bars).forEach(function (key) {
var el = dom.querySelector(bars[key]);
if (el) {
el.parentNode.removeChild(el);
}
result[key] = el;
});
result.contents = dom.querySelector(fragment);
return result;
};
var parseXHR = function (xhr, options) {
var head;
var body;
var data = {};
var responseText = xhr.responseText;
data.url = options.url;
if (!responseText) {
return data;
}
if (/<html/i.test(responseText)) {
head = document.createElement('div');
body = document.createElement('div');
head.innerHTML = responseText.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0];
body.innerHTML = responseText.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0];
} else {
head = body = document.createElement('div');
head.innerHTML = responseText;
}
data.title = head.querySelector('title');
var text = 'innerText' in data.title ? 'innerText' : 'textContent';
data.title = data.title && data.title[text].trim();
if (options.transition) {
data = extendWithDom(data, '.content', body);
} else {
data.contents = body;
}
return data;
};
// Attach PUSH event handlers
// ==========================
window.addEventListener('touchstart', function () { isScrolling = false; });
window.addEventListener('touchmove', function () { isScrolling = true; });
window.addEventListener('touchend', touchend);
window.addEventListener('click', function (e) { if (getTarget(e)) {e.preventDefault();} });
window.addEventListener('popstate', popstate);
window.PUSH = PUSH;
}());
/* ========================================================================
* Ratchet: segmented-controllers.js v2.0.2
* http://goratchet.com/components#segmentedControls
* ========================================================================
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
* ======================================================================== */
!(function () {
'use strict';
var getTarget = function (target) {
var i;
var segmentedControls = document.querySelectorAll('.segmented-control .control-item');
for (; target && target !== document; target = target.parentNode) {
for (i = segmentedControls.length; i--;) {
if (segmentedControls[i] === target) {
return target;
}
}
}
};
window.addEventListener('touchend', function (e) {
var activeTab;
var activeBodies;
var targetBody;
var targetTab = getTarget(e.target);
var className = 'active';
var classSelector = '.' + className;
if (!targetTab) {
return;
}
activeTab = targetTab.parentNode.querySelector(classSelector);
if (activeTab) {
activeTab.classList.remove(className);
}
targetTab.classList.add(className);
if (!targetTab.hash) {
return;
}
targetBody = document.querySelector(targetTab.hash);
if (!targetBody) {
return;
}
activeBodies = targetBody.parentNode.querySelectorAll(classSelector);
for (var i = 0; i < activeBodies.length; i++) {
activeBodies[i].classList.remove(className);
}
targetBody.classList.add(className);
});
window.addEventListener('click', function (e) { if (getTarget(e.target)) {e.preventDefault();} });
}());
/* ========================================================================
* Ratchet: sliders.js v2.0.2
* http://goratchet.com/components#sliders
* ========================================================================
Adapted from Brad Birdsall's swipe
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
* ======================================================================== */
!(function () {
'use strict';
var pageX;
var pageY;
var slider;
var deltaX;
var deltaY;
var offsetX;
var lastSlide;
var startTime;
var resistance;
var sliderWidth;
var slideNumber;
var isScrolling;
var scrollableArea;
var getSlider = function (target) {
var i;
var sliders = document.querySelectorAll('.slider > .slide-group');
for (; target && target !== document; target = target.parentNode) {
for (i = sliders.length; i--;) {
if (sliders[i] === target) {
return target;
}
}
}
};
var getScroll = function () {
if ('webkitTransform' in slider.style) {
var translate3d = slider.style.webkitTransform.match(/translate3d\(([^,]*)/);
var ret = translate3d ? translate3d[1] : 0;
return parseInt(ret, 10);
}
};
var setSlideNumber = function (offset) {
var round = offset ? (deltaX < 0 ? 'ceil' : 'floor') : 'round';
slideNumber = Math[round](getScroll() / (scrollableArea / slider.children.length));
slideNumber += offset;
slideNumber = Math.min(slideNumber, 0);
slideNumber = Math.max(-(slider.children.length - 1), slideNumber);
};
var onTouchStart = function (e) {
slider = getSlider(e.target);
if (!slider) {
return;
}
var firstItem = slider.querySelector('.slide');
scrollableArea = firstItem.offsetWidth * slider.children.length;
isScrolling = undefined;
sliderWidth = slider.offsetWidth;
resistance = 1;
lastSlide = -(slider.children.length - 1);
startTime = +new Date();
pageX = e.touches[0].pageX;
pageY = e.touches[0].pageY;
deltaX = 0;
deltaY = 0;
setSlideNumber(0);
slider.style['-webkit-transition-duration'] = 0;
};
var onTouchMove = function (e) {
if (e.touches.length > 1 || !slider) {
return; // Exit if a pinch || no slider
}
deltaX = e.touches[0].pageX - pageX;
deltaY = e.touches[0].pageY - pageY;
pageX = e.touches[0].pageX;
pageY = e.touches[0].pageY;
if (typeof isScrolling === 'undefined') {
isScrolling = Math.abs(deltaY) > Math.abs(deltaX);
}
if (isScrolling) {
return;
}
offsetX = (deltaX / resistance) + getScroll();
e.preventDefault();
resistance = slideNumber === 0 && deltaX > 0 ? (pageX / sliderWidth) + 1.25 :
slideNumber === lastSlide && deltaX < 0 ? (Math.abs(pageX) / sliderWidth) + 1.25 : 1;
slider.style.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)';
};
var onTouchEnd = function (e) {
if (!slider || isScrolling) {
return;
}
setSlideNumber(
(+new Date()) - startTime < 1000 && Math.abs(deltaX) > 15 ? (deltaX < 0 ? -1 : 1) : 0
);
offsetX = slideNumber * sliderWidth;
slider.style['-webkit-transition-duration'] = '.2s';
slider.style.webkitTransform = 'translate3d(' + offsetX + 'px,0,0)';
e = new CustomEvent('slide', {
detail: { slideNumber: Math.abs(slideNumber) },
bubbles: true,
cancelable: true
});
slider.parentNode.dispatchEvent(e);
};
window.addEventListener('touchstart', onTouchStart);
window.addEventListener('touchmove', onTouchMove);
window.addEventListener('touchend', onTouchEnd);
}());
/* ========================================================================
* Ratchet: toggles.js v2.0.2
* http://goratchet.com/components#toggles
* ========================================================================
Adapted from Brad Birdsall's swipe
* Copyright 2014 Connor Sears
* Licensed under MIT (https://github.com/twbs/ratchet/blob/master/LICENSE)
* ======================================================================== */
!(function () {
'use strict';
var start = {};
var touchMove = false;
var distanceX = false;
var toggle = false;
var findToggle = function (target) {
var i;
var toggles = document.querySelectorAll('.toggle');
for (; target && target !== document; target = target.parentNode) {
for (i = toggles.length; i--;) {
if (toggles[i] === target) {
return target;
}
}
}
};
window.addEventListener('touchstart', function (e) {
e = e.originalEvent || e;
toggle = findToggle(e.target);
if (!toggle) {
return;
}
var handle = toggle.querySelector('.toggle-handle');
var toggleWidth = toggle.clientWidth;
var handleWidth = handle.clientWidth;
var offset = toggle.classList.contains('active') ? (toggleWidth - handleWidth) : 0;
start = { pageX : e.touches[0].pageX - offset, pageY : e.touches[0].pageY };
touchMove = false;
});
window.addEventListener('touchmove', function (e) {
e = e.originalEvent || e;
if (e.touches.length > 1) {
return; // Exit if a pinch
}
if (!toggle) {
return;
}
var handle = toggle.querySelector('.toggle-handle');
var current = e.touches[0];
var toggleWidth = toggle.clientWidth;
var handleWidth = handle.clientWidth;
var offset = toggleWidth - handleWidth;
touchMove = true;
distanceX = current.pageX - start.pageX;
if (Math.abs(distanceX) < Math.abs(current.pageY - start.pageY)) {
return;
}
e.preventDefault();
if (distanceX < 0) {
return (handle.style.webkitTransform = 'translate3d(0,0,0)');
}
if (distanceX > offset) {
return (handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)');
}
handle.style.webkitTransform = 'translate3d(' + distanceX + 'px,0,0)';
toggle.classList[(distanceX > (toggleWidth / 2 - handleWidth / 2)) ? 'add' : 'remove']('active');
});
window.addEventListener('touchend', function (e) {
if (!toggle) {
return;
}
var handle = toggle.querySelector('.toggle-handle');
var toggleWidth = toggle.clientWidth;
var handleWidth = handle.clientWidth;
var offset = (toggleWidth - handleWidth);
var slideOn = (!touchMove && !toggle.classList.contains('active')) || (touchMove && (distanceX > (toggleWidth / 2 - handleWidth / 2)));
if (slideOn) {
handle.style.webkitTransform = 'translate3d(' + offset + 'px,0,0)';
} else {
handle.style.webkitTransform = 'translate3d(0,0,0)';
}
toggle.classList[slideOn ? 'add' : 'remove']('active');
e = new CustomEvent('toggle', {
detail: { isActive: slideOn },
bubbles: true,
cancelable: true
});
toggle.dispatchEvent(e);
touchMove = false;
toggle = false;
});
}());

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,168 +0,0 @@
/**
* Fun with Binary - a fun way of introducing binary
* Copyright (C) 2018, Diogo Cordeiro.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* output.ino
*
* Fun with Binary
* Arduino Controller
*
* Diogo Peralta Cordeiro
* up201705417@fc.up.pt
*
* Receives input via the searial port and turn the leds accordingly.
*/
// int bits[6] = {12, 10, 8, 6, 4, 2};
int bits[6] = { 2, 4, 6, 8, 10, 12 };
// Memorizes bits state
int bits_state[6] = { 0 };
// for incoming serial data
int incomingByte = 0;
// the setup routine runs once when you press reset:
void
setup()
{
// initialize the digital pins as an output.
for (int i = 0; i < 6; i++)
{
pinMode(bits[i], OUTPUT);
}
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void
loop()
{
if (Serial.available() > 0)
{
// read the incoming byte:
incomingByte = Serial.read() - '0';
// handle it
if (incomingByte == 7)
{
won_game();
}
else if (incomingByte == 8)
{
lost_game();
}
else if (incomingByte == 9)
{
reset_game();
}
else if (bits_state[incomingByte] == 1)
{ // Turn LED off
digitalWrite(bits[incomingByte], LOW);
bits_state[incomingByte] = 0;
}
else
{ // Turn LED on
digitalWrite(bits[incomingByte], HIGH);
bits_state[incomingByte] = 1;
}
}
}
/**
* Blinks every LED while waits for reset signal
*/
void
won_game()
{
while (true)
{
// read the incoming byte:
incomingByte = Serial.read() - '0';
if (incomingByte == 9)
{
reset_game();
break;
}
for (int i = 0; i < 6; i++)
{
digitalWrite(bits[i], LOW);
}
delay(1000);
for (int i = 0; i < 6; i++)
{
digitalWrite(bits[i], HIGH);
}
delay(1000);
}
}
/**
* Blinks red LEDs while waits for reset signal
*/
void
lost_game()
{
for (int i = 0; i < 6; i++)
{
digitalWrite(bits[i], LOW);
}
while (true)
{
// read the incoming byte:
incomingByte = Serial.read() - '0';
if (incomingByte == 9)
{
reset_game();
break;
}
digitalWrite(bits[0], LOW);
digitalWrite(bits[2], LOW);
digitalWrite(bits[4], LOW);
delay(1000);
digitalWrite(bits[0], HIGH);
digitalWrite(bits[2], HIGH);
digitalWrite(bits[4], HIGH);
delay(1000);
}
}
/**
* Resets for a potential new game
*/
void
reset_game()
{
for (int i = 0; i < 6; i++)
{
digitalWrite(bits[i], LOW);
bits_state[i] = 0;
}
}

72
index.html Normal file
View File

@ -0,0 +1,72 @@
<!--
Fun with Binary - a fun way of introducing binary
Copyright (C) 2018, Diogo Cordeiro.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=800" />
<title>Fun with Binary</title>
<meta name="description" content="A fun way of introducing binary">
<meta name="author" content="Diogo Cordeiro">
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body class="container">
<!-- Game Board -->
<div class="images" id="leds">
</div>
<!-- Statement -->
<div id="statement">
<p class="text" id="statement_text">
How do you represent the number
<span id="statement_value"></span>
in binary?
</p>
</div>
<!-- Settings -->
<ul id="settings">
<li>
<div class="button" id="label_switch_button">
<p class="text" id="settings_label_label">Labels</p>
<label class="switch">
<input id="label_switch"
class="toggle"
checked
type="checkbox"
onclick="switch_labels()"
autocomplete="off">
<span class="slider round"></span>
</label>
</div>
</li>
</ul>
<!-- Credits -->
<p class="text" id="footer">Made with <span style="color: #e25555;">&#9829;</span> by
<a href="https://www.diogo.site/">Diogo Cordeiro</a></p>
<!-- JS -->
<script src="script.js"></script>
</body>
</html>

404
script.js Normal file
View File

@ -0,0 +1,404 @@
/*
* Fun with Binary - a fun way of introducing binary
* Copyright (C) 2018, Diogo Cordeiro.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category UI interaction
* @package Fun with Binary
* @author Diogo Cordeiro <up201705417@fc.up.pt>
* @copyright 2018 Diogo Cordeiro.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.diogo.site/projects/fun_with_binary/
*/
/***********************************
* EXTEND JAVASCRIPT FUNCTIONALITY *
***********************************/
/**
* Returns a random integer between min(inclusive) and max(inclusive)
* Using Math.round() would give a non-uniform distribution!
*/
function getRandomInt(min, max)
{
return Math.floor(Math.random() *(max - min + 1)) + min;
}
/**
* Replace char at given position
*/
String.prototype.replaceAt=function(index, replacement)
{
return this.substr(0, index) + replacement+ this.substr(index +
replacement.length);
}
/**
* Checks if session storage is available
*/
function is_session_storage_available()
{
return window.sessionStorage != null;
}
/***********************************
* GAME SETTINGS *
***********************************/
// Online Mode (only used in Online Mode)
ONLINEMODE = false;
// Box IP (only used in Online Mode)
ONLINEURL = "http://42.42.42.42/";
// Number of leds
NLEDS = 6;
// Activate the Show 2 powers Labels feature
HAVELABELS = true;
// Default Show 2 powers Labels feature mode
show_labels = true;
// Easter Egg
EASTEREGG = true;
// ON and OFF leds srcs
LED_OFF = "data:image/png;base64,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";
LED_ON = "data:image/png;base64,R0lGODlhZAC0ANX/AMDAwP//zP//mf//Zv//M///AP/M///MzP/Mmf/MZv/MM/+Zmf+ZZv+ZM8z//8z/zMz/Zsz/M8zM/8zMzMzMmczMZsyZzMyZmcyZZsyZM5nMzJnMmZmZzJmZmZmZZplmZplmM2ZmmWZmZmYzZmYzMzNmZjNmMzMzZjMzMzMzAAAzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAABkALQAQAb/QIBwSCwaj8ikcslsOp/EQGFKrVqv2KzWOoB6i9KteEwmAwTZ7nc4KLvf8G2AKCBMCQQmOs7v+417VGB+hIWGV3MAh2IEAmtEbYtaeXaSVwQDlVUDAgGenwF1VgQUFJaXDkKnaaZxE6tYR7BXGpqTFZmzd3lMulSvFBMTGhN4BK+6eI8AkYcEGsETHRMc1BQc0RfFi8rLSYYEFsLT1BPB5MiFat5OYXzC0sLRFOQdhOzervDk1RMX/OkYAZjwwAA+fG+OlUNnLl45MwMTHcRnq4AdCOM6aOywAZ65fvG0SduoUVgFPAVSDTwwsSWAAw4skJxJs+bMCUdGknPpkgGD/wQIgDIIiqDoUKEIhv5MsNQngwZQoyI4gADq0wYJeLokGnTpAgQLEnxNQDbsz6NnfTYYSvXAVaUNEGidWBVsUbFkiaJ1GvVq1L5QgRqVOnduAAYKlCYlChRv0bBG9SaNKrGw5SMiVqxAMcIECs8lUGgevULE5dNEKloiUBm1kma+DGmFHVvSOgC2eD2pzbuKEdhJaPceLoYO8QKOmAj3xSs2nmDLzKk+lcfdLFIn+ZBafgoS71ZlME4/1XqI9Vm1xOSK7WW8nwETOl6L77HfhfSrJwYq5JFcMGz1BERIcpZxR8Yz4whTDYDwENKNa0No1w9D5zToBid2EAjhIG/0l/8ggw0dCIAEOG2oxHlieNhQghZuIcQEMJm4hAMkbmDTjTjeWOJAO8rYxFpFBRAjPDx6lOA0SBoJTwASBJDUU3L52ERRj4nVlVNnJfDXllxi1VhXf0nZhJZrHcXVUGPdxdiaj3U1GQNOEiZmE4cBGZRjig0VFGR4meWUlVVRNic+E6SwGQgeYIDXWQv8ycAHIBjawaA8hdIHJ5R+EYB7sFSi4ZzrHTcGhBaJOiBPnJqaRTcBhDrFp1CgqGofldlym3KzdlfEJrjmugqsVpSniq+zJJJJRY0YQayv5uVqx7OzNtebsMqluogjvBVBokcsvUgkHdYWQokvpTxLbRLuTBD/gS9dOBDue+Bp5yosc8i6yjZxVEDBu34QaO8pExiYBQUCc2MEv30QkF0Z8epC7b+WLDyJgJ02URu+WJQS261MIJyQNNh41JE2KMHC8RMlO0PfBhZ0VM002FgQDAS64gMxHCs6hA0H5GgjCawHeZwFMSwGQ0+LhQDtkiEegjTNfUKPsiEh6PBToTBRT3HyaaLAQYqC8xmNjteVnMs1Hx2xKIxM5uBHxgAPBNCjlF2XYSTM/mjAUBnJzS0mzlUnePQwGGvRhdwSZHpGh/3srKIwYzhiwAN+z2ktSiteE81IHlmUMq8vVW45FRHoZBMx0ZAkUkY3EgGj4kQ4YHqOtNfk//dOsBfBEk775Ci6t6YLA9MBZg96F1NHCUYlAgEY9OJL0LMk5PJgchll7kNo+ZSZYDkGVJqCMRWVYFT5VSZU12MPQFVYEjXWWMgzJX+WZDUWFllxBSWo+kK47333Y9me+bo0PjOF5S/pw94BwveUL3HvKHxizFeuUhSqcKlb/FtfX3zypT7ZpU3fa9NX7sdBC8Ylg0ZY4FIWo5i7pEUt21sLVn5ypxOikAkBYMqaOsjBs2BlS0O54RoysxkUkAAFSDwBEkkzGhQkToje6AASp2jEJZJmUlBkhyfqNgoBdCKLXrCUg6gwgOJhT4xZO5BFlEap/YiKNZkq2HGSJaOb+f8KjqfZ1LIOtDV8uHGPZPwcGV1iR2J1448F6CMUAHkg3TDDFmZMAiIZqQUNwcaRKKNkQgoQhWA9oZCavMKnUuYELobSDZ+yDhuFAMpTYqE1qlSCK/t1ME1gMkKzTFgRVFOeVubyCmV0zy3T+MsxOJKYxRxDInyZzDgkZ5LOGUC7DOAAARzLVEJA5htWeQRormJYtYkkErxpG9zUZgkekWRtuqDNUUWkSU3g3QSquU5FkEsY3jCAOeRIiC7UphVla8J+jhEbR5CTaYZoGCwMejH+nBMAzNQOxdww0VOso51bIGgcjoHRLRDooOCoaEYLN4td1kYBGsBZbejYrHXyawL/CqgnIFYq0lHQ7KHd7CgWFMZPksJiCTrdacEUFtRLcJMZzNHYJBS6CkV6h1zNgNYUfFozJ/AzYQqxhgU0IA5iMGcNESXDfxqyVRiNA3UmW0ZYtxABcYhjbZsLBjEsENSjdkwS4ZjAW+VhJGJwQKctsUQ5BLcPYXhVEuK06iIGG4+QOWQY7bzlQa4qhrambrA8g0dkLdNOD80ns9RYxNkKAQ3CgqimbnCNKeGw12kYDbSohYhr1jrVwkYDtBwohIz8kNXG/mdsfkhsYPvgNAVRAx1ppFsfPLsgfsBhD5KFUNQ8BLPBxXYTJHqimJhJAAi09iMU0Bs8KoBKA5CIUgg7/0bg5OqQYIQrD/iklC/VW9gVASRcc4jvoOZ7t/qQQxwiiojicEZdBfnnuo44r+IQljPXvowh1nqRdtvohmNsLkAliQenkvUACWAwUxVmLN6SpOGMCkECBcndcqClkMw6Tm2E0wg2TGGMQY7oAdiLqsJwJLPiGjYeONLvPHNsEQTUTsZHtt0QhKGS3B1gdklOsn4HMo0MQjnKQTYC535HKYJcGcuVywg+uTyoBcrlvP3RkZJmJ4wmJc4Bh0kg9qyiPOLxCAAOmByReOeA4ckOzwBw3gFU2BcUSsZ+8ttTB6m3PKGIj4AN+HDu2KfDRTnwTvI74ADXQr5HR0XS2EtKXv/KMmoA5iUtQJThBvVnFUOvkNRkQQyk/4KlL0HmKDJkAAoDwKXkNQZQyuMK9bxCJfPdsHyXHjWguCIUvtB6LYmpn1/krDhOX5qG0iZTrgNDv/B1RSjouyEHraKUX5tF0SwUdf3MgpWpaFvXN7wTtk2Nbgcib9O5nl9gUHgAbp9pMb/OtvxiXb+8uBB/UAF1qMcHpP8JHODKljdQ6rQWMAJAS99btPxmnerzNUC4insK+PRipYDfaYdggrfFdddupCgGL42hIZYQuHIldAADNAQ4ZJh9vAZkAAQ1b0IImqhE0HwGBSpgomZQEHQnTGDpnlHiEY+o9BVgselOEM0USaAXRCuSButr6IAIPlACEZhABFpHQZVlFAQAOw==";
/**********************************
* ACTUAL GAME CODE *
**********************************/
/**
* Global variables
*/
// Empty Answer
for (empty_answer = ''; empty_answer.length < NLEDS; empty_answer += '0');
// correct answer
correct_answer = empty_answer;
// current answer
current_answer = empty_answer;
/**
* Create leds
*/
for (let i = 0; i < NLEDS; ++i)
{
// Led holder
let figure = document.createElement("figure");
figure.setAttribute("class", "box");
// Label
if (HAVELABELS)
{
let c_label = Math.pow(2, NLEDS-i-1);
let figcaption = document.createElement("figcaption");
figcaption.setAttribute("value", c_label);
figcaption.setAttribute("class", "text labels");
figcaption.id = "label" + i;
figcaption.innerHTML = c_label;
figure.appendChild(figcaption);
}
else
{
document.getElementById('label_switch_button').setAttribute("style", "display:none");
}
// Led
let img = document.createElement("img");
// Set img src
if (is_session_storage_available()
&& sessionStorage.playing == 'true'
&& sessionStorage.current_answer.charAt(i) == '1')
{
img.src = LED_ON;
img.setAttribute("value", "ON");
}
else
{
img.src = LED_OFF;
img.setAttribute("value", "OFF");
}
img.id = "led" + i;
img.setAttribute("class", "led");
img.setAttribute("onclick", "switch_led("+i+")");
figure.appendChild(img);
document.getElementById("leds").appendChild(figure);
}
// If initial value for label is false, handle it
if (HAVELABELS && !show_labels)
{
show_labels = true;
document.getElementById("label_switch").click();
}
// Let the game begin
get_game();
/**
* Switch labels
*/
function switch_labels()
{
if (show_labels)
{
for (let i = 0; i < NLEDS; ++i)
{
document.getElementById("label"+i).setAttribute
("style", "visibility:hidden");
}
}
else
{
for (let i = 0; i < NLEDS; ++i)
{
document.getElementById("label"+i).setAttribute
("style", "");
}
}
show_labels = !show_labels;
cache_current_game();
}
/**
* Turn current answer bits accordingly
*/
function switch_led(led_id)
{
let image = document.getElementById("led"+led_id);
if (image.getAttribute("value") == "ON")
{
image.setAttribute("value", "OFF");
image.src = LED_OFF;
current_answer = current_answer.replaceAt(led_id, "0");
}
else
{
image.setAttribute("value", "ON");
image.src = LED_ON;
current_answer = current_answer.replaceAt(led_id, "1");
}
cache_current_game();
// Easter egg
if (EASTEREGG && current_answer == (empty_answer.substr(6) + "101010"))
{
alert("That's the answer to life, the universe and everything!");
}
// If we are connected to the box
if (ONLINEMODE)
{
let xhttp = new XMLHttpRequest();
xhttp.open("GET", ONLINEURL+"switch_state?led=" + led_id, true);
xhttp.send();
}
// If right answer, finish game, restart a new one
if (current_answer == correct_answer)
{
end_game();
restart_game();
}
}
/**
* Sets problem statement's decimal number
*/
function set_statement(n_dec)
{
document.getElementById("statement_value").innerHTML = n_dec;
}
/**
* Recovers game from page reload
*/
function get_game()
{
if (!is_session_storage_available() || sessionStorage.playing != 'true')
{
start_game();
}
else
{
restore_from_cache();
}
}
/**
* Restore current game from cache
*/
function restore_from_cache()
{
correct_answer = sessionStorage.correct_answer;
current_answer = sessionStorage.current_answer;
set_statement(Number(sessionStorage.number_dec));
if (HAVELABELS && sessionStorage.show_label != show_labels.toString())
{
show_labels = true;
document.getElementById("label_switch").click();
}
}
/**
* Caches current game
*/
function cache_current_game()
{
if (!is_session_storage_available())
{
return;
}
sessionStorage.current_answer = current_answer;
sessionStorage.show_label = show_labels;
}
/**
* Starts game
*/
function start_game()
{
let n_dec = getRandomInt(1, Math.pow(2, NLEDS)-1);
let n_bin = n_dec.toString(2);
correct_answer = empty_answer.substr(n_bin.length) + n_bin;
set_statement(n_dec);
if (is_session_storage_available())
{
sessionStorage.playing = true;
sessionStorage.correct_answer = correct_answer;
sessionStorage.number_dec = n_dec;
cache_current_game();
}
}
/**
* Prepares everything for a new game
*/
function reset_game()
{
correct_answer = empty_answer;
current_answer = empty_answer;
turn_all_leds_images_off();
for (let i = 0; i < NLEDS; ++i)
{
document.getElementById("led"+i).setAttribute("value", "OFF");
}
}
/**
* Start a new game
*/
function restart_game()
{
reset_game();
start_game();
}
/**
* Finishes the game
*/
function end_game()
{
// If we are connected to the box
if (ONLINEMODE)
{
let xhttp = new XMLHttpRequest();
xhttp.open("GET", ONLINEURL+"won", true);
xhttp.send();
}
// Blink correct answer leds 3 times
blink_led_effect(3, correct_answer);
// Reset cache
if (is_session_storage_available())
{
sessionStorage.clear();
}
}
/**
* Turn every led on(without turning value attribute)
*/
function turn_leds_images_on(which)
{
// Turn all on
for (let i = 0; i < NLEDS; ++i)
{
if (which.charAt(i) == '1')
{
document.getElementById("led"+i).src = LED_ON;
}
}
}
/**
* Turn every led off(without turning value attribute)
*/
function turn_all_leds_images_off()
{
// Turn all off
for (let i = 0; i < NLEDS; ++i)
{
document.getElementById("led"+i).src = LED_OFF;
}
}
/**
* Makes leds blink i times
*/
function blink_led_effect(i, which)
{
// Because the recursive function fulfills an action every two iterations
blink_led_effect_helper(i*2, which);
}
/**
* Makes leds blink i/2 times
*/
function blink_led_effect_helper(i, which)
{
if (i % 2 == 1)
{
turn_leds_images_on(which);
}
else
{
turn_all_leds_images_off();
}
if (--i > -1)
{
setTimeout(function() { blink_led_effect_helper(i, which); }, 500);
}
}

View File

@ -1,146 +0,0 @@
<?php
/**
* Fun with Binary - a fun way of introducing binary
* Copyright (C) 2018, Diogo Cordeiro.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* api.php
*
* Fun with Binary
* Web Server
*
* Diogo Peralta Cordeiro
* up201705417@fc.up.pt
*
* Generates the chalenges and controls the arduino
*/
header('Access-Control-Allow-Origin: *');
class game
{
/*
* ==Warning==
* You must add www-data to dialout group
* for serial port communication to work!
*/
// Arduino related
protected $comPort = "/dev/ttyACM0";
protected $arduino_available = true;
// Storage related
public $correct_answer_path = "/var/www/answer.txt";
public $current_answer_path = "/var/www/current_binary_digit.txt";
/**
* Prepares everything for a new game
*/
public function reset()
{
// Reset current binary digit for a potential new game
$fp = fopen($this->current_answer_path, "w");
fwrite($fp, "000000");
// Sends reset command to Arduino
if ($this->arduino_available) {
$fp = fopen($this->comPort, "wb");
fwrite($fp, 9); // 9 is the Reset Byte
}
}
/**
* Starts game
*/
public function start()
{
// Generates a 6-bit random number
$number = rand(0, 63);
// Memorizes the correct binary answer
$fp = fopen($this->correct_answer_path, "w");
fwrite($fp, sprintf("%06d", decbin($number)));
return $number;
}
/**
* Turn current answer bits accordingly
*/
public function change_state($led_id)
{
// Update and memorize the new current answer
$current_binary_digit = file_get_contents($this->current_answer_path);
$current_binary_digit[(int)$led_id] = ($current_binary_digit[(int)$led_id] == 1) ? 0 : 1;
$fp = fopen($this->current_answer_path, "w");
fwrite($fp, $current_binary_digit);
// Updates Arduino output
if ($this->arduino_available) {
$fp = fopen($this->comPort, "wb");
fwrite($fp, (int)$led_id);
}
}
/**
* Compares the given answer with the right answer and tells the result
* Returns true if won, false otherwise
*/
public function end($given_answer, $correct_answer)
{
if ($given_answer == $correct_answer) { // Won
// Sends Won command to Arduino
if ($this->arduino_available) {
$fp = fopen($this->comPort, "wb");
fwrite($fp, 7); // 7 is the Won Byte
}
return true;
} else { // Lost
// Sends Lost command to Arduino
if ($this->arduino_available) {
$fp = fopen($this->comPort, "wb");
fwrite($fp, 8); // 8 is the Lost Byte
}
return false;
}
}
}
/**
* API Handler
*/
$game = new game();
if (isset($_GET["start"])) {
$game->reset();
$number = $game->start();
// Print out the number and let the games begin
echo $number;
} elseif (isset($_GET["change_state"])) {
$led_id = $_GET["change_state"];
$game->change_state($led_id);
} elseif (isset($_GET["end"])) { // Game Over
$given_answer = file_get_contents($game->current_answer_path);
$correct_answer = file_get_contents($game->correct_answer_path);
if ($game->end($given_answer, $correct_answer)) {
echo "That's right!";
} else {
echo "Oops, the answer was: ".$correct_answer;
}
}

292
server/server.ino Normal file
View File

@ -0,0 +1,292 @@
/**
* Fun with Binary - a fun way of introducing binary
* Copyright (C) 2018, Diogo Cordeiro.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Server Core
* @package Fun with Binary
* @author Diogo Cordeiro <up201705417@fc.up.pt>
* @copyright 2018 Diogo Cordeiro.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link https://www.diogo.site/projects/fun_with_binary/
*/
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
// Pages
#include "file1.h"
// Define a dns server for Captive Portal
const byte DNS_PORT = 53;
DNSServer dnsServer;
IPAddress apIP(42, 42, 42, 42); // Defining a static IP address: local & gateway
// Default IP in AP mode is 192.168.4.1
IPAddress netMsk(255, 255, 255, 0);
// These are the WiFi access point settings. Update them to your liking
const char *ssid = "Fun with Binary";
//const char *password = "";
// Define a web server at port 80 for HTTP
ESP8266WebServer webServer(80);
// Number of leds
#define NLEDS 6
// LEDs board outputs
int bits[NLEDS] = { D0, D1, D2, D3, D4, D5 };
// Memorizes bits state
int current_answer[NLEDS] = { 0 };
/**
* Turns all leds on
* **Doesn't update current_answer**
*/
void
turn_all_on()
{
for (int i = 0; i < NLEDS; ++i)
{
digitalWrite(bits[i], HIGH);
}
}
/**
* Turns all leds off
* **Doesn't update current_answer**
*/
void
turn_all_off()
{
for (int i = 0; i < NLEDS; ++i)
{
digitalWrite(bits[i], LOW);
}
}
/**
* App endpoint
*/
void
handleRoot()
{
webServer.send(200, "text/html", file1);
}
/**
* 404 - Page Not Found endpoint
*/
void
handleNotFound()
{
String message = "File Not Found\n\n";
message += "URI: ";
message += webServer.uri();
message += "\nMethod: ";
message +=(webServer.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += webServer.args();
message += "\n";
for (uint8_t i = 0; i < webServer.args(); ++i) {
message +=
" " + webServer.argName(i) + ": " + webServer.arg(i) +
"\n";
}
webServer.send(404, "text/plain", message);
}
/**
* Let the user know when an invalid input is attempted. When this function
* is called it actually is a good sign because although we return a 500 HTTP
* Status Code we have in fact controlled the invalid input internal error.
*
* This kind of errors shall not happen during regular usage of our App.
* If this is thrown it probably was due to someone messing with our API.
*/
void
handleInputError()
{
String message = "Invalid Input - Internal Error Controlled\n\n";
message += "URI: ";
message += webServer.uri();
message += "\nMethod: ";
message +=(webServer.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += webServer.args();
message += "\n";
for (uint8_t i = 0; i < webServer.args(); ++i)
{
message +=
" " + webServer.argName(i) + ": " + webServer.arg(i) +
"\n";
}
webServer.send(500, "text/plain", message);
}
/**
* Switches a led state (a.k.a. bit of current answer)
*
* **Updates current_answer**
*/
void
switch_led()
{
int incomingByte = webServer.arg("led").toInt();
// Validate input
if (incomingByte >= NLEDS || incomingByte < 0)
{
handleInputError();
return;
}
if (current_answer[incomingByte] == 1)
{ // Turn LED off
digitalWrite(bits[incomingByte], LOW);
current_answer[incomingByte] = 0;
}
else
{ // Turn LED on
digitalWrite(bits[incomingByte], HIGH);
current_answer[incomingByte] = 1;
}
webServer.send(200, "text/plain", "ok");
}
/**
* Allows the printing of a binary string in our "led display"
*
* **Doesn't update current_answer**
*/
void
print_binary_string(String which)
{
for (int i = 0; i < NLEDS; ++i)
{
if (which.charAt(i) == '1')
{
digitalWrite(bits[i], HIGH);
}
else
{
digitalWrite(bits[i], LOW);
}
}
}
/**
* Resets for a potential new game
*/
void
reset_game()
{
turn_all_off();
// Reset current_answer
for (int i = 0; i < NLEDS; ++i)
{
current_answer[i] = 0;
}
}
/**
* Blinks current_answer for 3 seconds (3 times) and resets the game
*/
void
won_game()
{
for (int i = 0; i < 3; ++i)
{
turn_all_off();
delay(500);
print_binary_string(current_answer);
delay(500);
}
reset_game();
}
/**
* The setup routine runs once when you press reset.
*/
void
setup()
{
// initialize the digital pins as an output.
for (int i = 0; i < NLEDS; ++i)
{
pinMode(bits[i], OUTPUT);
}
Serial.begin(115200);
Serial.println();
Serial.println("Configuring access point...");
// Set WiFi mode to Access Point, you can also add Station mode
WiFi.mode(WIFI_AP); //_STA);
// set-up the custom IP address
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); // subnet FF FF FF 00
// You can remove/add the password parameter if you want the AP to be open/closed.
WiFi.softAP(ssid); //, password);
// if DNSServer is started with "*" for domain name, it will reply with
// provided IP to all DNS request
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(DNS_PORT, "*", apIP);
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
/**** ROUTES ****/
webServer.on("/generate_204", handleRoot); // Android captive portal.
webServer.on("/fwlink", handleRoot); // Microsoft captive portal.
webServer.on("/", handleRoot);
webServer.on("/switch_state", switch_led);
webServer.on("/won", won_game);
webServer.onNotFound(handleNotFound);
// Start WebServer
webServer.begin();
Serial.println("HTTP server started");
}
/**
* The loop routine runs over and over again forever.
*/
void
loop()
{
dnsServer.processNextRequest();
webServer.handleClient();
}

258
style.css Normal file
View File

@ -0,0 +1,258 @@
/** theme: base
*
* @package Fun with Binary
* @author Diogo Cordeiro <up201705417@fc.up.pt>
* @copyright 2018 Diogo Cordeiro.
* @license http://creativecommons.org/licenses/by/3.0/ Creative Commons Attribution 3.0 Unported
* @link https://www.diogo.site/projects/fun_with_binary/
*/
/* Resets css values */
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video
{
margin: 0;
padding: 0;
border: 0;
font: inherit;
vertical-align: baseline
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section
{
display: block
}
body
{
line-height: 1
}
ol,ul
{
list-style: none
}
blockquote,q
{
quotes: none
}
blockquote:before, blockquote:after,
q:before, q:after
{
content: '';
content: none
}
table
{
border-collapse: collapse;
border-spacing: 0
}
/* Custom styling */
/* Sets font type to Code */
@font-face,.container,.text
{
font-family:code, sans-serif
}
/* Sets overall font, size, and blocks user highlighting/dragging */
.container
{
width: 100%;
cursor: default;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none
}
/* Center leds and text */
.images,.text
{
text-align: center
}
/* Cursor over led shall be a pointer */
.led:hover
{
cursor: pointer
}
/* single led container */
.box
{
display: inline-block
}
/* led's corresponding power of 2 (a.k.a.: label) */
.labels
{
z-index: 0;
height: 2.5vw;
visibility: visible;
margin: 8% -5% 0px -15%;
font-size: 3vw
}
.box,.labels
{
position: relative
}
/* single led */
.led
{
margin-top: 1vh;
display: block;
z-index: 0;
opacity: 100;
width: 90%
}
/* Statement holder */
#statement
{
position: relative;
right: .5vw;
text-align: center;
margin-bottom: 1vh
}
/* Statement */
#statement_text
{
font-size: 2vw;
margin-top: 2vw;
margin-bottom: 3vw
}
/* Settings */
#settings
{
display: block;
text-align: center
}
#settings li
{
display: inline-block
}
.button
{
width: 20vw;
margin: auto 0 auto auto
}
.button
{
height: auto;
text-align: center;
margin: auto 0 auto auto
}
.switch
{
position: relative;
display: inline-block;
width: 60px;
height: 34px
}
.switch input
{
display:none
}
.toggle
{
transition: none;
-webkit-transition: none;
-moz-transition: none;
-o-transition: none
}
.slider
{
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s
}
.slider:before
{
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s
}
input:checked + .slider
{
background-color: #2196F3
}
input:focus + .slider
{
box-shadow: 0 0 1px #2196F3
}
input:checked + .slider:before
{
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px)
}
/* Rounded sliders */
.slider.round
{
border-radius: 34px
}
.slider.round:before
{
border-radius: 50%
}
/* Footer/Credits */
#footer
{
font-size: 12px;
margin-top: 3vw
}