diff --git a/2019-setembro/foxalex/README.md b/2019-setembro/foxalex/README.md
new file mode 100644
index 0000000..355763f
--- /dev/null
+++ b/2019-setembro/foxalex/README.md
@@ -0,0 +1,9 @@
+# Pense Bem Challenge
+
+Esse é o código para entrada no desafio promovido pela CollabCodeTech.
+
+##### Nota
+
+Enquanto desenvolvia a parte de Javascript para as funcionalidades da aplicação fui procurar por alguma referência sobre os sons originais do aparelho, acabei visualizando o excelente projeto do [Leandro Pereira](https://github.com/lpereira/Pense-Bem) e **Felipe Sanches**, a anos atrás eles já haviam feito todo um trabalho de engenharia reversa do brinquedo, aconselho bastante a dar uma olhada em todo material deles.
+
+Depois de ler e estudar todo conteúdo deles resolvi utilizar o código deles ao invés de rescrever tudo do zero novamente, modificando e adaptando o código a necessidade da minha aplicação.
diff --git a/2019-setembro/foxalex/css/app.css b/2019-setembro/foxalex/css/app.css
new file mode 100644
index 0000000..15d1128
--- /dev/null
+++ b/2019-setembro/foxalex/css/app.css
@@ -0,0 +1,556 @@
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+ outline: 0;
+}
+
+body {
+ font-family: 'Roboto', sans-serif;
+ background: repeating-linear-gradient(
+ 90deg,
+ #f0f0f0 0,
+ #f0f0f0 5%,
+ transparent 0,
+ transparent 50%
+ )
+ 0 / 15px 15px,
+ repeating-linear-gradient(
+ 180deg,
+ #f0f0f0 0,
+ #f0f0f0 5%,
+ transparent 0,
+ transparent 50%
+ )
+ 0 / 15px 15px;
+}
+button {
+ font-family: 'Roboto', sans-serif;
+}
+
+.image-ref img {
+ max-width: 800px;
+}
+
+/** Main Wrap */
+.main-wrap {
+ max-width: 960px;
+ margin: 40px auto;
+ padding: 10px;
+}
+.main-wrap button {
+ border: 1px solid #3c302b;
+ cursor: pointer;
+ transition: border 0.1s ease-in-out;
+}
+.main-wrap button:hover {
+ border: 1px solid #905846;
+}
+.main-wrap button:active {
+ border: 2px solid #000;
+ border-right-width: 0px;
+ border-bottom-width: 0px;
+}
+/** End Main Wrap */
+
+/** Top Structure */
+.top-structure {
+ background-color: #cdcac9;
+ padding: 2.2em;
+ margin: 10px;
+ margin-bottom: 0;
+ border-radius: 10px;
+ box-shadow: inset 0em 0em 1em -0.3em rgba(0, 0, 0, 0.5);
+}
+.top-structure .content {
+ display: flex;
+ padding: 3px;
+ border-radius: 5px;
+ box-shadow: 0em 0em 0.1em 0.1em rgba(0, 0, 0, 0.5),
+ 0.03em 0.01em 0em 0.2em rgba(255, 255, 255, 0.9),
+ inset 0em 0em 0.1em 0.03em rgba(255, 255, 255, 0.4),
+ inset 0.5em 0em 0.2em rgba(0, 0, 0, 0.4);
+}
+.top-structure .content .fake-disk {
+ width: 40%;
+ display: flex;
+ position: relative;
+ border-radius: 5px;
+ border-top-left-radius: 0px;
+ border-bottom-left-radius: 0px;
+ justify-content: center;
+ align-items: center;
+ box-shadow: inset 0.2em 0 0.2em -0.1em #fff;
+}
+.top-structure .content .fake-disk .cube,
+.top-structure .content .fake-disk .disk {
+ position: absolute;
+}
+.top-structure .content .fake-disk .cube {
+ width: 30%;
+ height: 30%;
+ border-radius: 4px;
+ box-shadow: inset 0.3em 0em 0.4em -0.2em rgba(0, 0, 0, 0.5),
+ inset -0.2em 0em 0.2em -0.1em rgba(255, 255, 255, 0.9);
+}
+.top-structure .content .fake-disk .disk {
+ background-color: #cdcac9;
+ width: 80%;
+ height: 4%;
+ /* border: 1px dashed red; */
+ border-radius: 5px;
+ border: 1px solid #aaa;
+ box-shadow: inset 0.3em 0em 0.4em -0.2em rgba(0, 0, 0, 0.8),
+ 0em -0.2em 0.1em 0.05em rgba(0, 0, 0, 0.07),
+ 0.4em 0em 0.2em -0.05em rgba(255, 255, 255, 1), 0em 0em 0.1em 0.3em #cdcac9;
+}
+/** End Top Structure */
+
+/** Display */
+.screen-wrap {
+ background-color: #1b2327;
+ width: 100%;
+ padding: 1em 3em 0 3em;
+}
+.screen-wrap .display {
+ padding: 1em;
+ margin: 0 auto;
+}
+.st0 {
+ fill: #1b2327;
+}
+.st1 {
+ fill: #ed2224;
+}
+.st2 {
+ /* fill: #585c4c; */
+ fill: #352523;
+}
+.screen-wrap .footer {
+ display: flex;
+ color: #fff;
+}
+.screen-wrap .footer > div {
+ width: 50%;
+}
+.screen-wrap .footer .colors {
+ text-align: left;
+}
+.screen-wrap .footer .colors span {
+ display: inline-block;
+ width: 18%;
+ height: 10px;
+ margin: 1%;
+}
+.screen-wrap .footer .colors span:nth-child(1) {
+ background-color: #b22514;
+}
+.screen-wrap .footer .colors span:nth-child(2) {
+ background-color: #c8a201;
+}
+.screen-wrap .footer .colors span:nth-child(3) {
+ background-color: #1451ae;
+}
+.screen-wrap .footer .colors span:nth-child(4) {
+ background-color: #0a9923;
+}
+/** End Display */
+
+/** Join Element */
+.join-element {
+ width: 90%;
+ margin: 0 auto;
+ background-color: #cdcac9;
+ height: 2em;
+ box-shadow: inset 0.3em 0em 0.2em -0.2em rgba(255, 255, 255, 0.9),
+ inset 0em 0em 1em 0em rgba(0, 0, 0, 0.4),
+ inset 0em -0.5em 0.8em -0.5em rgba(0, 0, 0, 0.4);
+}
+/** End Join Element */
+
+/** Bottom Structure */
+.bottom-structure {
+ margin: 10px;
+ margin-top: 0;
+ background-color: #cdcac9;
+ padding: 2.2em;
+ padding-top: 0.8em;
+ border-radius: 5px;
+ box-shadow: inset 0em 0em 2em -0.5em rgba(0, 0, 0, 0.5),
+ inset 0.5em 0 0.2em rgba(255, 255, 255, 0.9),
+ inset 0em 0.3em 0.4em -0.1em rgba(0, 0, 0, 0.3),
+ inset -0.3em 0em 0.2em -0em rgba(0, 0, 0, 0.2);
+}
+.bottom-structure .header {
+ display: flex;
+ justify-content: flex-end;
+}
+.bottom-structure .header h2 {
+ display: inline-block;
+ padding: 0em 0.9em;
+ background: #ceccc4;
+ font-size: 2em;
+ line-height: 0.9em;
+ letter-spacing: -0.05em;
+ margin-bottom: 0.5em;
+ color: #174588;
+ border: 1px solid #999;
+ box-shadow: inset 0.05em 0.01em 0.2em -0.1em rgba(0, 0, 0, 0.2),
+ 2px 1px 1px -1px rgba(0, 0, 0, 0.8),
+ -1px -1px 1px -1px rgba(255, 255, 255, 0.8),
+ 4px 1px 2px -1px rgba(255, 255, 255, 0.8);
+}
+.bottom-structure .header h2 span {
+ display: inline-block;
+ font-size: 0.4em;
+ vertical-align: super;
+}
+/** End Bottom Structure */
+
+/** KeyBoard Wrap */
+.keyboard-wrap {
+ font-size: 1.2em;
+ position: relative;
+ padding: 20px;
+ padding-left: 0px;
+ background-color: #4b423f;
+ border: 1px solid #4b423f;
+ border-radius: 5px;
+ box-shadow: inset 0em 0em 1.2em -0.2em rgba(0, 0, 0, 0.7),
+ 0.7em 0em 0.15em -0.2em rgba(255, 255, 255, 1),
+ 0.1em -0.3em 0.5em -0.1em rgba(255, 255, 255, 1),
+ 0em 0em 0.25em 0.4em rgba(0, 0, 0, 0.3);
+}
+.keyboard-wrap .row {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.keyboard-wrap .col {
+ display: flex;
+ flex-flow: column;
+ justify-content: space-evenly;
+}
+/** End Keyboard Wrap */
+
+/** Main buttons */
+.main-buttons-wrap {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.main-button-wrap {
+ display: inline-block;
+ transform: skew(-15deg);
+ /* border: 1px solid #806056; */
+ border: 1px solid #4e3f3a;
+ padding: 3px;
+ border-radius: 6px;
+ margin: 0 5px;
+ box-shadow: inset -1px 1px 1px 0px rgba(0, 0, 0, 0.2),
+ 1px -1px 1px -1px rgba(255, 255, 255, 0.4);
+}
+.main-button-wrap button {
+ font-size: 1.05em;
+ padding: 2.5em 1.8em;
+ border-radius: 6px;
+ box-shadow: 1px -1px 1px -1px rgba(255, 255, 255, 0.5),
+ -2px -2px 2px -1px rgba(0, 0, 0, 0.4),
+ inset 2px 2px 1px -2px rgba(255, 255, 255, 0.4),
+ inset 2px 2px 2px -1px rgba(0, 0, 0, 0.6),
+ inset 2em 0px 2em rgba(0, 0, 0, 0.1);
+ background-color: transparent;
+}
+.main-button-wrap:nth-child(1) button {
+ background-color: #b22514;
+}
+.main-button-wrap:nth-child(2) button {
+ background-color: #c8a201;
+}
+.main-button-wrap:nth-child(3) button {
+ background-color: #1451ae;
+}
+.main-button-wrap:nth-child(4) button {
+ background-color: #0a9923;
+}
+.main-button-wrap button span {
+ display: block;
+ text-transform: uppercase;
+ color: #fff;
+ transform: skew(15deg);
+ font-weight: bold;
+}
+/** End Main Buttons */
+
+/** Normal Buttons */
+.buttons-wrap {
+ display: flex;
+ justify-content: center;
+ margin: 0.4em;
+ flex-wrap: wrap;
+}
+.button-wrap {
+ width: 3.5em;
+ height: 3.5em;
+ border: 1px solid #4e3f3a;
+ padding: 3px;
+ margin: 0.1em;
+ border-radius: 4px;
+ box-shadow: inset -1px 1px 1px 0px rgba(0, 0, 0, 0.2),
+ inset 0.03em -0.01em 0 0 rgba(0, 0, 0, 0.6),
+ 1px -1px 1px -1px rgba(255, 255, 255, 0.4);
+}
+.button-wrap button {
+ width: 100%;
+ height: 100%;
+ border-radius: 4px;
+ text-transform: uppercase;
+ font-size: 0.7em;
+ font-weight: bold;
+ box-shadow: 1px -0.03em 1px -1px rgba(255, 255, 255, 0.7),
+ -2px -2px 2px -1px rgba(0, 0, 0, 0.4),
+ inset 2px 2px 1px -2px rgba(255, 255, 255, 0.2),
+ inset 2px 2px 2px -1px rgba(0, 0, 0, 0.6),
+ inset 1em 0em 0.8em rgba(0, 0, 0, 0.1);
+}
+/** End Normal Buttons */
+
+/** System Buttons */
+.buttons-wrap.system {
+ transform: translateX(2em);
+ margin-bottom: 0;
+}
+.buttons-wrap.system button {
+ background-color: #fff;
+ color: #1451ae;
+}
+.buttons-wrap.system .button-wrap:nth-child(3) button {
+ background-color: #b22514;
+ color: #fff;
+ font-weight: 300;
+}
+.buttons-wrap.system .button-wrap:nth-child(4) button {
+ background-color: #0a9923;
+ color: #fff;
+}
+/** End System Buttons */
+
+/** Math Buttons */
+.buttons-wrap.math {
+ margin-top: 0;
+}
+.buttons-wrap.math button {
+ color: rgba(255, 255, 255, 0.7);
+ background-color: #1451ae;
+ font-size: 1.9em;
+ font-weight: 300;
+ font-family: Arial, Helvetica, sans-serif;
+}
+/** End Math Buttons */
+
+/** Numbers Buttons */
+.buttons-wrap.numbers {
+ transform: translateX(2em);
+}
+.buttons-wrap.numbers button {
+ background-color: #fff;
+ color: #1451ae;
+ display: flex;
+ align-items: center;
+ justify-content: space-around;
+ flex-flow: column;
+ position: relative;
+}
+.buttons-wrap.numbers button:before {
+ content: ' ';
+ display: block;
+ width: 100%;
+ height: 50%;
+ background-color: #b22514;
+ bottom: 0px;
+ left: 0px;
+ position: absolute;
+ box-shadow: inset 1em 0em 0.8em rgba(0, 0, 0, 0.1);
+}
+.buttons-wrap.numbers button span {
+ display: block;
+ position: relative;
+}
+.buttons-wrap.numbers button span:nth-child(1) {
+ font-size: 1.4em;
+ font-weight: 700;
+}
+.buttons-wrap.numbers button span:nth-child(2) {
+ color: #fff;
+ font-weight: 300;
+ font-size: 0.9em;
+ letter-spacing: 0.1em;
+}
+/** End Numbers Buttons */
+
+/** Games Buttons */
+.buttons-wrap.games button {
+ background-color: #c8a201;
+ color: #1a6d29;
+ font-size: 0.45em;
+ line-height: 1.5em;
+}
+/** End Games Buttons */
+
+/** Overlay */
+.overlay {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+.overlay.hidden {
+ display: none;
+}
+.overlay .modal {
+ background-color: #fff;
+ padding: 2em;
+ padding-top: 1.5em;
+ margin: 20px;
+ max-width: 500px;
+}
+.overlay .modal .colors {
+ margin-bottom: 10px;
+}
+.overlay .modal .colors span {
+ display: inline-block;
+ width: 20px;
+ height: 10px;
+}
+.overlay .modal .colors span:nth-child(1) {
+ background-color: #b22514;
+}
+.overlay .modal .colors span:nth-child(2) {
+ background-color: #c8a201;
+}
+.overlay .modal .colors span:nth-child(3) {
+ background-color: #1451ae;
+}
+.overlay .modal .colors span:nth-child(4) {
+ background-color: #0a9923;
+}
+.overlay .modal h2 {
+ border-bottom: 2px solid #333;
+ padding-bottom: 10px;
+}
+.overlay .modal p {
+ margin: 20px 0;
+}
+.overlay .modal .center {
+ text-align: center;
+}
+.overlay .modal button {
+ margin-top: 20px;
+ border: 1px solid #aaa;
+ padding: 10px 20px;
+ background-color: #aaa;
+ color: #fff;
+ cursor: pointer;
+}
+.overlay .modal button:hover {
+ background-color: #888;
+}
+/** End Overlay */
+
+/** Media Queries for responsible */
+@media only screen and (max-width: 960px) {
+ .main-wrap {
+ font-size: 0.8em;
+ }
+}
+@media only screen and (max-width: 785px) {
+ .keyboard-wrap {
+ padding: 20px 5px 10px 5px;
+ }
+ .keyboard-wrap .row {
+ flex-flow: column;
+ }
+ .keyboard-wrap .row .col {
+ flex-flow: row;
+ }
+ .buttons-wrap.system {
+ transform: none;
+ }
+ .buttons-wrap.math {
+ margin: 0.4em;
+ }
+ .buttons-wrap.numbers {
+ transform: none;
+ }
+ .break-line-1 {
+ width: 100%;
+ }
+}
+@media only screen and (max-width: 625px) {
+ .keyboard-wrap .row .col {
+ flex-flow: column;
+ }
+ .screen-wrap {
+ padding: 1em 2.5em 0 2.5em;
+ }
+}
+@media only screen and (max-width: 525px) {
+ .break-line-1 {
+ width: auto;
+ }
+ .main-buttons-wrap {
+ font-size: 0.8em;
+ }
+ .main-wrap {
+ margin: 0;
+ padding: 0;
+ }
+ .top-structure .content {
+ flex-flow: column;
+ }
+ .top-structure .content .fake-disk {
+ height: 80px;
+ width: 100%;
+ order: -1;
+ box-shadow: none;
+ }
+}
+@media only screen and (max-width: 435px) {
+ .main-buttons-wrap {
+ font-size: 0.7em;
+ }
+ .buttons-wrap {
+ font-size: 0.9em;
+ }
+ .top-structure {
+ margin: 5px;
+ margin-bottom: 0;
+ }
+ .bottom-structure {
+ margin: 5px;
+ margin-top: 0;
+ }
+ .screen-wrap {
+ padding: 1em 1.8em 0 1.8em;
+ }
+}
+@media only screen and (max-width: 400px) {
+ .main-buttons-wrap {
+ font-size: 0.6em;
+ margin: 0;
+ }
+ .screen-wrap {
+ padding: 1em 1.3em 0 1.3em;
+ }
+}
+@media only screen and (max-width: 370px) {
+ .main-buttons-wrap {
+ flex-wrap: wrap;
+ }
+}
+/** End Media Queries for responsible */
diff --git a/2019-setembro/foxalex/index.html b/2019-setembro/foxalex/index.html
new file mode 100644
index 0000000..6be1227
--- /dev/null
+++ b/2019-setembro/foxalex/index.html
@@ -0,0 +1,493 @@
+
+
+
+
+
+
+ Pense Bem Challenge
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a
+
+
+ b
+
+
+ c
+
+
+ d
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Pense Bem Challenge
+
+
Esse é um exemplo do brinquedo de grande popularidade no Brasil entre os anos 80 e 90. Todas as funcionabilidades estão ativas, inclusive você pode utlizar os livros originais do brinquedo.
+
Não esqueça de clicar em Ligar para iniciar o aplicativo.
+
+
+ Visualizar Exemplo
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2019-setembro/foxalex/js/app.js b/2019-setembro/foxalex/js/app.js
new file mode 100644
index 0000000..964251a
--- /dev/null
+++ b/2019-setembro/foxalex/js/app.js
@@ -0,0 +1,83 @@
+/**
+ * Buttons
+ */
+
+function initButtons() {
+ // Main Buttons
+ const mainButtons = document.querySelectorAll('.main-buttons-wrap button');
+ mainButtons.forEach(button => {
+ button.addEventListener('click', () =>
+ PB_buttonPress(button.innerText.toUpperCase())
+ );
+ });
+ // End Main Buttons
+
+ // System Buttons
+ const systemButtons = document.querySelectorAll(
+ '.buttons-wrap.system button'
+ );
+ systemButtons.forEach(button => {
+ button.addEventListener('click', () =>
+ PB_buttonPress(button.innerText.replace('.', '').toUpperCase())
+ );
+ });
+ // End System Buttons
+
+ // Math Numbers
+ const mathButtons = document.querySelectorAll('.buttons-wrap.math button');
+ mathButtons.forEach(button => {
+ button.addEventListener('click', () =>
+ PB_buttonPress(button.getAttribute('data-signal'))
+ );
+ });
+
+ // Numbers Buttons
+ const numbersButtons = document.querySelectorAll(
+ '.buttons-wrap.numbers button'
+ );
+ numbersButtons.forEach(button => {
+ const number = button.querySelector('span').innerText;
+ button.addEventListener('click', () => PB_buttonPress(number));
+ });
+ // End Numbers
+
+ // Games Buttons
+ const gamesButtons = document.querySelectorAll('.buttons-wrap.games button');
+ gamesButtons.forEach(button => {
+ const action = button.getAttribute('data-game');
+ button.addEventListener('click', () => PB_buttonPress(action));
+ });
+ // End Games Buttons
+}
+
+/**
+ * Overlay Welcome
+ */
+const overlay = document.querySelector('.overlay');
+const btnWelcome = document.querySelector('.overlay button');
+// Add Event - Click
+btnWelcome.addEventListener('click', () => {
+ overlay.classList.add('hidden');
+ window.localStorage.setItem('first', true);
+});
+// End Overlay
+
+/**
+ * Init
+ */
+function init() {
+ // Check and Show Overlay
+ const check = window.localStorage.getItem('first');
+ if (check === null) {
+ overlay.classList.remove('hidden');
+ }
+
+ // Init Buttons
+ initButtons();
+
+ // Init Pensebem.js
+ PB_init();
+}
+
+// Init App
+window.addEventListener('load', init);
diff --git a/2019-setembro/foxalex/js/pensebem.js b/2019-setembro/foxalex/js/pensebem.js
new file mode 100644
index 0000000..1f7cc20
--- /dev/null
+++ b/2019-setembro/foxalex/js/pensebem.js
@@ -0,0 +1,1192 @@
+/**
+ * Pense-Bem Logica desenvolvido por
+ * e
+ *
+ * https://github.com/lpereira/Pense-Bem
+ */
+
+pulseAudioBug = navigator.userAgent.indexOf('Linux') > 0;
+
+if (typeof Float32Array !== "function")
+ Float32Array = Array;
+
+Songs = {
+ Welcome: 'egage',
+ GameSelected: 'CgC',
+ Correct: 'gCC',
+ Wrong: 'ec',
+ Fail: 'egec',
+ Winner: 'gggeCCC',
+ HighBeep: 'C',
+ LowBeep: 'c'
+};
+
+Som = {
+ SampleRate: 8192,
+ TickInterval: 20,
+ currentNote: 0,
+ isPlayingSong: false,
+ lowBeep: function() {
+ Som.playNote(Songs.LowBeep);
+ },
+ highBeep: function() {
+ Som.playNote(Songs.HighBeep);
+ },
+ songFinishedCallback: function() {},
+ toneFinishedPlaying: function() {
+ if (!Som.isPlayingSong) return;
+
+ if (Som.currentNote >= Som.playQueue.length) {
+ Som.currentNote = 0;
+ Som.isPlayingSong = false;
+ if (Som.shouldClearQueue)
+ Som.playQueue = [];
+ Som.songFinishedCallback();
+ Som.songFinishedCallback = function() {};
+ PB.enableKeyboard();
+ } else {
+ Som.playNote(Som.playQueue[Som.currentNote]);
+ Som.notePlayCallback(Som.playQueue[Som.currentNote], Som.currentNote >= Som.playQueue.length - 1);
+ Som.currentNote++;
+ }
+ },
+ playSoundQueue: function(shouldClearQueue, notePlayCallback) {
+ Som.isPlayingSong = true;
+ Som.shouldClearQueue = shouldClearQueue || false;
+ Som.notePlayCallback = notePlayCallback || function() {};
+ PB.disableKeyboard();
+ Som.toneFinishedPlaying();
+ },
+ playSong: function(song, callback) {
+ Som.songFinishedCallback = callback || function() {};
+ Som.playQueue = song;
+ Som.playSoundQueue(true);
+ },
+ encodeBase64: function(str) {
+ var out, i, len;
+ var c1, c2, c3;
+ const Base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+ len = str.length;
+ i = 0;
+ out = '';
+ while (i < len) {
+ c1 = str.charCodeAt(i++) & 0xff;
+ if (i == len) {
+ out += Base64EncodeChars[c1 >> 2];
+ out += Base64EncodeChars[(c1 & 0x3) << 4];
+ out += '==';
+ break;
+ }
+ c2 = str.charCodeAt(i++);
+ if (i == len) {
+ out += Base64EncodeChars[c1 >> 2];
+ out += Base64EncodeChars[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
+ out += Base64EncodeChars[(c2 & 0xF) << 2];
+ out += '=';
+ break;
+ }
+ c3 = str.charCodeAt(i++);
+ out += Base64EncodeChars[c1 >> 2];
+ out += Base64EncodeChars[((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)];
+ out += Base64EncodeChars[((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)];
+ out += Base64EncodeChars[c3 & 0x3F];
+ }
+ return out;
+ },
+ encode8BitAudio: function(data) {
+ var n = data.length;
+
+ // 8-bit mono WAVE header template
+ var header = 'RIFF<##>WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00<##><##>\x01\x00\x08\x00data<##>';
+
+ // Helper to insert a 32-bit little endian int.
+ function insertLong(value) {
+ var bytes = '';
+ for (var i = 0; i < 4; ++i) {
+ bytes += String.fromCharCode(value & 255);
+ value = Math.floor(value / 256);
+ }
+ header = header.replace('<##>', bytes);
+ }
+
+ insertLong(36 + n); // chunk size
+ insertLong(Som.SampleRate); // sample rate
+ insertLong(Som.SampleRate); // byte rate
+ insertLong(n); // subchunk2 size
+ // Output sound data
+ for (var i = 0; i < n; ++i) {
+ header += String.fromCharCode(data[i] * 255);
+ }
+
+ return 'data:audio/wav;base64,' + Som.encodeBase64(header);
+ },
+ newTone: function(f) {
+ var audio = new Audio();
+ audio.volume = PB.audioVolume;
+ const numberOfSamples = Math.ceil(Som.SampleRate * Som.TickInterval / 100);
+ const dt = 1 / Som.SampleRate;
+ var samples = new Float32Array(numberOfSamples);
+ for (var i = 0; i < numberOfSamples; ++i) {
+ const x = f * (i * dt);
+ const y = x - Math.floor(x);
+ const envelope = Math.min(1, 5 * (1 - i / numberOfSamples));
+ //square wave
+ samples[i] = envelope * !!(y >= 0.5);
+ //sawtooth wave
+ //samples.push(envelope * y);
+ //sine wawe
+ //samples.push(envelope * (Math.sin(2*3.1415*x)/2.0 + 0.5));
+ }
+
+ audio.setAttribute('src', Som.encode8BitAudio(samples));
+
+ if (!pulseAudioBug) {
+ audio.addEventListener('ended', function() {
+ Som.toneFinishedPlaying();
+ }, false);
+ }
+
+ audio.autoplay = false;
+ return function() {
+ audio.load();
+ audio.play();
+ if (pulseAudioBug) {
+ window.setTimeout(Som.toneFinishedPlaying, 300);
+ }
+ };
+ },
+ NoteToToneTable: null,
+ playNote: function(n) {
+ //real note frequency values:
+ const FreqC4 = 261.63;
+ const FreqD4 = 293.66;
+ const FreqE4 = 329.63;
+ const FreqF4 = 349.23;
+ const FreqF4Sharp = 369.994;
+ const FreqG4 = 392.00;
+ const FreqA4 = 440.00;
+ const FreqB4 = 493.88;
+ const FreqC5 = 523.25;
+ const FreqC5Sharp = 554.365;
+ const FreqD5 = 587.33;
+ const FreqE5 = 659.255;
+
+ if (!Som.NoteToToneTable) {
+ if (!PB.bugfix) {
+ Som.NoteToToneTable = {
+ 'c': Som.newTone(FreqD4),
+ 'd': Som.newTone(FreqE4),
+ 'e': Som.newTone(FreqF4Sharp),
+ 'f': Som.newTone(FreqG4),
+ 'g': Som.newTone(FreqA4),
+ 'a': Som.newTone(FreqB4),
+ 'b': Som.newTone(FreqC5Sharp),
+ 'C': Som.newTone(FreqD5),
+ 'D': Som.newTone(FreqE5),
+ 'p': function() {
+ PB.delay(3, Som.toneFinishedPlaying);
+ }
+ };
+ } else {
+ Som.NoteToToneTable = {
+ 'c': Som.newTone(FreqC4),
+ 'd': Som.newTone(FreqD4),
+ 'e': Som.newTone(FreqE4),
+ 'f': Som.newTone(FreqF4),
+ 'g': Som.newTone(FreqG4),
+ 'a': Som.newTone(FreqA4),
+ 'b': Som.newTone(FreqB4),
+ 'C': Som.newTone(FreqC5),
+ 'D': Som.newTone(FreqD5),
+ 'p': function() {
+ PB.delay(3, Som.toneFinishedPlaying);
+ }
+ };
+ }
+ }
+ var tone = Som.NoteToToneTable[n];
+ if (tone)
+ tone();
+ }
+};
+
+//------------------------------------------------------------------------------
+Aritmetica = {
+ reset: function(possibleOperations) {
+ Aritmetica.possibleOperations = possibleOperations || '+-/*';
+ Aritmetica.showResultFlag = false;
+ Aritmetica.showOperatorFlag = true;
+ Aritmetica.numQuestions = 10;
+ Display.clear();
+ Som.playSong(Songs.GameSelected, Aritmetica.newGame);
+ },
+ newGame: function() {
+ Aritmetica.points = 0;
+ Aritmetica.currentQuestion = 0;
+ Aritmetica.advanceQuestion();
+ },
+ oneLoopIteration: function() {
+ if (Prompt.done) {
+ Aritmetica.answerQuestion(parseInt(Prompt.getInput(), 10) == Aritmetica.answer);
+ }
+ },
+ answerQuestion: function(correct) {
+ if (correct) {
+ Aritmetica.correct();
+ } else {
+ Aritmetica.incorrect();
+ }
+ },
+ flashResultsAndAdvanceQuestion: function(ticks) {
+ Aritmetica.showCorrectAnswer();
+ Display.blinkAll();
+ PB.delay(ticks || 30, function() {
+ Display.clear();
+ PB.delay(4, Aritmetica.advanceQuestion);
+ });
+ },
+ incorrect: function() {
+ Aritmetica.tries++;
+ if (Aritmetica.tries >= 3) {
+ Display.clear();
+ Som.playSong(Songs.Fail, Aritmetica.flashResultsAndAdvanceQuestion);
+ } else {
+ Display.clear();
+ Som.playSong(Songs.Wrong, function() {
+ PB.delay(2, function() {
+ Aritmetica.redrawScreen();
+ if (Aritmetica.showOperatorFlag) PB.prompt(7, 3);
+ });
+ });
+ }
+ },
+ correct: function() {
+ Display.clear();
+ Som.playSong(Songs.Correct, function() {
+ Aritmetica.points += PB.pointsByNumberOfTries(Aritmetica.tries);
+ Aritmetica.flashResultsAndAdvanceQuestion(10);
+ });
+ },
+ showCorrectAnswer: function() {
+ Aritmetica.redrawScreen();
+ if (Aritmetica.showOperatorFlag) {
+ Display.showNumberAtDigit(Aritmetica.answer, 7);
+ } else {
+ Aritmetica.showOperator(true);
+ }
+ },
+ showOperator: function(force) {
+ if (force || Aritmetica.showOperatorFlag) {
+ Display.setSpecialDigit({
+ '*': 'x',
+ '/': '%',
+ '+': '+',
+ '-': '-'
+ }[Aritmetica.operation]);
+ } else {
+ Display.blinkSpecialDigit('#');
+ }
+ },
+ buttonPress: function(b) {},
+ OperatorFunctionTable: {
+ '+': function(a, b) {
+ return ~~ (a + b);
+ },
+ '-': function(a, b) {
+ return ~~ (a - b);
+ },
+ '/': function(a, b) {
+ return ~~ (a / b);
+ },
+ '*': function(a, b) {
+ return ~~ (a * b);
+ }
+ },
+ redrawScreen: function() {
+ Display.clear();
+ Display.showNumberAtDigit(Aritmetica.firstDigit, 2);
+ Display.showNumberAtDigit(Aritmetica.secondDigit, 4);
+ if (Aritmetica.showResultFlag) Display.showNumberAtDigit(Aritmetica.answer, 7);
+ Aritmetica.showOperator();
+ Display.setSpecialDigit2('=');
+ },
+ advanceQuestion: function() {
+ function isDivisionByZero() {
+ return Aritmetica.operation == '/' && Aritmetica.secondDigit == 0;
+ }
+ function isSumOrSubtractionWithZero() {
+ return (Aritmetica.operation == '+' || Aritmetica.operation == '-') && Aritmetica.secondDigit == 0;
+ }
+ function isDivisionOrMultiplication() {
+ return Aritmetica.operation == '*' || Aritmetica.operation == '/';
+ }
+ function isDivisionOrMultiplicationWithOne() {
+ return isDivisionOrMultiplication() && Aritmetica.secondDigit == 1;
+ }
+ function isZeroDividedOrMultipliedBySomething() {
+ return isDivisionOrMultiplication() && Aritmetica.firstDigit == 0;
+ }
+ function isDivisionOrSubtractionAndResultIsLessThanOne() {
+ return (Aritmetica.operation == '/' || Aritmetica.operation == '-') && Aritmetica.firstDigit < Aritmetica.secondDigit;
+ }
+ function isForbiddenCombination() {
+ return isDivisionByZero() ||
+ isSumOrSubtractionWithZero() ||
+ isDivisionOrMultiplicationWithOne() ||
+ isDivisionOrSubtractionAndResultIsLessThanOne() ||
+ (Aritmetica.showResultFlag && isZeroDividedOrMultipliedBySomething());
+ }
+
+ if (Aritmetica.currentQuestion++ >= Aritmetica.numQuestions) {
+ PB.delay(10, function() {
+ Display.showNumberAtDigit(Aritmetica.points, 7);
+ Display.blinkAll();
+ Som.playSong(Songs.Winner, function() {
+ PB.delay(30, Aritmetica.newGame);
+ });
+ });
+ return;
+ }
+ Aritmetica.tries = 0;
+
+ do {
+ Aritmetica.operation = Aritmetica.possibleOperations[~~ (Math.random() * (Aritmetica.possibleOperations.length - 1))];
+ Aritmetica.firstDigit = ~~ (Math.random() * 99);
+ Aritmetica.secondDigit = ~~ (Math.random() * 9);
+ } while (isForbiddenCombination());
+
+ if (Aritmetica.secondDigit && isDivisionOrMultiplication())
+ Aritmetica.firstDigit -= Aritmetica.firstDigit % Aritmetica.secondDigit;
+ Aritmetica.answer = Aritmetica.OperatorFunctionTable[Aritmetica.operation](Aritmetica.firstDigit, Aritmetica.secondDigit);
+ Aritmetica.redrawScreen();
+ if (Aritmetica.showOperatorFlag)
+ PB.prompt(7, 3);
+ }
+};
+
+//------------------------------------------------------------------------------
+Adicao = {
+ reset: function() {
+ Aritmetica.reset('+');
+ },
+ oneLoopIteration: Aritmetica.oneLoopIteration,
+ buttonPress: Aritmetica.buttonPress
+};
+
+//------------------------------------------------------------------------------
+Subtracao = {
+ reset: function() {
+ Aritmetica.reset('-');
+ },
+ oneLoopIteration: Aritmetica.oneLoopIteration,
+ buttonPress: Aritmetica.buttonPress
+};
+
+//------------------------------------------------------------------------------
+Multiplicacao = {
+ reset: function() {
+ Aritmetica.reset('*');
+ },
+ oneLoopIteration: Aritmetica.oneLoopIteration,
+ buttonPress: Aritmetica.buttonPress
+};
+
+//------------------------------------------------------------------------------
+Divisao = {
+ reset: function() {
+ Aritmetica.reset('/');
+ },
+ oneLoopIteration: Aritmetica.oneLoopIteration,
+ buttonPress: Aritmetica.buttonPress
+};
+
+//------------------------------------------------------------------------------
+Operacao = {
+ reset: function() {
+ Aritmetica.reset();
+ Aritmetica.showOperatorFlag = false;
+ Aritmetica.showResultFlag = true;
+ },
+ oneLoopIteration: function() {},
+ buttonPress: function(b) {
+ switch (b) {
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ Display.setSpecialDigit({
+ '+': '+',
+ '-': '-',
+ '*': 'x',
+ '/': '%'
+ }[b]);
+ Display.stopBlinking(8);
+ PB.delay(2, function() {
+ Aritmetica.answerQuestion(b == Aritmetica.operation);
+ });
+ break;
+ default:
+ Som.highBeep();
+ }
+ }
+};
+
+//------------------------------------------------------------------------------
+SigaMe = {
+ reset: function() {
+ Display.clear();
+ SigaMe.guessIndex = 0;
+ SigaMe.sequence = [];
+ Som.playSong(Songs.GameSelected, function() {
+ PB.delay(5, SigaMe.addRandomNote);
+ });
+ },
+ addRandomNote: function() {
+ SigaMe.sequence.push(~~(Math.random() * 9));
+ SigaMe.playSequence();
+ },
+ oneLoopIteration: function() {},
+ playSequence: function() {
+ var sequenceIndex = 0;
+ function noteFinishedPlaying() {
+ if (++sequenceIndex >= SigaMe.sequence.length)
+ return;
+ Display.clear();
+ PB.delay(2, function() {
+ Display.setDigit(7, SigaMe.sequence[sequenceIndex]);
+ Som.playSong('cdefgabCDE'[SigaMe.sequence[sequenceIndex]], noteFinishedPlaying);
+ });
+ }
+ Display.clear();
+ Display.setDigit(7, SigaMe.sequence[0]);
+ Som.playSong('cdefgabCDE'[SigaMe.sequence[0]], noteFinishedPlaying);
+ },
+ buttonPress: function(b) {
+ if (b in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) {
+ if (b == SigaMe.sequence[SigaMe.guessIndex]) {
+ Display.clear();
+ PB.disableKeyboard();
+ PB.delay(2, function() {
+ Som.playNote('cdefgabCDE'[b]);
+ Display.setDigit(7, b);
+ PB.delay(4, function() {
+ if (SigaMe.sequence.length == 1) {
+ SigaMe.addRandomNote();
+ } else if (SigaMe.sequence.length == 15) {
+ Som.playSong(Songs.Winner, SigaMe.reset);
+ } else if (SigaMe.guessIndex < SigaMe.sequence.length - 1) {
+ SigaMe.guessIndex++;
+ } else {
+ SigaMe.guessIndex = 0;
+ SigaMe.addRandomNote();
+ }
+ PB.enableKeyboard();
+ });
+ });
+ } else {
+ Som.playSong(Songs.Wrong, function() {
+ PB.delay(10, function() {
+ SigaMe.playSequence();
+ SigaMe.guessIndex = 0;
+ });
+ });
+ }
+ }
+ }
+};
+
+//------------------------------------------------------------------------------
+MemoriaTons = {
+ reset: function() {
+ Display.clear();
+ Som.playSong(Songs.GameSelected, function() {
+ MemoriaTons.pressedEnter = false;
+ MemoriaTons.fakePrompt();
+ });
+ },
+ fakePrompt: function() {
+ Display.blinkDigit(7, '-');
+ },
+ oneLoopIteration: function() {},
+ buttonPress: function(b) {
+ if (b == 'ENTER') {
+ MemoriaTons.pressedEnter = true;
+ Som.playSoundQueue(false, function(noteCode, lastNote) {
+ Display.showNumberAtDigit({
+ 'p': 0, 'c': 1, 'd': 2,
+ 'e': 3, 'f': 4, 'g': 5,
+ 'a': 6, 'b': 7, 'C': 8,
+ 'D': 9
+ }[noteCode], 7);
+ PB.delay(2, lastNote ? MemoriaTons.fakePrompt : Display.clear);
+ });
+ return;
+ }
+ var note = {
+ '0': 'p', '1': 'c', '2': 'd',
+ '3': 'e', '4': 'f', '5': 'g',
+ '6': 'a', '7': 'b', '8': 'C',
+ '9': 'D'
+ }[b];
+ if (note) {
+ Display.clear();
+ if (MemoriaTons.pressedEnter) {
+ MemoriaTons.pressedEnter = false;
+ Som.playQueue = [];
+ }
+ Som.playQueue.push(note);
+ Som.playNote(note);
+ Display.showNumberAtDigit(b, 7);
+ } else
+ Som.lowBeep();
+ }
+};
+
+//------------------------------------------------------------------------------
+AdivinheONumero = {
+ isMiddleNumber: false,
+ maxTries: 10,
+ reset: function(isMiddleNumber) {
+ Display.clear();
+ AdivinheONumero.points = 0;
+ AdivinheONumero.isMiddleNumber = isMiddleNumber || false;
+ AdivinheONumero.maxTries = isMiddleNumber ? 3 : 10;
+ Som.playSong(Songs.GameSelected, AdivinheONumero.advanceQuestion);
+ },
+ advanceQuestion: function() {
+ Display.clear();
+
+ if (AdivinheONumero.isMiddleNumber) {
+ AdivinheONumero.firstDigit = Math.round(Math.random() * 50);
+ AdivinheONumero.secondDigit = AdivinheONumero.firstDigit + Math.round(Math.random() * 47) + 2;
+ AdivinheONumero.answer = Math.round((AdivinheONumero.firstDigit + AdivinheONumero.secondDigit) / 2);
+ } else {
+ AdivinheONumero.firstDigit = 0;
+ AdivinheONumero.secondDigit = 99;
+ AdivinheONumero.answer = AdivinheONumero.firstDigit + Math.round(Math.random() * (AdivinheONumero.secondDigit - AdivinheONumero.firstDigit));
+ }
+
+ AdivinheONumero.tries = 0;
+ Display.showNumberAtDigit(AdivinheONumero.firstDigit, 2);
+ Display.showNumberAtDigit(AdivinheONumero.secondDigit, 6);
+ PB.prompt(4, 2, '*');
+ },
+ showAnswer: function(s) {
+ Display.clear();
+ Som.playSong(s, function() {
+ Display.setSpecialDigit('~');
+ Display.setSpecialDigit2('-');
+ Display.showNumberAtDigit(AdivinheONumero.firstDigit, 2);
+ Display.showNumberAtDigit(AdivinheONumero.secondDigit, 6);
+ Display.showNumberAtDigit(AdivinheONumero.answer, 4);
+ PB.delay(20, function() {
+ Display.clear();
+ PB.delay(3, AdivinheONumero.advanceQuestion);
+ });
+ });
+ },
+ oneLoopIteration: function() {
+ if (!Prompt.done) return;
+ var guess = Prompt.getInput();
+ if (guess != AdivinheONumero.answer) {
+ if (!AdivinheONumero.isMiddleNumber) {
+ if (guess < AdivinheONumero.answer) AdivinheONumero.firstDigit = guess;
+ else AdivinheONumero.secondDigit = guess;
+
+ Display.showNumberAtDigit(AdivinheONumero.firstDigit, 2);
+ Display.showNumberAtDigit(AdivinheONumero.secondDigit, 6);
+ }
+
+ AdivinheONumero.tries++;
+ if (AdivinheONumero.tries < AdivinheONumero.maxTries) {
+ Som.playSong(Songs.Wrong, function() {
+ PB.prompt(4, 2, '*');
+ });
+ return;
+ }
+ AdivinheONumero.showAnswer(Songs.Fail);
+ } else {
+ AdivinheONumero.showAnswer(Songs.Correct);
+ AdivinheONumero.points += PB.pointsByNumberOfTries(AdivinheONumero.tries);
+ }
+ },
+ buttonPress: function() {}
+};
+
+//------------------------------------------------------------------------------
+NumeroDoMeio = {
+ reset: function() {
+ AdivinheONumero.maxTries = 3;
+ AdivinheONumero.reset(true);
+ },
+ oneLoopIteration: AdivinheONumero.oneLoopIteration,
+ buttonPress: AdivinheONumero.buttonPress
+};
+
+//------------------------------------------------------------------------------
+Livro = {
+ StateChoosingBook: 0,
+ StateQuestioning: 1,
+ reset: function() {
+ Som.playSong(Songs.GameSelected, function() {
+ Livro.state = Livro.StateChoosingBook;
+ PB.prompt();
+ });
+ },
+ oneLoopIteration: function() {
+ switch (Livro.state) {
+ case Livro.StateChoosingBook:
+ if (!Prompt.done) return;
+ const bookCode = Prompt.getInput();
+ const bookNumber = parseInt(bookCode.substring(0, 2));
+ const sectionNumber = parseInt(bookCode.substring(2));
+
+ if (sectionNumber < 1 || sectionNumber > 6 || bookCode < 1) {
+ Display.clear();
+ Som.playSong(Songs.Wrong, PB.prompt);
+ return;
+ }
+
+ Livro.bookNumber = bookNumber;
+ Livro.sectionNumber = sectionNumber;
+ Livro.isReviewMode = sectionNumber == 6;
+ if (!Livro.isReviewMode) {
+ Livro.maxQuestion = sectionNumber * 30;
+ Livro.currentQuestion = Livro.maxQuestion - 30;
+ } else {
+ Livro.maxQuestion = 150;
+ Livro.chooseRandomQuestion();
+ }
+ Livro.answeredQuestions = 0;
+ Livro.points = 0;
+
+ Livro.state = Livro.StateQuestioning;
+
+ Display.clear();
+ Som.playSong(Songs.Correct, Livro.advanceQuestion);
+ break;
+ case Livro.StateQuestioning:
+ }
+ },
+ chooseRandomQuestion: function() {
+ Livro.currentQuestion = ~~(Math.random() * (Livro.maxQuestion - 1)) + 1;
+ },
+ highlightAnswer: function(answer, blink) {
+ Display.clear();
+ Display.showNumberAtDigit(Livro.currentQuestion, 3);
+ const digit = {'A': 4, 'B': 5, 'C': 6, 'D': 7}[answer];
+ if (blink)
+ Display.blinkDigit(digit, '_');
+ else
+ Display.setDigit(digit, '_');
+ },
+ showCorrectAnswer: function(blink) {
+ Livro.highlightAnswer(Livro.getCorrectAnswer(), blink);
+ },
+ displayQuestionPrompt: function() {
+ Display.clear();
+ PB.delay(3, function() {
+ Display.showNumberAtDigit(Livro.currentQuestion, 3);
+ for (var i = 4; i <= 7; i++)
+ Display.setDigit(i, '_');
+ });
+ PB.enableKeyboard();
+ },
+ advanceQuestion: function() {
+ if (Livro.currentQuestion >= 0) {
+ Livro.points += PB.pointsByNumberOfTries(Livro.tries);
+ }
+ Livro.tries = 0;
+ if (Livro.isReviewMode) {
+ Livro.chooseRandomQuestion();
+ } else {
+ ++Livro.currentQuestion;
+ }
+
+ if (Livro.answeredQuestions >= 30) {
+ Display.clear();
+ Display.showNumberAtDigit(Livro.points, 7);
+ Display.blinkAll();
+ PB.disableKeyboard();
+ Som.playSong(Songs.Winner, function() {
+ PB.delay(30, function() {
+ Livro.state = Livro.StateChoosingBook;
+ PB.enableKeyboard();
+ PB.prompt();
+ });
+ });
+ return;
+ }
+ Livro.displayQuestionPrompt();
+ },
+ getCorrectAnswer: function() {
+
+
+ const patternList = [
+ 'CDDBAADCBDAADCBB',
+ 'CCBDDDBDABABDACA',
+ 'DDCBDABABDACACCB',
+ 'AABBCDCDDDACAABC',
+ 'CCABADBBBCDCDDDA',
+ 'ADCBADBADBBDDCCB',
+ 'ADDBADBBDCCCBADB',
+ 'DDBBDABBDABDABCC',
+ 'BDDCCDDAACDBBDDB',
+ 'CBCDCBBBDABDDDCD'
+ ];
+
+ const index = Math.floor((Livro.currentQuestion - 1) / 15);
+ const question = (Livro.currentQuestion % 15 > 0 ? Livro.currentQuestion % 15 : 15)
+
+ const answers = patternList[index];
+
+ return answers[(Livro.bookNumber+question)%16]
+ },
+ buttonPress: function(b) {
+ switch (Livro.state) {
+ case Livro.StateChoosingBook:
+ break;
+ case Livro.StateQuestioning:
+ switch (b) {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ PB.disableKeyboard();
+
+ if (Livro.getCorrectAnswer(b) == b) {
+ ++Livro.answeredQuestions;
+ Livro.showCorrectAnswer(true);
+ Som.playSong(Songs.Correct, function() {
+ PB.delay(10, Livro.advanceQuestion);
+ });
+ return;
+ }
+ ++Livro.tries;
+ if (Livro.tries >= 3) {
+ ++Livro.answeredQuestions;
+ Livro.showCorrectAnswer(true);
+ Som.playSong(Songs.Fail, function() {
+ PB.delay(20, Livro.advanceQuestion);
+ });
+ } else {
+ Display.clear();
+ PB.delay(3, function() {
+ Livro.highlightAnswer(b, false);
+ Som.playSong(Songs.Wrong, function() {
+ PB.delay(10, Livro.displayQuestionPrompt);
+ });
+ });
+ }
+ break;
+ default:
+ Som.lowBeep();
+ }
+ break;
+ }
+ }
+};
+
+//------------------------------------------------------------------------------
+Welcome = {
+ ButtonToActivityTable: {
+ 'ADIVINHE-O-NÚMERO': AdivinheONumero,
+ 'ADIÇÃO': Adicao,
+ 'MULTIPLICAÇÃO': Multiplicacao,
+ 'DIVISÃO': Divisao,
+ 'ARITMÉTICA': Aritmetica,
+ 'OPERAÇÃO': Operacao,
+ 'SIGA-ME': SigaMe,
+ 'MEMÓRIA-TONS': MemoriaTons,
+ 'NÚMERO-DO-MEIO': NumeroDoMeio,
+ 'SUBTRAÇÃO': Subtracao,
+ 'LIVRO': Livro
+ },
+ reset: function() {
+ Display.clear();
+ Som.playSong(Songs.Welcome, function() {
+ Display.blinkSpecialDigit('*');
+ });
+ },
+ oneLoopIteration: function() {},
+ buttonPress: function(b) {
+ const newActivity = Welcome.ButtonToActivityTable[b];
+ if (newActivity)
+ PB.setActivity(newActivity);
+ else
+ Som.lowBeep();
+ }
+};
+
+//------------------------------------------------------------------------------
+Standby = {
+ reset: function() {
+ Display.clear();
+ PB.disableKeyboard();
+ },
+ oneLoopIteration: function() {},
+ buttonPress: function(b) {}
+};
+
+//------------------------------------------------------------------------------
+Prompt = {
+ maxDigitSize: 3,
+ initialDigit: 7,
+ done: false,
+ promptCharacter: '-',
+ reset: function() {
+ Prompt.done = false;
+ Prompt.input = ' ';
+ Display.clear(Prompt.initialDigit - Prompt.maxDigitSize + 1, Prompt.initialDigit);
+ if (Prompt.initialDigit == 4 && Prompt.maxDigitSize == 2) {
+ Display.setSpecialDigit(' ');
+ Display.setSpecialDigit2(' ');
+ Display.blinkSpecialDigit(Prompt.promptCharacter);
+ } else
+ Display.blinkDigit(Prompt.initialDigit, Prompt.promptCharacter);
+ },
+ getInput: function() {
+ const value = Prompt.input;
+ Prompt.reset();
+ return value;
+ },
+ isEmpty: function() {
+ return Prompt.input == ' ';
+ },
+ oneLoopIteration: function() {},
+ redrawPrompt: function() {
+ Display.showNumberAtDigit(Prompt.input, Prompt.initialDigit);
+ },
+ buttonPress: function(b) {
+ if (b == 'ENTER') {
+ if (Prompt.isEmpty()) {
+ Som.highBeep();
+ return;
+ }
+ Prompt.done = true;
+ PB.activity = PB.previousActivity;
+ return;
+ }
+ if (b in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) {
+ Som.lowBeep();
+ Display.disableBlink();
+ if (Prompt.initialDigit == 4 && Prompt.maxDigitSize == 2) {
+ Display.setSpecialDigit('~');
+ Display.setSpecialDigit2('-');
+ }
+ switch (Prompt.maxDigitSize) {
+ case 1:
+ Prompt.input = b;
+ break;
+ case 2:
+ Prompt.input = Prompt.input[1] + b;
+ break;
+ default:
+ Prompt.input = Prompt.input[1] + Prompt.input[2] + b;
+ break;
+ }
+ Prompt.redrawPrompt();
+ } else {
+ //blink and HighBeep
+ Som.highBeep();
+ }
+ }
+};
+
+//------------------------------------------------------------------------------
+Display = {
+ onPhase: true,
+ blinkTable: 0,
+ blinkTimer: null,
+ contents: ['?', '?', '?', '?', '?', '?', '?', '?', '?'],
+ SpecialFontTable: {
+ ' ': 0,
+ '#': 49279,
+ '%': 49216,
+ '+': 16420,
+ '*': 16447,
+ '-': 16384,
+ 'x': 27,
+ '~': 128
+ },
+ FontTable: {
+ ' ': 0,
+ '*': 64,
+ '-': 64,
+ '0': 63,
+ '1': 3,
+ '2': 109,
+ '3': 103,
+ '4': 83,
+ '5': 118,
+ '6': 126,
+ '7': 35,
+ '8': 127,
+ '9': 119,
+ '_': 4
+ },
+ setSegmentById: function(id, state) {
+ var s = document.getElementById(id);
+ s.setAttribute('visibility', state ? 'hidden' : 'visible');
+ },
+ setSegment: function(i, seg, state) {
+ Display.setSegmentById('d' + i + '_' + seg, state);
+ },
+ clear: function(begin, end) {
+ begin = begin || 1;
+ end = end || 7;
+ for (var i = begin; i <= end; ++i)
+ Display.setDigit(i, ' ');
+ const range = end - begin;
+ if (range >= 3) Display.setSpecialDigit(' ');
+ if (range >= 5) Display.setSpecialDigit2(' ');
+ Display.disableBlink();
+ },
+ restoreFromStoredContents: function() {
+ if (!Display.onPhase) return;
+ for (var d = 0; d < 7; d++)
+ if (Display.blinkTable & (1 << d))
+ Display.setDigit(d + 1, Display.contents[d], true);
+ if (Display.blinkTable & 1 << 7) Display.setSpecialDigit(Display.contents[7], true);
+ if (Display.blinkTable & 1 << 8) Display.setSpecialDigit2(Display.contents[8], true);
+ Display.onPhase = false;
+ },
+ hideBlinkingSegments: function() {
+ if (Display.onPhase) return;
+ for (var d = 0; d < 7; d++)
+ if (Display.blinkTable & (1 << d))
+ Display.setDigit(d + 1, ' ', true);
+ if (Display.blinkTable & 1 << 7) Display.setSpecialDigit(' ', true);
+ if (Display.blinkTable & 1 << 8) Display.setSpecialDigit2(' ', true);
+ Display.onPhase = true;
+ },
+ blinkTimerCallback: function() {
+ if (PB.ticks % 10 < 3) {
+ Display.hideBlinkingSegments();
+ } else {
+ Display.restoreFromStoredContents();
+ }
+ },
+ enableBlinkTimerIfNeeded: function() {
+ if (!Display.blinkTable) {
+ if (Display.blinkTimer) {
+ Display.blinkTimer = clearInterval(Display.blinkTimer);
+ Display.restoreFromStoredContents();
+ }
+ } else if (!Display.blinkTimer)
+ Display.blinkTimer = setInterval(Display.blinkTimerCallback, 100);
+ },
+ disableBlink: function() {
+ Display.blinkTable = 0;
+ Display.enableBlinkTimerIfNeeded();
+ },
+ blinkAll: function() {
+ Display.blinkTable = -1;
+ Display.enableBlinkTimerIfNeeded();
+ },
+ blinkDigit: function(which, c) {
+ if (c) Display.setDigit(which, c);
+ Display.blinkTable |= 1 << (which - 1);
+ Display.enableBlinkTimerIfNeeded();
+ },
+ blinkSpecialDigit: function(c) {
+ if (c) Display.setSpecialDigit(c);
+ Display.blinkTable |= 1 << 7;
+ Display.enableBlinkTimerIfNeeded();
+ },
+ blinkSpecialDigit2: function(c) {
+ if (c) Display.setSpecialDigit2(c);
+ Display.blinkTable |= 1 << 8;
+ Display.enableBlinkTimerIfNeeded();
+ },
+ stopBlinking: function(which) {
+ Display.blinkTable &= ~ (1 << (which - 1));
+ Display.enableBlinkTimerIfNeeded();
+ },
+ setDisplay: function(c) {
+ for (var i = 1; i <= 7; ++i) {
+ Display.setDigit(i, c[i - 1]);
+ }
+ },
+ setDigit: function(i, c, tmp) {
+ if (tmp === undefined) {
+ Display.contents[i - 1] = c;
+ }
+ var state = Display.FontTable[c] || Display.FontTable[' '];
+ for (var segment = 0; segment < 7; segment++)
+ Display.setSegment(i, 'abcdefg'[segment], state & (1 << segment));
+ },
+ showNumberAtDigit: function(n, d) {
+ if (typeof (n) == 'string') {
+ if (n.length == 1) {
+ Display.setDigit(d, n[0]);
+ } else if (n.length == 2) {
+ Display.setDigit(d, n[1]);
+ Display.setDigit(d - 1, n[0]);
+ } else {
+ Display.setDigit(d, n[2]);
+ Display.setDigit(d - 1, n[1]);
+ Display.setDigit(d - 2, n[0]);
+ }
+ } else {
+ Display.setDigit(d, n % 10);
+ if (n < 100) {
+ if (n = ~~(n / 10) % 10)
+ Display.setDigit(d - 1, n);
+ } else {
+ Display.setDigit(d - 1, ~~ (n / 10) % 10);
+ Display.setDigit(d - 2, ~~ (n / 100) % 10);
+ }
+ }
+ },
+ setSpecialDigit: function(c, tmp) {
+ if (tmp === undefined) {
+ Display.contents[7] = c;
+ }
+ if (c in Display.FontTable)
+ Display.setDigit(3, c);
+ var state = Display.SpecialFontTable[c] || Display.SpecialFontTable[' '];
+ for (var segment = 0; segment < 8; segment++) {
+ Display.setSegment(8, 'abcdefgh'[segment], state & (1 << segment));
+ Display.setSegment(3, 'abcdefgh'[segment], (state >> 8) & (1 << segment));
+ }
+ },
+ setSpecialDigit2: function(c, tmp) {
+ if (tmp === undefined) {
+ Display.contents[8] = c;
+ }
+
+ Display.setSegmentById('igual', {'=': true, '-': true}[c] || false);
+ Display.setSegmentById('igual2', {'=': true, '-': false}[c] || false);
+ }
+};
+
+//------------------------------------------------------------------------------
+PB = {
+ bugfix: false,
+ /* we are simulating all the bugs from the original machine */
+ activity: null,
+ ticks: 0,
+ delayTable: {},
+ keyboardEnabled: true,
+ audioVolume: 1,
+ init: function() {
+ PB.setActivity(Standby);
+ PB.reset();
+ setInterval(PB.oneLoopIteration, 100);
+ PB.turnOnReminderTimer = setTimeout(PB.showReminder, 3000);
+ },
+ showReminder: function() {
+ //document.getElementById('ligue-me-tip').setAttribute('display', 'true');
+ PB.turnOnReminderTimer = clearTimeout(PB.turnOnReminderTimer);
+ },
+ resetDefaultVariables: function() {
+ PB.delayTable = {};
+ PB.enableKeyboard();
+ PB.ticks = 0;
+ Display.disableBlink();
+ },
+ reset: function() {
+ PB.resetDefaultVariables();
+ if (PB.activity) PB.activity.reset();
+ },
+ delay: function(ticks, callback) {
+ PB.delayTable[PB.ticks + ticks] = callback;
+ },
+ oneLoopIteration: function() {
+ ++PB.ticks;
+
+ for (var delay in PB.delayTable) {
+ if (PB.ticks >= delay) {
+ PB.delayTable[delay]();
+ delete PB.delayTable[delay];
+ }
+ }
+
+ if (PB.activity) PB.activity.oneLoopIteration();
+ },
+ setActivity: function(m, keepScreenContents) {
+
+ if (PB.turnOnReminderTimer)
+ PB.turnOnReminderTimer = clearTimeout(PB.turnOnReminderTimer);
+ //document.getElementById('ligue-me-tip').setAttribute('display', 'none');
+ if (!keepScreenContents)
+ Display.clear();
+ PB.resetDefaultVariables();
+ PB.activity = m;
+ PB.reset();
+ },
+ prompt: function(initialDigit, maxDigitSize, promptCharacter) {
+ Prompt.initialDigit = initialDigit || 7;
+ Prompt.maxDigitSize = maxDigitSize || 3;
+ Prompt.promptCharacter = promptCharacter || '-';
+ PB.previousActivity = PB.activity;
+ PB.setActivity(Prompt, true);
+ },
+ buttonPress: function(b) {
+ switch (b) {
+ case 'LIGA':
+ PB.setActivity(Welcome);
+ return;
+ case 'DESL':
+ PB.setActivity(Standby);
+ return;
+ default:
+ if (PB.keyboardEnabled && PB.activity) {
+ if ((PB.activity != Welcome) && (b in Welcome.ButtonToActivityTable)) {
+ Som.highBeep();
+ return;
+ }
+ PB.activity.buttonPress(b);
+ }
+ }
+ },
+ enableKeyboard: function() {
+ PB.keyboardEnabled = true;
+ },
+ disableKeyboard: function() {
+ PB.keyboardEnabled = false;
+ },
+ pointsByNumberOfTries: function(t) {
+ switch (t) {
+ case 0:
+ return 10;
+ case 1:
+ return 6;
+ case 2:
+ return 4;
+ }
+ return 0;
+ }
+};
+
+document.onkeydown = function(event) {
+ const keyCode = {
+ 13: 'ENTER',
+ 19: 'PAUSE',
+ 80: 'PAUSE',
+ 27: 'DESL',
+ 48: '0',
+ 49: '1',
+ 50: '2',
+ 51: '3',
+ 52: '4',
+ 53: '5',
+ 54: '6',
+ 55: '7',
+ 56: '8',
+ 57: '9'
+ }[event.which];
+ if (keyCode) PB.buttonPress(keyCode);
+};
+
+//If we want to fix bugs found on the original machine
+// then uncomment the following line:
+//PB.bugfix = true;
+//Change the PB Audio Volume;
+PB.audioVolume = .05;
+
+// Add Functions to Window;
+window['PB_buttonPress'] = PB.buttonPress;
+window['PB_init'] = PB.init;
\ No newline at end of file