<commit_before>
'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;

const scriptRules = require('./script.json');

var myDate = new Date();
var groet = '';

/* hour is before noon */
if ( myDate.getHours() < 12 )
{
groet = "Goeiemorgen 🌝";
}
else  /* Hour is from noon to 5pm (actually to 5:59 pm) */
if ( myDate.getHours() >= 12 && myDate.getHours() <= 17 )
{
groet = "Goedendag 🌞";
}
else  /* the hour is after 5pm, so it is between 6pm and midnight */
if ( myDate.getHours() > 17 && myDate.getHours() <= 24 )
{
groet = "Goedenavond 🌙";
}
else
if (myDate.getHours() > 20  || myDate.getHours() <= 8 )
{
  groet = "Goedenavond 🌙  Bedankt voor je bezoek maar op dit moment is Independer echter gesloten. 🕘 Uiteraard kun je met onze IndyBot verder praten maar er is helaas niemand die jouw vraag specifiek kan beantwoorden. Je kan je vraag ook doormailen 📩 naar info@independer. Dan komt het altijd goed.";
}
else  /* the hour is not between 0 and 24, so something is wrong */
{
groet = "Welkom. ";
}

function wait(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

module.exports = new Script({

 processing: {
prompt: (bot) => bot.say('![](http://www.bieg.nl/beeld/speechbubble.gif)'),
 receive: () => 'processing'
 },

start: {
    receive: (bot,message) => {
        const opening = message.text.trim().toUpperCase();
        return bot.say(`${groet}... Wat voor soort hypotheek zoek je? `)
        .then(() => bot.say(`![](http://www.bieg.nl/beeld/woningen.jpg)`))
        .then(() => bot.say(`%[Starters Hypotheek](postback:hypotheektype_starter) %[Nieuwe hypotheek](postback:hypotheektype_nieuw) %[Hypotheek oversluiten](postback:hypotheektype_oversluiten)`))
        .then(() => 'selecteerHypotheek');
    }
},

selecteerHypotheek: {
    receive: (bot, message) => {
      switch(message.text) {
      case 'Hoi':
            return bot.say(`${groet} waar ben je naar op zoek? %[Starters hypotheek](postback:hypotheektype_starter) %[Nieuwe hypotheek](postback:hypotheektype_nieuw) %[Hypotheek oversluiten](postback:hypotheektype_oversluiten)`)
            .then(() => 'askName')
          break;
      case 'Starters Hypotheek':
          return bot.say(`Wat voor type woning zoek je? `)
          .then(() => bot.say(`%[🏬 Appartement](postback:hypotheekkeuze_appartement) %[🏠 Huis](postback:hypotheekkeuze_huis) %[📭 Vakantiewoning](postback:hypotheekkeuze_vakantiewoning)`))
          .then(() => 'woningType')
              break;
        case 'Nieuwe hypotheek':
          return bot.say(`😞 Helaas biedt Independer momenteel alleen Starters een hypotheek aan.`)
          .then(() => bot.say(`Via onderstaande link kun je de beste hypotheekadviseur voor jou vinden. %[💼 Zoek Hypotheek Adviseur](https://www.independer.nl/hypotheekadviseur/jelocatie.aspx)`))
            .then(() => 'finish')
          break;
        case 'Hypotheek oversluiten':
          return bot.say(`😟 Het spijt me maar op dit moment biedt Independer alleen  Starters een hypotheek.`)
          .then(()=> bot.say(`Als het allemaal wel zo ver is, wil je dan een update ontvangen? %[Ja, dat wil ik wel](postback:update_ja) %[Nee, dat hoeft niet](postback:update_nee)`))
            .then(() => 'updateOntvangen')
          break;
        default:
          return bot.say(`![](http://www.bieg.nl/beeld/speechbubble.gif)`)
            .then(() => 'processing')
          break;
      }
    }
},

updateOntvangen: {
    receive: (bot, message) => {
      switch(message.text) {
        case 'Ja, dat wil ik wel':
            return bot.say(`👍 Leuk, dan houd ik  je op de hoogte zodra er weer nieuws is.`)
            .then(() => 'update_ja');
          break;
          case 'Nee, dat hoeft niet':
              receive: () => 'bye'
              break;
          default:
            receive => 'processing'
            break;
}
}
},

update_ja: {
  prompt: (bot) => bot.say('Wat is je email adres?'),
      receive: (bot, message) => {
          const emailer=message.text.trim();
          return bot.setProp('emailer', emailer)
              .then(()  => bot.say(`Ok - ✉  dan hou ik je via ${emailer} op de hoogte.`))
              .then(()  =>'lastCheck')
    }
},
update_nee: {
  receive: () => 'bye'
},

hypotheekkeuze_appartement: {
receive: (bot,message)  => {
    //  prompt: (bot) => bot.say(`![](http:www.bieg.nl/beeld/appartement.jpg)`)
    receive: () => 'askName'
}
},
hypotheekkeuze_huis: {
//    prompt: (bot) => bot.say(`![](http:www.bieg.nl/beeld/appartement.jpg)`)
  receive: () => 'askName'
},
hypotheekkeuze_vakantiewoning: {
//    prompt: (bot) => bot.say(`![](http:www.bieg.nl/beeld/appartement.jpg)`)
    receive: () => 'askName'
},
hypotheekStarter: {
    receive: () => 'askName'
},
hypotheektype_nieuw: {
    prompt: (bot) => bot.say('Independer biedt momenteel alleen voor Starters een hypotheek. Onderstaande link bied je meer informatie %[Hypotheek Adviseur](https://www.independer.nl/hypotheekadviseur/intro.aspx)'),
    receive: () => 'processing'
},

woningType: {
  receive: (bot, message) => {
    switch(message.text) {
        case '🏬 Appartement':
          return bot.say(`Nice!`)
          .then(() => 'vervolgVragen')
          break;
      case '🏠 Huis':
          return bot.say(`Leuk`)
          .then(() => 'vervolgVragen')
          break;
    case '📭 Vakantiewoning':
          return bot.say(`Gezellig`)
          .then(() => 'vervolgVragen')
          break;
      default:
        receive => 'processing'
        break;
        }
    }
},

vervolgVragen: {
  prompt: (bot) => bot.say('Hoe heet je eigelijk? Dat maakt het praten een stuk makkelijker...'),
  receive: (bot, message) => {
      const name = message.text;
      return bot.setProp('name', name)
          .then(() => bot.say('Hoi ${name}. 📋 Ik heb nog wat vragen voor je om verder te kunnen.'))
          .then(() => 'processing');
    }
},

lastCheck: {
    prompt: (bot) => bot.say(' Is er nog iets waar ik  je bij kan helpen?  🚦  %[Ja, nou je het zegt ](postback:verzoekPDF) %[Nee hoor](postback:bye)'),
          receive: (bot, message) => {
            switch(message.text) {
              case 'Nee hoor':
                  receive: ()  => 'bye'
                  break;
             case 'Ja':
                  receive: () => 'speak'
                  break;
            case 'Nee':
                  receive: () => 'bye'
                  break;
            default:
              return bot.say('![](http://www.bieg.nl/beeld/speechbubble.gif)')
                .then(() => 'processing')
              break;
            }
        }
},

verzoekPDF: {
    //bot.sendMessage  = "Heb je wat algemene informatie voor me?";
    return bot.say('![](http://www.bieg.nl/beeld/info.pdf)')
      .then(() => 'processing')
}

bye: {
    prompt: (bot) => bot.say('Fijn je gesproken te hebben. Bedankt voor je tijd ⏲'),
    receive: ()  => 'finish'
},

// error: {
// prompt: (bot) => bot.say('Sorry - kun je dat nog eens zeggen?  Er ging iets mis...'),
// receive: () => ''
// },

finish: {
receive: () => 'finish'
},

  speak: {
          receive: (bot, message) => {

              let upperText = message.text.trim().toUpperCase();

              function updateSilent() {
                  switch (upperText) {
                      case "CONNECT ME":
                          return bot.setProp("silent", true);
                      case "DISCONNECT":
                          return bot.setProp("silent", false);
                      default:
                          return Promise.resolve();
                  }
              }

              function getSilent() {
                  return bot.getProp("silent");
              }

              function processMessage(isSilent) {
                  if (isSilent) {
                      return Promise.resolve("speak");
                  }

                  if (!_.has(scriptRules, upperText)) {
                      return bot.say(`So, I'm good at structured conversations but stickers, emoji and sentences still confuse me. Say 'more' to chat about something else.`).then(() => 'speak');
                  }

                  var response = scriptRules[upperText];
                  var lines = response.split('\n');

                  var p = Promise.resolve();
                  _.each(lines, function(line) {
                      line = line.trim();
                      p = p.then(function() {
                          console.log(line);
                          return wait(50).then(function() {
                              return bot.say(line);
                          });
                      });
                  });

                  return p.then(() => 'speak');
              }

              return updateSilent()
                  .then(getSilent)
                  .then(processMessage);
          }
      }
});
<commit_msg>ds<commit_after>
'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;

const scriptRules = require('./script.json');

var myDate = new Date();
var groet = '';

/* hour is before noon */
if ( myDate.getHours() < 12 )
{
groet = "Goeiemorgen 🌝";
}
else  /* Hour is from noon to 5pm (actually to 5:59 pm) */
if ( myDate.getHours() >= 12 && myDate.getHours() <= 17 )
{
groet = "Goedendag 🌞";
}
else  /* the hour is after 5pm, so it is between 6pm and midnight */
if ( myDate.getHours() > 17 && myDate.getHours() <= 24 )
{
groet = "Goedenavond 🌙";
}
else
if (myDate.getHours() > 20  || myDate.getHours() <= 8 )
{
  groet = "Goedenavond 🌙  Bedankt voor je bezoek maar op dit moment is Independer echter gesloten. 🕘 Uiteraard kun je met onze IndyBot verder praten maar er is helaas niemand die jouw vraag specifiek kan beantwoorden. Je kan je vraag ook doormailen 📩 naar info@independer. Dan komt het altijd goed.";
}
else  /* the hour is not between 0 and 24, so something is wrong */
{
groet = "Welkom. ";
}

function wait(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}

module.exports = new Script({

 processing: {
prompt: (bot) => bot.say('![](http://www.bieg.nl/beeld/speechbubble.gif)'),
 receive: () => 'processing'
 },

start: {
    receive: (bot,message) => {
        const opening = message.text.trim().toUpperCase();
        return bot.say(`${groet}... Wat voor soort hypotheek zoek je? `)
        .then(() => bot.say(`![](http://www.bieg.nl/beeld/woningen.jpg)`))
        .then(() => bot.say(`%[Starters Hypotheek](postback:hypotheektype_starter) %[Nieuwe hypotheek](postback:hypotheektype_nieuw) %[Hypotheek oversluiten](postback:hypotheektype_oversluiten)`))
        .then(() => 'selecteerHypotheek');
    }
},

selecteerHypotheek: {
    receive: (bot, message) => {
      switch(message.text) {
      case 'Hoi':
            return bot.say(`${groet} waar ben je naar op zoek? %[Starters hypotheek](postback:hypotheektype_starter) %[Nieuwe hypotheek](postback:hypotheektype_nieuw) %[Hypotheek oversluiten](postback:hypotheektype_oversluiten)`)
            .then(() => 'askName')
          break;
      case 'Starters Hypotheek':
          return bot.say(`Wat voor type woning zoek je? `)
          .then(() => bot.say(`%[🏬 Appartement](postback:hypotheekkeuze_appartement) %[🏠 Huis](postback:hypotheekkeuze_huis) %[📭 Vakantiewoning](postback:hypotheekkeuze_vakantiewoning)`))
          .then(() => 'woningType')
              break;
        case 'Nieuwe hypotheek':
          return bot.say(`😞 Helaas biedt Independer momenteel alleen Starters een hypotheek aan.`)
          .then(() => bot.say(`Via onderstaande link kun je de beste hypotheekadviseur voor jou vinden. %[💼 Zoek Hypotheek Adviseur](https://www.independer.nl/hypotheekadviseur/jelocatie.aspx)`))
            .then(() => 'finish')
          break;
        case 'Hypotheek oversluiten':
          return bot.say(`😟 Het spijt me maar op dit moment biedt Independer alleen  Starters een hypotheek.`)
          .then(()=> bot.say(`Als het allemaal wel zo ver is, wil je dan een update ontvangen? %[Ja, dat wil ik wel](postback:update_ja) %[Nee, dat hoeft niet](postback:update_nee)`))
            .then(() => 'updateOntvangen')
          break;
        default:
          return bot.say(`![](http://www.bieg.nl/beeld/speechbubble.gif)`)
            .then(() => 'processing')
          break;
      }
    }
},

updateOntvangen: {
    receive: (bot, message) => {
      switch(message.text) {
        case 'Ja, dat wil ik wel':
            return bot.say(`👍 Leuk, dan houd ik  je op de hoogte zodra er weer nieuws is.`)
            .then(() => 'update_ja');
          break;
          case 'Nee, dat hoeft niet':
              receive: () => 'bye'
              break;
          default:
            receive => 'processing'
            break;
}
}
},

update_ja: {
  prompt: (bot) => bot.say('Wat is je email adres?'),
      receive: (bot, message) => {
          const emailer=message.text.trim();
          return bot.setProp('emailer', emailer)
              .then(()  => bot.say(`Ok - ✉  dan hou ik je via ${emailer} op de hoogte.`))
              .then(()  =>'lastCheck')
    }
},
update_nee: {
  receive: () => 'bye'
},

hypotheekkeuze_appartement: {
receive: (bot,message)  => {
    //  prompt: (bot) => bot.say(`![](http:www.bieg.nl/beeld/appartement.jpg)`)
    receive: () => 'askName'
}
},
hypotheekkeuze_huis: {
//    prompt: (bot) => bot.say(`![](http:www.bieg.nl/beeld/appartement.jpg)`)
  receive: () => 'askName'
},
hypotheekkeuze_vakantiewoning: {
//    prompt: (bot) => bot.say(`![](http:www.bieg.nl/beeld/appartement.jpg)`)
    receive: () => 'askName'
},
hypotheekStarter: {
    receive: () => 'askName'
},
hypotheektype_nieuw: {
    prompt: (bot) => bot.say('Independer biedt momenteel alleen voor Starters een hypotheek. Onderstaande link bied je meer informatie %[Hypotheek Adviseur](https://www.independer.nl/hypotheekadviseur/intro.aspx)'),
    receive: () => 'processing'
},

woningType: {
  receive: (bot, message) => {
    switch(message.text) {
        case '🏬 Appartement':
          return bot.say(`Nice!`)
          .then(() => 'vervolgVragen')
          break;
      case '🏠 Huis':
          return bot.say(`Leuk`)
          .then(() => 'vervolgVragen')
          break;
    case '📭 Vakantiewoning':
          return bot.say(`Gezellig`)
          .then(() => 'vervolgVragen')
          break;
      default:
        receive => 'processing'
        break;
        }
    }
},

vervolgVragen: {
  prompt: (bot) => bot.say('Hoe heet je eigelijk? Dat maakt het praten een stuk makkelijker...'),
  receive: (bot, message) => {
      const name = message.text;
      return bot.setProp('name', name)
          .then(() => bot.say('Hoi ${name}. 📋 Ik heb nog wat vragen voor je om verder te kunnen.'))
          .then(() => 'processing');
    }
},

lastCheck: {
    prompt: (bot) => bot.say(' Is er nog iets waar ik  je bij kan helpen?  🚦  %[Ja, nou je het zegt ](postback:verzoekPDF) %[Nee hoor](postback:bye)'),
          receive: (bot, message) => {
            switch(message.text) {
              case 'Nee hoor':
                  receive: ()  => 'bye'
                  break;
             case 'Ja':
                  receive: () => 'speak'
                  break;
            case 'Nee':
                  receive: () => 'bye'
                  break;
            default:
              return bot.say('![](http://www.bieg.nl/beeld/speechbubble.gif)')
                .then(() => 'processing')
              break;
            }
        }
},

verzoekPDF: {
    //bot.sendMessage  = "Heb je wat algemene informatie voor me?";
    return bot.say('![](http://www.bieg.nl/beeld/info.pdf)')
      .then(() => 'processing')
},

bye: {
    prompt: (bot) => bot.say('Fijn je gesproken te hebben. Bedankt voor je tijd ⏲'),
    receive: ()  => 'finish'
},

// error: {
// prompt: (bot) => bot.say('Sorry - kun je dat nog eens zeggen?  Er ging iets mis...'),
// receive: () => ''
// },

finish: {
receive: () => 'finish'
},

  speak: {
          receive: (bot, message) => {

              let upperText = message.text.trim().toUpperCase();

              function updateSilent() {
                  switch (upperText) {
                      case "CONNECT ME":
                          return bot.setProp("silent", true);
                      case "DISCONNECT":
                          return bot.setProp("silent", false);
                      default:
                          return Promise.resolve();
                  }
              }

              function getSilent() {
                  return bot.getProp("silent");
              }

              function processMessage(isSilent) {
                  if (isSilent) {
                      return Promise.resolve("speak");
                  }

                  if (!_.has(scriptRules, upperText)) {
                      return bot.say(`So, I'm good at structured conversations but stickers, emoji and sentences still confuse me. Say 'more' to chat about something else.`).then(() => 'speak');
                  }

                  var response = scriptRules[upperText];
                  var lines = response.split('\n');

                  var p = Promise.resolve();
                  _.each(lines, function(line) {
                      line = line.trim();
                      p = p.then(function() {
                          console.log(line);
                          return wait(50).then(function() {
                              return bot.say(line);
                          });
                      });
                  });

                  return p.then(() => 'speak');
              }

              return updateSilent()
                  .then(getSilent)
                  .then(processMessage);
          }
      }
});
<|endoftext|>


<commit_before>import PropTypes from 'prop-types'

const List = ({ selected, members }) => {
  const item = (selectedMember) => {
    const m = members[selectedMember]
    return (

{m.name}

    )
  }

  return (

      {selected.map(item)}

  )
}

List.propTypes = {
  selected: PropTypes.array.isRequired,
  members: PropTypes.object.isRequired
}

export default List
<commit_msg>Modify style.<commit_after>import PropTypes from 'prop-types'

const List = ({ selected, members }) => {
  const item = (selectedMember) => {
    const m = members[selectedMember]
    return (

{m.name}

    )
  }

  return (

      {selected.map(item)}

  )
}

List.propTypes = {
  selected: PropTypes.array.isRequired,
  members: PropTypes.object.isRequired
}

export default List
<|endoftext|>


<commit_before>var gamepadIndex = null;
var gamepad = null;

function gamepadconnected(e) {
  if(gamepadIndex == null) {
    gamepadIndex = e.gamepad.index;
    gamepad = e.gamepad;
    document.getElementById("gamepadState").innerHTML = "connected";
    console.log("Connect: %s", e.gamepad.id);
  }
}

function gamepaddisconnected(e) {
  if(gamepadIndex == e.gamepad.index) {
    gamepadIndex = null;
    gamepad = null;
    document.getElementById("gamepadState").innerHTML = "disconnected";
    console.log("Disconnect: %s", e.gamepad.id);
  }
}

var buttonDown = false;

function mainloop() {
  if (gamepadIndex != null) {
    updateGamepadState();

    if (buttonDown) {
      if (!isButtonPressed(gamepad, 0)) {
        buttonDown = false;
      }
    } else {
      if (isButtonPressed(gamepad, 0)) {
        buttonDown = true;

        var newCoords = getNewCoordinates(coords, pov.heading, 10);
        svService.getPanorama({location: newCoords, radius: 20}, processSVData);
      }
    }

    // Update heading wrt controller x-axis - ranges from -1 (left) to +1 (right)
    var xAxis = getAxisValue(gamepad, 0);
    pov.heading += xAxis;

    // Simple rotation of steering wheel based on controller input
    document.getElementById("wheel").style.transform = "rotate(" + (xAxis*90) + "deg)";

    // Simple map
    document.getElementById("map").style.transform = "rotate(" + (-pov.heading) + "deg)";

    // Update pitch wrt controller y-axis - ranges from -1 (up) to +1 (down)
    var yAxis = getAxisValue(gamepad, 1);
    pov.pitch -= yAxis; // Need to invert y-axis control
    // Clamp value to +/- 20 so you don't end up looking at your feet or the sky
    if (pov.pitch > 20) {
      pov.pitch = 20;
    }
    if (pov.pitch < -20) {
      pov.pitch = -20;
    }
    pov.pitch *= 0.95; // Automatically drift pitch back to level
    //console.log(pov.pitch);

    streetView.setPov(pov);
  }

  window.requestAnimationFrame(mainloop);
}

function getGamepads() {
  return navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
}

function isButtonPressed(gamepad, buttonId) {
  var button = gamepad.buttons[buttonId];
  //console.log("button[%d]: pressed: %s, value: %d", buttonId, button.pressed, button.value);
  return button.pressed;
}

function getAxisValue(gamepad, axisId) {
  return gamepad.axes[axisId];
}

function updateGamepadState() {
  var connectedGamepads = getGamepads();
  for (var i = 0; i < connectedGamepads.length; i++) {
    if (connectedGamepads[i] && connectedGamepads[i].index == gamepadIndex) {
      gamepad = connectedGamepads[i];
    }
  }
}

// Conversion: degrees to radians
function d2r(degrees) {
  return degrees * (Math.PI / 180);
}

// Conversion: radians to degrees
function r2d(radians) {
  return radians * (180 / Math.PI);
}

// Calculate new coordinates given current coordinates, a heading, and a distance
function getNewCoordinates(coords, heading, distance) {
  // Current coordinates
  var lat = coords.lat;
  var lng = coords.lng;

  // Calculate deviation in meters
  var dx = Math.sin(d2r(heading)) * distance;
  var dy = Math.cos(d2r(heading)) * distance;

  // Calculate deviation in degrees lat/long
  var dlng = dx / (111111.1 * Math.cos(d2r(lat)));
  var dlat = dy / 111111.1;

  // Calculate new lat/long
  lat += dlat;
  lng += dlng;

  // Return new coordinate
  return {lat: lat, lng: lng};
}

// Register event listeners
window.addEventListener("gamepadconnected", gamepadconnected);
window.addEventListener("gamepaddisconnected", gamepaddisconnected);

// Register main update loop
window.requestAnimationFrame(mainloop);

// References to important JS objects
var map;
var streetView;
var svService;
var marker;
// Default view direction
var pov = {heading: 225, pitch: 0};
// Start in Paris
var coords = {lat: 48.8592236, lng: 2.2972824};

function initMap() {
  // Map panel
  map = new google.maps.Map(document.getElementById('map'), {
    center: coords,
    zoom: 18, // Reasonable zoom level for our requirements
    streetViewControl: false // No pegman button
  });
  map.setOptions({
    disableDefaultUI: true,
    draggable: false,
    scrollwheel: false,
    keyboardShortcuts: false
  });

  // Street view panel
  streetView = new google.maps.StreetViewPanorama(document.getElementById("streetView"));
  streetView.setZoom(2);
  streetView.setOptions({
    disableDefaultUI: true, // Remove all controls: compass, zoom etc
    scrollwheel: false, // Disable zooming using the scroll wheel
    panControl: false
  });

  // Hook to communicate with the street view data provider service
  svService = new google.maps.StreetViewService();

  // Set the initial Street View camera to near the starting coordinates
  svService.getPanorama({location: coords, radius: 10}, processSVData);
}

function processSVData(data, status) {
  if (status === google.maps.StreetViewStatus.OK) {
    // Update street view with new location
    streetView.setPano(data.location.pano);
    streetView.setPov(pov);
    streetView.setVisible(true);

    var dot = {
      url: 'dot.png',
      size: new google.maps.Size(20, 20),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(10, 10)
    };

    // Create or update map marker
    if(marker == null) {
      marker = new google.maps.Marker({
        position: data.location.latLng,
        map: map,
        clickable: false,
        icon: dot
      });
    } else {
      marker.setPosition(data.location.latLng);
    }

    // Update minimap to show new location
    map.panTo(data.location.latLng);

    // Update current coordinates
    coords.lat = data.location.latLng.lat();
    coords.lng = data.location.latLng.lng();
  } else {
    console.error('Street View data not found for this location.');
  }
}

<commit_msg>Include Street View coverage layer on map<commit_after>var gamepadIndex = null;
var gamepad = null;

function gamepadconnected(e) {
  if(gamepadIndex == null) {
    gamepadIndex = e.gamepad.index;
    gamepad = e.gamepad;
    document.getElementById("gamepadState").innerHTML = "connected";
    console.log("Connect: %s", e.gamepad.id);
  }
}

function gamepaddisconnected(e) {
  if(gamepadIndex == e.gamepad.index) {
    gamepadIndex = null;
    gamepad = null;
    document.getElementById("gamepadState").innerHTML = "disconnected";
    console.log("Disconnect: %s", e.gamepad.id);
  }
}

var buttonDown = false;

function mainloop() {
  if (gamepadIndex != null) {
    updateGamepadState();

    if (buttonDown) {
      if (!isButtonPressed(gamepad, 0)) {
        buttonDown = false;
      }
    } else {
      if (isButtonPressed(gamepad, 0)) {
        buttonDown = true;

        var newCoords = getNewCoordinates(coords, pov.heading, 10);
        svService.getPanorama({location: newCoords, radius: 20}, processSVData);
      }
    }

    // Update heading wrt controller x-axis - ranges from -1 (left) to +1 (right)
    var xAxis = getAxisValue(gamepad, 0);
    pov.heading += xAxis;

    // Simple rotation of steering wheel based on controller input
    document.getElementById("wheel").style.transform = "rotate(" + (xAxis*90) + "deg)";

    // Simple map
    document.getElementById("map").style.transform = "rotate(" + (-pov.heading) + "deg)";

    // Update pitch wrt controller y-axis - ranges from -1 (up) to +1 (down)
    var yAxis = getAxisValue(gamepad, 1);
    pov.pitch -= yAxis; // Need to invert y-axis control
    // Clamp value to +/- 20 so you don't end up looking at your feet or the sky
    if (pov.pitch > 20) {
      pov.pitch = 20;
    }
    if (pov.pitch < -20) {
      pov.pitch = -20;
    }
    pov.pitch *= 0.95; // Automatically drift pitch back to level
    //console.log(pov.pitch);

    streetView.setPov(pov);
  }

  window.requestAnimationFrame(mainloop);
}

function getGamepads() {
  return navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
}

function isButtonPressed(gamepad, buttonId) {
  var button = gamepad.buttons[buttonId];
  //console.log("button[%d]: pressed: %s, value: %d", buttonId, button.pressed, button.value);
  return button.pressed;
}

function getAxisValue(gamepad, axisId) {
  return gamepad.axes[axisId];
}

function updateGamepadState() {
  var connectedGamepads = getGamepads();
  for (var i = 0; i < connectedGamepads.length; i++) {
    if (connectedGamepads[i] && connectedGamepads[i].index == gamepadIndex) {
      gamepad = connectedGamepads[i];
    }
  }
}

// Conversion: degrees to radians
function d2r(degrees) {
  return degrees * (Math.PI / 180);
}

// Conversion: radians to degrees
function r2d(radians) {
  return radians * (180 / Math.PI);
}

// Calculate new coordinates given current coordinates, a heading, and a distance
function getNewCoordinates(coords, heading, distance) {
  // Current coordinates
  var lat = coords.lat;
  var lng = coords.lng;

  // Calculate deviation in meters
  var dx = Math.sin(d2r(heading)) * distance;
  var dy = Math.cos(d2r(heading)) * distance;

  // Calculate deviation in degrees lat/long
  var dlng = dx / (111111.1 * Math.cos(d2r(lat)));
  var dlat = dy / 111111.1;

  // Calculate new lat/long
  lat += dlat;
  lng += dlng;

  // Return new coordinate
  return {lat: lat, lng: lng};
}

// Register event listeners
window.addEventListener("gamepadconnected", gamepadconnected);
window.addEventListener("gamepaddisconnected", gamepaddisconnected);

// Register main update loop
window.requestAnimationFrame(mainloop);

// References to important JS objects
var map;
var streetView;
var svService;
var marker;
// Default view direction
var pov = {heading: 225, pitch: 0};
// Start in Paris
var coords = {lat: 48.8592236, lng: 2.2972824};

function initMap() {
  // Map panel
  map = new google.maps.Map(document.getElementById('map'), {
    center: coords,
    zoom: 18, // Reasonable zoom level for our requirements
    streetViewControl: false // No pegman button
  });
  map.setOptions({
    disableDefaultUI: true,
    draggable: false,
    scrollwheel: false,
    keyboardShortcuts: false
  });

  // Show valid Street View locations in a blue overlay on the map
  var streetViewLayer = new google.maps.StreetViewCoverageLayer();
  streetViewLayer.setMap(map);

  // Street view panel
  streetView = new google.maps.StreetViewPanorama(document.getElementById("streetView"));
  streetView.setZoom(2);
  streetView.setOptions({
    disableDefaultUI: true, // Remove all controls: compass, zoom etc
    scrollwheel: false, // Disable zooming using the scroll wheel
    panControl: false
  });

  // Hook to communicate with the street view data provider service
  svService = new google.maps.StreetViewService();

  // Set the initial Street View camera to near the starting coordinates
  svService.getPanorama({location: coords, radius: 10}, processSVData);
}

function processSVData(data, status) {
  if (status === google.maps.StreetViewStatus.OK) {
    // Update street view with new location
    streetView.setPano(data.location.pano);
    streetView.setPov(pov);
    streetView.setVisible(true);

    var dot = {
      url: 'dot.png',
      size: new google.maps.Size(20, 20),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(10, 10)
    };

    // Create or update map marker
    if(marker == null) {
      marker = new google.maps.Marker({
        position: data.location.latLng,
        map: map,
        clickable: false,
        icon: dot
      });
    } else {
      marker.setPosition(data.location.latLng);
    }

    // Update minimap to show new location
    map.panTo(data.location.latLng);

    // Update current coordinates
    coords.lat = data.location.latLng.lat();
    coords.lng = data.location.latLng.lng();
  } else {
    console.error('Street View data not found for this location.');
  }
}

<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var newUser = require("./db");
var logConversation = require("./conversation");
var nlp = require("./nlp");
var pushConv = require("./push");
var newBot_msg = require("./newBot");
//var findSession = require("./sessionsearch");

//var sched = require("./sched");

const scriptRules = require('./script.json');

var msgLog = {
    smoochId: '',
    received: '',
    usermessage: '',
    role: '',
    message_id: '',
    sourcetype: '',
    receivedtime: '',
    responsemessage: '',
    responsetype: '',
    responsetime: '',
    newUsercheck: 'false'
  };

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

//    s1: {
//      prompt: (bot) => bot.say('Type part of the session name?'),
//      receive: (bot, message) => {
//        const name = message.text;
//        return bot.setProp('name', name)
//            .then(() => bot.say(`Great! I'll call you ${name}
//Is that OK? %[Yes](postback:yes) %[No](postback:no)`))
//            .then(() => 'speak');
//      }
//    },

//    chris: {
//      receive: (bot, message) => {
//        return bot.getProp('name')
//          .then((name) => bot.say('That is all!'))
//          .then(() => 'speak');
//      }
//    },

    speak: {
        receive: (bot, message) => {

            console.log("===bot message ", message);

            let upperText = message.text.trim().toUpperCase();

//TODO: don't try stateMachine; instead capture last text and if a search thing ie is search by speaker
//then the submit is speaker name and call speakersearch won't work for is session expires
//            if (msgLog.usermessage == 'SBSN') {
//                console.log("=== search string", upperText);
//                var msg = {};
//                findSession(upperText, msg);
//                return bot.setProp("silent", true);
//            }

            msgLog.smoochId = bot.userId;
            msgLog.received = message.received;
            msgLog.usermessage = message.text;
            msgLog.role = message.role;
            msgLog.message_id = message._id;
            msgLog.receivedtime = new Date();
//this mess is my way around the fact that smooch completely  changes the structure of the message obj if it is a postback vs user entered text
//            console.log("===message.message",message.message);
            switch (typeof message.message === "undefined") {
              case false:
//                  console.log("!!!! appMaker = T, message.role", message.message);
                  msgLog.sourcetype = message.action.type;
                break;
              default:
//                  console.log("!!!! appUser = T, message.role", message.source);
                  msgLog.sourcetype = message.source.type;
                break;
            }

            //SK_ACCESS is a heroku config var that has the list of devices smoochids for auth users to send ad hoc push conversations
            var authUsers = process.env.SK_ACCESS

            //Not sure if this is the best way to accomplish not calling newUser everytime, but it seems to work
            if(msgLog.newUsercheck == 'false') {
              console.log("===NewUser");
              newUser(bot)
                .then(msgLog.newUsercheck = 'true');
            }

            //For ad hoc messages - scheduled messages are done differently in checkItems
            if (authUsers.indexOf(bot.userId) !== -1) {
              if (upperText.substr(0,4) == '/SK ') {
                upperText = upperText.substr(0,3);
                newBot_msg(message.text.substr(4));
                console.log("****after push msg:  ",message.text," authUser:  ",authUsers);
              }
            }

//TODO: There is a bug with /support and /a16 now.  /support does not present message and /a16 sometimes doubles the message
            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "/SUPPORT":
                        console.log("*** /support", upperText);
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    case "/A16":
                        console.log("*** /A16 ",upperText," ***");
                        processMessage(false);
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                var promises = [];
                var source;
                var fulfillmentSpeech;
                var simplified;
                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("===in Q.all");
//                        console.log("===received result from API.ai",response);
                        source = response.result.source;
//                        if (source && source !== 'agent')
//                        {
                            fulfillmentSpeech = response.result.fulfillment.speech;
                            simplified = response.result.parameters.simplified;
//                        }
                        console.log("source: ", source);
                        console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                        console.log("simplified: ", simplified);

                        respondMessage(source, fulfillmentSpeech, simplified);
                    });
                }, function(error) {
                    console.log("===Q all error ", error);
                });
            }

            function respondMessage(source, fulfillmentSpeech, simplified)
            {
                console.log("source: ", source);
                console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                console.log("simplified: ", simplified);
                console.log("===receive step 3",upperText);

              if (source != 'agent')
                {
                    console.log("===source is ", source);
                    if (fulfillmentSpeech)
                    {
                      switch (simplified) {
                        case "hello":
                          console.log("===in hello");
                          upperText = simplified.trim().toUpperCase();
                          break;
                        case "do you know":
                        case "can you help":
                        case "do you have":
                        case "how does this app work":
                        case "how much time do you need":
                        case "how to open you":
                        case "what can you talk about":
                        case "what do you know":
                          console.log("===in what do you know");
                          upperText = 'KNOW';
                          break;
                        case "what do you do":
                        case "how do you know":
                        case "job":
                          console.log("===in what do do");
                          upperText = "JOB";
                          break;
                        case "do you know me":
                        case "do you remember me":
                          console.log("===do you know me");
                          upperText = "ME";
                          break;
                        case "who named you":
                        console.log("===NAME");
                          upperText = "NAME";
                          break;
                        case "can you hear me":
                        case "can you speak":
                        case "change your":
                        case "hurry":
                        case "talk faster":
                        case "do you drink":
                        case "do you eat":
                          console.log("===set to NULL and question");
                          upperText = "";
                          break;
                        default:
                          console.log("===in switch default");
                          if (upperText == "EVENING") {break;}
                          msgLog.responsemessage = fulfillmentSpeech;
                          msgLog.responsetime = new Date;
                          msgLog.responsetype = 'API.AI';
                          return bot.say(fulfillmentSpeech).then(() => 'speak');
                      }
                    }
                    else if (simplified)
                    {
                        console.log("simplified is: ", simplified);
                        msgLog.responsemessage = fulfillmentSpeech;
                        msgLog.responsetime = new Date;
                        msgLog.responsetype = 'API.AI';
                        return bot.say(fulfillmentSpeech).then(() => 'speak');
                    }
                }

                console.log("===finished switch, upperText now:",upperText);

                if (!_.has(scriptRules, upperText)) {
                    console.log("===no rule", upperText);
                    return bot.say(`I'm sorry that is not something I know.  Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                }

                var response = scriptRules[upperText];
                var lines = response.split('\n');
                msgLog.responsemessage = response;
                msgLog.responsetime = new Date;
                msgLog.responsetype = 'JSON';
                console.log("=== msgLog  obj",msgLog);
                logConversation(msgLog);

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("=== p line",line);
                        return wait(500).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<commit_msg>adding in api.ai intent for agile2017 - 1<commit_after>'use strict';

const _ = require('lodash');
const Script = require('smooch-bot').Script;
var pg = require('pg');
var Q = require("q");
var request = require("request");
var newUser = require("./db");
var logConversation = require("./conversation");
var nlp = require("./nlp");
var pushConv = require("./push");
var newBot_msg = require("./newBot");
//var findSession = require("./sessionsearch");

//var sched = require("./sched");

const scriptRules = require('./script.json');

var msgLog = {
    smoochId: '',
    received: '',
    usermessage: '',
    role: '',
    message_id: '',
    sourcetype: '',
    receivedtime: '',
    responsemessage: '',
    responsetype: '',
    responsetime: '',
    newUsercheck: 'false'
  };

function wait(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

module.exports = new Script({
    processing: {
        //prompt: (bot) => bot.say('Beep boop...'),
        receive: () => 'processing'
    },

    start: {
        receive: (bot) => {
            return bot.say('Hello!  I\'m A16, the Agile2016 EventBot Concierge.  To find out what I can help you with type MENU for options or KEY for Keywords.')
                .then(() => 'speak');
        }
    },

//    s1: {
//      prompt: (bot) => bot.say('Type part of the session name?'),
//      receive: (bot, message) => {
//        const name = message.text;
//        return bot.setProp('name', name)
//            .then(() => bot.say(`Great! I'll call you ${name}
//Is that OK? %[Yes](postback:yes) %[No](postback:no)`))
//            .then(() => 'speak');
//      }
//    },

//    chris: {
//      receive: (bot, message) => {
//        return bot.getProp('name')
//          .then((name) => bot.say('That is all!'))
//          .then(() => 'speak');
//      }
//    },

    speak: {
        receive: (bot, message) => {

            console.log("===bot message ", message);

            let upperText = message.text.trim().toUpperCase();

//TODO: don't try stateMachine; instead capture last text and if a search thing ie is search by speaker
//then the submit is speaker name and call speakersearch won't work for is session expires
//            if (msgLog.usermessage == 'SBSN') {
//                console.log("=== search string", upperText);
//                var msg = {};
//                findSession(upperText, msg);
//                return bot.setProp("silent", true);
//            }

            msgLog.smoochId = bot.userId;
            msgLog.received = message.received;
            msgLog.usermessage = message.text;
            msgLog.role = message.role;
            msgLog.message_id = message._id;
            msgLog.receivedtime = new Date();
//this mess is my way around the fact that smooch completely  changes the structure of the message obj if it is a postback vs user entered text
//            console.log("===message.message",message.message);
            switch (typeof message.message === "undefined") {
              case false:
//                  console.log("!!!! appMaker = T, message.role", message.message);
                  msgLog.sourcetype = message.action.type;
                break;
              default:
//                  console.log("!!!! appUser = T, message.role", message.source);
                  msgLog.sourcetype = message.source.type;
                break;
            }

            //SK_ACCESS is a heroku config var that has the list of devices smoochids for auth users to send ad hoc push conversations
            var authUsers = process.env.SK_ACCESS

            //Not sure if this is the best way to accomplish not calling newUser everytime, but it seems to work
            if(msgLog.newUsercheck == 'false') {
              console.log("===NewUser");
              newUser(bot)
                .then(msgLog.newUsercheck = 'true');
            }

            //For ad hoc messages - scheduled messages are done differently in checkItems
            if (authUsers.indexOf(bot.userId) !== -1) {
              if (upperText.substr(0,4) == '/SK ') {
                upperText = upperText.substr(0,3);
                newBot_msg(message.text.substr(4));
                console.log("****after push msg:  ",message.text," authUser:  ",authUsers);
              }
            }

//TODO: There is a bug with /support and /a16 now.  /support does not present message and /a16 sometimes doubles the message
            function updateSilent() {
                switch (upperText) {
                    case "CONNECT ME":
                        return bot.setProp("silent", true);
                    case "/SUPPORT":
                        console.log("*** /support", upperText);
                        return bot.setProp("silent", true);
                    case "DISCONNECT":
                        return bot.setProp("silent", false);
                    case "/A16":
                        console.log("*** /A16 ",upperText," ***");
                        processMessage(false);
                        return bot.setProp("silent", false);
                    default:
                        return Promise.resolve();
                }
            }

            function getSilent() {
                return bot.getProp("silent");
            }

            function processMessage(isSilent) {
                if (isSilent) {
                    return Promise.resolve("speak");
                }

                var promises = [];
                var source;
                var fulfillmentSpeech;
                var simplified;
                promises.push(nlp(upperText, bot.userId));

                Q.all(promises).then(function(responses) {
                    // response is the JSON from API.ai
                    responses.forEach(function(response) {
                        console.log("===in Q.all");
//                        console.log("===received result from API.ai",response);
                        source = response.result.source;
                        if (source && source !== 'agent')
                        {
                            fulfillmentSpeech = response.result.fulfillment.speech;
                            simplified = response.result.parameters.simplified;
                        } else if (source && source == 'agent') {
                          fulfillmentSpeech = response.result.fulfillment.speech;
                          simplified = response.result.metadata.intentName;
                        }
                        console.log("source: ", source);
                        console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                        console.log("simplified: ", simplified);

                        respondMessage(source, fulfillmentSpeech, simplified);
                    });
                }, function(error) {
                    console.log("===Q all error ", error);
                });
            }

            function respondMessage(source, fulfillmentSpeech, simplified)
            {
                console.log("source: ", source);
                console.log("fulfillmentSpeech: ", fulfillmentSpeech);
                console.log("simplified: ", simplified);
                console.log("===receive step 3",upperText);

              if (source != 'agent')
                {
                    console.log("===source is ", source);
                    if (fulfillmentSpeech)
                    {
                      switch (simplified) {
                        case "hello":
                          console.log("===in hello");
                          upperText = simplified.trim().toUpperCase();
                          break;
                        case "do you know":
                        case "can you help":
                        case "do you have":
                        case "how does this app work":
                        case "how much time do you need":
                        case "how to open you":
                        case "what can you talk about":
                        case "what do you know":
                          console.log("===in what do you know");
                          upperText = 'KNOW';
                          break;
                        case "what do you do":
                        case "how do you know":
                        case "job":
                          console.log("===in what do do");
                          upperText = "JOB";
                          break;
                        case "do you know me":
                        case "do you remember me":
                          console.log("===do you know me");
                          upperText = "ME";
                          break;
                        case "who named you":
                        console.log("===NAME");
                          upperText = "NAME";
                          break;
                        case "can you hear me":
                        case "can you speak":
                        case "change your":
                        case "hurry":
                        case "talk faster":
                        case "do you drink":
                        case "do you eat":
                          console.log("===set to NULL and question");
                          upperText = "";
                          break;
                        default:
                          console.log("===in switch default");
                          if (upperText == "EVENING") {break;}
                          msgLog.responsemessage = fulfillmentSpeech;
                          msgLog.responsetime = new Date;
                          msgLog.responsetype = 'API.AI Domain';
                          return bot.say(fulfillmentSpeech).then(() => 'speak');
                      }
                    }
                    else if (simplified)
                    {
                        console.log("simplified is: ", simplified);
                        msgLog.responsemessage = fulfillmentSpeech;
                        msgLog.responsetime = new Date;
                        msgLog.responsetype = 'API.AI Intent';
                        return bot.say(fulfillmentSpeech).then(() => 'speak');
                    }
                }

                console.log("===finished switch, upperText now:",upperText);

                if (!_.has(scriptRules, upperText)) {
                    console.log("===no rule", upperText);
                    return bot.say(`I'm sorry that is not something I know.  Type MENU or KEY for a list of things I can help you with.`).then(() => 'speak');
                }

                var response = scriptRules[upperText];
                var lines = response.split('\n');
                msgLog.responsemessage = response;
                msgLog.responsetime = new Date;
                msgLog.responsetype = 'JSON';
                console.log("=== msgLog  obj",msgLog);
                logConversation(msgLog);

                var p = Promise.resolve();
                _.each(lines, function(line) {
                    line = line.trim();
                    p = p.then(function() {
                        console.log("=== p line",line);
                        return wait(500).then(function() {
                            return bot.say(line);
                        });
                    });
                });
                return p.then(() => 'speak');
            }

            return updateSilent()
                .then(getSilent)
                .then(processMessage);
        }
    }
});
<|endoftext|>


<commit_before>//  The calculator pseudoClass represents a four-function calculator.
//  The following both defines and constructs the singleton calculator object.

var calculator = (function () {

    'use strict';

    var model,
        view,
        controller;

    // model pseudoclass is an internal representation of
    // the calculator's state.

    model = {

        tally : 0, // running total since last clear

        operator : '+', // last operator pressed

        temp : '', // number, as it entered by user

        isClear : true, // flag indicates whether there has been output

        // The evaluate function performs a computation.
        // First, it performs the stored operation on temp and tally.
        // Then it stores the given operation for the next evaluation.
        //
        // Returns the state to show to user.

        evaluate : function (operate) {

            // Special condition if there has not been output yet.

            var tempN = parseFloat(this.temp);

            if (this.isClear) {

                this.tally = tempN;
                this.isClear = false;

            } else {

                // Perform the stored operation on tally and
                // temp

                switch (this.operator) {

                case '+':
                    this.tally += tempN;
                    break;

                case '-':
                    this.tally -= tempN;
                    break;

                case 'x':
                    this.tally *= tempN;
                    break;

                case '/':
                    this.tally /= tempN;
                    break;

                }
            }

            // In either case, update the display, and prepare for
            // next input

            this.temp = '0'; // reset temp
            this.operator = operate; // get ready to perform
            // the given operation

            if (isNaN(this.tally)) {
                this.reset();
            }

            return this.tally; // user sees result of
            // computation
        },

        // The update function will take string representing a single
        // digit, and
        // append it to what the user has entered so far, both on the
        // screen and
        // internally.
        // Returns the state to show to user.

        update : function (lastDigit) {

            // wipe out display to prevent leading zero
            if (this.temp === '0') {
                this.temp = '';
            }

            // concat display with new input
            this.temp += lastDigit;

            return this.temp; // user sees number entered thus
            // far
        },

        // The reset function clears the calculator's instance
        // variables, and
        // wipes the screen.

        reset : function () {
            this.tally = 0;
            this.operator = '+';
            this.temp = '0';
            this.isClear = true;
            return 0;
        }

    }; // end model

    // view is the representation of the screen.

    view = {

        // the object holding the output.

        display : {
            innerHTML : "0"
        },

        // method to set display to given number

        output : function (val) {

            this.display.innerHTML = val;

        },

        // Sets sets given object to be the new display.
        // Copies the old output into new display.

        setDisplay : function (newScreen) { // function

            if (typeof newScreen === 'object') {

                newScreen.innerHTML = this.display.innerHTML;

                this.display = newScreen;
            }
        }
    }; // end view

    // These are the calculator's publicly facing methods.
    // They should be consided the controller.

    // Enter number is called when a user presses a digit, and takes that
    // digit as a param. If possible, enterNumber will pass that digit
    // to the inner calculator's update method.

    controller = {
        enterNumber : function (num) {

            if (typeof model.update === 'function') {

                // Pass response from model's update method to
                // the view
                view.output(model.update(num));
            }
        },

        // Enter operator is called when a user presses an operator, and
        // takes
        // that
        // operator as a param. If possible, enterOperator will pass
        // that
        // operator
        // to the inner calculator's evaluate method.

        enterOperator : function (opp) {

            if (typeof model.evaluate === 'function') {

                // Pass response from model's evaluate method to
                // the view
                view.output(model.evaluate(opp));
            }
        },

        // Clear is called when a user presses the clear button, and
        // takes
        // no params. If possible, clear will call the inner
        // calculator's
        // reset method.

        clear : function () {

            if (typeof model.reset === 'function') {

                // Pass response from model's reset method to
                // the view
                view.output(model.reset());
            }
        },

        // Set Display takes an object, and set it to be the
        // Calculator's new output field.

        setDisplay : function (obj) {

            view.setDisplay(obj);
        }
    };

    return controller;

}()); // end calculator definition

// This is where the setup for the calculator happens. It's all
// inside an anonymous function, so the vars and the functions
// will go away at the end.

(function () {

    'use strict';

    var numbers,
        operators,
        i,
        k;

    // First, create click handlers for the buttons

    // function takes a number button dom element, and
    // attaches calc's enterNumber method to its click event
    function bindNum(obj) {
        obj.onclick = function () {
            calculator.enterNumber(this.value); // this is obj
            // (a num btn)
        };
    }

    // function takes a function button dom element, and
    // attaches calc's enterOperator method to its click event
    function bindOpp(obj) {
        obj.onclick = function () {
            calculator.enterOperator(this.value); // this is obj
            // (a fn btn)
        };
    }

    // Second, run setup routine, in which page elements are bound to
    // calculator methods.

    // Start by calling the calcuator's init method, passing
    // in an output element to be the display.

    /*jslint browser:true*/

    calculator.setDisplay(document.getElementById('out'));

    // Move onto binding the numbers' click
    // event to the calculator's update method.

    numbers = document.getElementsByClassName('number');

    for (i = 0; i < numbers.length; i += 1) {

        // clicking a number will update the display and the temp
        // variable

        bindNum(numbers[i]);
    }

    operators = document.getElementsByClassName('operator');

    for (k = 0; k < operators.length; k += 1) {

        // clicking an operator will make the calculator perform an
        // operation.

        bindOpp(operators[k]);

    }

    // lastly, bind the clear function to the clear buttons' click event

    document.getElementById('clear').onclick = function () {
        calculator.clear();
    };

}()); // end the anonymous init function, and invoke it
<commit_msg>pass jslint and comments are the way I want them<commit_after>//  The calculator pseudoClass represents a four-function calculator.
//  The following both defines and constructs the singleton calculator object.

var calculator = (function () {

    'use strict';

    var model,
        view,
        controller;

//  model pseudoclass is an internal representation of
//  the calculator's state.

    model = {

        tally : 0, // running total since last clear

        operator : '+', // last operator pressed

        temp : '', // number, as it entered by user

        isClear : true, // flag indicates whether there has been output

//      The evaluate function performs a computation.
//      First, it performs the stored operation on temp and tally.
//      Then it stores the given operation for the next evaluation.
//
//      Returns the state to show to user.

        evaluate : function (operate) {

//      Special condition if there has not been output yet.

            var tempN = parseFloat(this.temp);

            if (this.isClear) {

                this.tally = tempN;
                this.isClear = false;

            } else {

//              Perform the stored operation on tally and temp

                switch (this.operator) {

                case '+':
                    this.tally += tempN;
                    break;

                case '-':
                    this.tally -= tempN;
                    break;

                case 'x':
                    this.tally *= tempN;
                    break;

                case '/':
                    this.tally /= tempN;
                    break;

                }
            }

//          In either case, update the display, and prepare for
//          next input

            this.temp = '0'; // reset temp
            this.operator = operate; // get ready to perform
            // the given operation

            if (isNaN(this.tally)) {
                this.reset();
            }

            return this.tally; // user sees result of computation
        },

//      The update function will take string representing a single
//      digit, and
//      append it to what the user has entered so far, both on the
//      screen and internally.
//      Returns the state to show to user.

        update : function (lastDigit) {

//          wipe out display to prevent leading zero
            if (this.temp === '0') {
                this.temp = '';
            }

//          concat display with new input
            this.temp += lastDigit;

            return this.temp; // user sees number entered thus far
        },

//      The reset function clears the calculator's instance
//      variables, and wipes the screen.

        reset : function () {
            this.tally = 0;
            this.operator = '+';
            this.temp = '0';
            this.isClear = true;
            return 0;
        }

    }; // end model

//  view is the representation of the screen.

    view = {

//      the object holding the output.

        display : {
            innerHTML : "0"
        },

//      method to set display to given number

        output : function (val) {

            this.display.innerHTML = val;

        },

//      Sets sets given object to be the new display.
//      Copies the old output into new display.

        setDisplay : function (newScreen) { // function

            if (typeof newScreen === 'object') {

                newScreen.innerHTML = this.display.innerHTML;

                this.display = newScreen;
            }
        }
    }; // end view

//  These are the calculator's publicly facing methods.
//  They should be consided the controller.

//  Enter number is called when a user presses a digit, and takes that
//  digit as a param. If possible, enterNumber will pass that digit
//  to the inner calculator's update method.

    controller = {
        enterNumber : function (num) {

            if (typeof model.update === 'function') {

//              Pass response from model's update method to
//              the view
                view.output(model.update(num));
            }
        },

//      Enter operator is called when a user presses an operator,
//      and takes that operator as a param. If possible, enterOperator
//      will pass that operator to the inner calculator's
//      evaluate method.

        enterOperator : function (opp) {

            if (typeof model.evaluate === 'function') {

//              Pass response from model's evaluate method to
//              the view
                view.output(model.evaluate(opp));
            }
        },

//      Clear is called when a user presses the clear button, and
//      takes no params. If possible, clear will call the inner
//      calculator's reset method.

        clear : function () {

            if (typeof model.reset === 'function') {

//              Pass response from model's reset method to
//              the view
                view.output(model.reset());
            }
        },

//      Set Display takes an object, and set it to be the
//      Calculator's new output field.

        setDisplay : function (obj) {

            view.setDisplay(obj);
        }
    };

    return controller;

}()); // end calculator definition

// This is where the setup for the calculator happens. It's all
// inside an anonymous function, so the vars and the functions
// will go away at the end.

(function () {

    'use strict';

    var numbers,
        operators,
        i,
        k;

//  First, create click handlers for the buttons

//  function takes a number button dom element, and
//  attaches calc's enterNumber method to its click event
    function bindNum(obj) {
        obj.onclick = function () {
            calculator.enterNumber(this.value); // 'this' is obj (a num btn)
        };
    }

//  function takes a function button dom element, and
//  attaches calc's enterOperator method to its click event
    function bindOpp(obj) {
        obj.onclick = function () {
            calculator.enterOperator(this.value); // 'this' is obj (a fn btn)
        };
    }

//  Second, run setup routine, in which page elements are bound to
//  calculator methods.

//  Start by calling the calcuator's init method, passing
//  in an output element to be the display.

    /*jslint browser:true*/

    calculator.setDisplay(document.getElementById('out'));

//  Move onto binding the numbers' click
//  event to the calculator's update method.

    numbers = document.getElementsByClassName('number');

    for (i = 0; i < numbers.length; i += 1) {

//      clicking a number will update the display and
//      the temp variable

        bindNum(numbers[i]);
    }

    operators = document.getElementsByClassName('operator');

    for (k = 0; k < operators.length; k += 1) {

//      clicking an operator will make the calculator
//      perform an operation.

        bindOpp(operators[k]);

    }

//  lastly, bind the clear function to the clear buttons' click event

    document.getElementById('clear').onclick = function () {
        calculator.clear();
    };

}()); // end the anonymous init function, and invoke it
<|endoftext|>


<commit_before>$(function() {
    var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    });

    var wsUri = 'ws://busdrone.com:28737/';

    var map = L.map('map', {
        center: [47.6210, -122.3328],
        zoom: 13,
        layers: [osm]
    });

    function debug(val) {
      console.log(val);
    }

    function wsConnect() {
      debug('Connecting to ' + wsUri);
      websocket = new WebSocket(wsUri);
      websocket.onopen = function(evt) { onWsOpen(evt) };
      websocket.onmessage = function(evt) { onWsMessage(evt) };
      websocket.onerror = function(evt) { onWsError(evt) };
      websocket.onclose = function(evt) { onWsClose(evt) };
    }

    function onWsOpen(evt) {
      debug('Connected');
    }

    function onWsClose(evt) {
      debug('Disconnected');
      window.setTimeout(wsConnect, Math.random() * 1000 * 25 + 5);
    }

    function onWsMessage(evt) {
      var data = JSON.parse(evt.data);
      if (data.type == 'update_vehicle') {
      } else if (data.type == 'init') {
        data.vehicles.forEach(function(vehicle) {
            L.marker([vehicle.lat, vehicle.lon]).addTo(map);
        });
      } else if (data.type == 'remove_vehicle') {
        debug('remove');
      } else {
        debug('unknown', data)
      }
    }

    wsConnect();

    var hash = new L.Hash(map);
});
<commit_msg>Edited script.js for leaflet-getlocation<commit_after>$(function() {
    var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    });

    var wsUri = 'ws://busdrone.com:28737/';

    var map = L.map('map', {
        center: [47.6210, -122.3328],
        zoom: 13,
        layers: [osm]
    });

    L.control.locate().addTo(map);

    function debug(val) {
      console.log(val);
    }

    function wsConnect() {
      debug('Connecting to ' + wsUri);
      websocket = new WebSocket(wsUri);
      websocket.onopen = function(evt) { onWsOpen(evt) };
      websocket.onmessage = function(evt) { onWsMessage(evt) };
      websocket.onerror = function(evt) { onWsError(evt) };
      websocket.onclose = function(evt) { onWsClose(evt) };
    }

    function onWsOpen(evt) {
      debug('Connected');
    }

    function onWsClose(evt) {
      debug('Disconnected');
      window.setTimeout(wsConnect, Math.random() * 1000 * 25 + 5);
    }

    function onWsMessage(evt) {
      var data = JSON.parse(evt.data);
      if (data.type == 'update_vehicle') {
      } else if (data.type == 'init') {
        data.vehicles.forEach(function(vehicle) {
            L.marker([vehicle.lat, vehicle.lon]).addTo(map);
        });
      } else if (data.type == 'remove_vehicle') {
        debug('remove');
      } else {
        debug('unknown', data)
      }
    }

    wsConnect();

    var hash = new L.Hash(map);
});

<|endoftext|>


<commit_before>
function fixLength(minute, length = 2) {
    minute = String(minute);
    if (minute.length >= length) return minute;
    return new Array(length - minute.length + 1).join("0") + minute;
}
var days = "天一二三四五六";
function format(formater) {
    var v = getSplitedDate(this);
    var o = {};
    "yMdhmsSD".split("").forEach(function (k, i) {
        o[k] = v[i];
    });
    "年月日时分秒".split("").forEach(function (k, i) {
        o[k] = v[i];
    });

    o.Y = o.y;
    o.D = o.d;
    o.H = o.h;
    o.Day = v[v.length - 1];
    formater.replace(/[yY年]+|[M月]+|[hH时]+|毫秒|[m+分]+|[sS]{3}|[Ss秒]+|[星期周天][dD]*|[dD]{3}|[日号dD]+/g, function (m) {
        if (/^[dD]{3}$/.test(m)) {
            return o.Day;
        }
        if (/星期周天/.test(m)) {
            var v = days[o.Day]
            if (!/[天星期]/.test(m)) {
                m = m.replace(/天/g, "日");
            }
        } else {
            var a = m.charAt(0);
            var v = o[a];
        }
        var l = m.replace(/\W+/g, "");
        var b = m.split(/[\w天]+/).map(a => a || fixLength(v, l.length)).join("");
        return b;
    });
}
function filterTime(time, format) {
    var value = new Date(time);
    if (!+value) {
        return time;
    }
    if (format && !/^[\-\/]+$/.test(format)) {
        return format.call(value, format);
    }
    if (format) {
        format = format.charAt(0);
    }
    var splited = getSplitedDate(value);
    var [year, month, date, hour, minute, second, milli, day] = splited;
    var [year1, month1, date1, hour1, minute1] = getSplitedDate(new Date);
    var today = new Date(year1, month1 - 1, date1);
    var thatday = new Date(year, month - 1, date);
    var delta = (today - thatday) / 24 / 3600000;
    var time = `${hour}:${fixLength(minute)}`;
    if (delta < 6 && delta > 2) {
        return `星期` + days[day] + hour + "点";
    }
    switch (delta) {
        case 0:
            if (minute === minute1 && hour === hour1) {
                return `刚刚`;
            }
            return time;
        case 1:
            return '昨天' + hour + "点"
        case 2:
            return '前天' + hour + "点"
        default:
            switch (year1 - year) {
                case 0:
                    return `${month}${format || '月'}${date}${format ? '' : '日'} `;
                case 1:
                    if (month1 % 12 - month % 12 === 1) {
                        return `${month}${format || '月'}${date}${format ? '' : '日'} `;
                    }
                    return "去年" + month + "月";
                case 2:
                    return "前年" + month + "月";
            }
            return `${year}${format || '年'}`;
    }
}<commit_msg>增加解析字符串类型的数字<commit_after>
function fixLength(minute, length = 2) {
    minute = String(minute);
    if (minute.length >= length) return minute;
    return new Array(length - minute.length + 1).join("0") + minute;
}
var days = "天一二三四五六";
function format(formater) {
    var v = getSplitedDate(this);
    var o = {};
    "yMdhmsSD".split("").forEach(function (k, i) {
        o[k] = v[i];
    });
    "年月日时分秒".split("").forEach(function (k, i) {
        o[k] = v[i];
    });

    o.Y = o.y;
    o.D = o.d;
    o.H = o.h;
    o.Day = v[v.length - 1];
    formater.replace(/[yY年]+|[M月]+|[hH时]+|毫秒|[m+分]+|[sS]{3}|[Ss秒]+|[星期周天][dD]*|[dD]{3}|[日号dD]+/g, function (m) {
        if (/^[dD]{3}$/.test(m)) {
            return o.Day;
        }
        if (/星期周天/.test(m)) {
            var v = days[o.Day]
            if (!/[天星期]/.test(m)) {
                m = m.replace(/天/g, "日");
            }
        } else {
            var a = m.charAt(0);
            var v = o[a];
        }
        var l = m.replace(/\W+/g, "");
        var b = m.split(/[\w天]+/).map(a => a || fixLength(v, l.length)).join("");
        return b;
    });
}
function filterTime(time, format) {
    if (isFinite(time)) time = +time;
    var value = new Date(time);
    if (!+value) {
        return time;
    }
    if (format && !/^[\-\/]+$/.test(format)) {
        return format.call(value, format);
    }
    if (format) {
        format = format.charAt(0);
    }
    var splited = getSplitedDate(value);
    var [year, month, date, hour, minute, second, milli, day] = splited;
    var [year1, month1, date1, hour1, minute1] = getSplitedDate(new Date);
    var today = new Date(year1, month1 - 1, date1);
    var thatday = new Date(year, month - 1, date);
    var delta = (today - thatday) / 24 / 3600000;
    var time = `${hour}:${fixLength(minute)}`;
    if (delta < 6 && delta > 2) {
        return `星期` + days[day] + hour + "点";
    }
    switch (delta) {
        case 0:
            if (minute === minute1 && hour === hour1) {
                return `刚刚`;
            }
            return time;
        case 1:
            return '昨天' + hour + "点"
        case 2:
            return '前天' + hour + "点"
        default:
            switch (year1 - year) {
                case 0:
                    return `${month}${format || '月'}${date}${format ? '' : '日'} `;
                case 1:
                    if (month1 % 12 - month % 12 === 1) {
                        return `${month}${format || '月'}${date}${format ? '' : '日'} `;
                    }
                    return "去年" + month + "月";
                case 2:
                    return "前年" + month + "月";
            }
            return `${year}${format || '年'}`;
    }
}<|endoftext|>


<commit_before>(function () {

  if (!('indexedDB' in window)) {
    console.log('This browser doesn\'t support IndexedDB');
    return;
  }

  const idb = indexedDB.open('polar', 1, (upgradeDb) => {
    if (!upgradeDb.objectStoreNames.contains('imagesOS')) {
      const imagesOS = upgradeDb.createObjectStore('imagesOS');
      imagesOS.createIndex('image', 'image', { unique: true });
    }
  });

})();

const canvas = document.getElementById('canvas');
const point = new Point(200, 200, 180);
const clock = new PolarClock(canvas, point, 15, 2);
const menu = document.getElementById('menu');
const backgroundImageURL = document.getElementById('backgroundImageURL');
const opacity = document.getElementById('opacity');
const backgroundColor = document.getElementById('backgroundColor');
const save = document.getElementById('save');
const digitalTime = document.getElementById('digitalTime');
const positionCenter = document.getElementById('positionCenter');
const positionBottom = document.getElementById('positionBottom');
const digitalSize = document.getElementById('digitalSize');
const digitalFace = document.getElementById('digitalFace');
const digitalFont = document.getElementById('digitalFont');
const digitalOpacity = document.getElementById('digitalOpacity');
const digitalColor = document.getElementById('digitalColor');
const menuTabPolar = document.getElementById('menu-tab-polar');
const menuTabDigital = document.getElementById('menu-tab-digital');
const menuContentPolar = document.getElementById('menu-content-polar');
const menuContentDigital = document.getElementById('menu-content-digital');
const barColor = [
  document.getElementById('second'),
  document.getElementById('minute'),
  document.getElementById('hour'),
  document.getElementById('weekday'),
  document.getElementById('date'),
  document.getElementById('month'),
];
let activeTab = 'polar';

const restoreSettings = () => {
  chrome.storage.sync.get({
    barColor: ['#000', '#333', '#555', '#777', '#888', '#999'],
    backgroundImageURL: '',
    backgroundColor: '#f8f8f8',
    digitalColor: '#f8f8f8',
    opacity: 80,
    digitalOpacity: 80,
    digitalPosition: 'relative',
    digitalSize: 20,
    digitalFont: 'Roboto Mono',
  }, (res) => {
    digitalTime.style.position = res.digitalPosition;
    digitalTime.style.fontSize = `${res.digitalSize}px`;
    digitalSize.value = res.digitalSize;
    if (res.digitalFont.length > 0) {
      digitalFace.href = `https://fonts.googleapis.com/css?family=${res.digitalFont.split(' ').join('+')}`;
    }
    digitalTime.style.fontFamily = `${res.digitalFont}, monospace`;
    digitalFont.value = res.digitalFont;
    positionCenter.checked = res.digitalPosition === 'absolute';
    positionBottom.checked = res.digitalPosition === 'relative';
    opacity.value = res.opacity;
    digitalOpacity.value = res.digitalOpacity;
    digitalTime.style.opacity = res.digitalOpacity * 0.01;
    canvas.style.opacity = res.opacity * 0.01;
    backgroundColor.value = res.backgroundColor;
    digitalColor.value = res.digitalColor;
    digitalTime.style.color = res.digitalColor;
    document.body.style.backgroundColor = res.backgroundColor;
    res.barColor.forEach((color, index) => {
      clock.color[index] = color;
      barColor[index].value = color;
    });
    if (res.backgroundImageURL.length > 0) {
      backgroundImageURL.value = res.backgroundImageURL;
      document.body.style.backgroundImage = `url(${res.backgroundImageURL})`;
    }
  });
};

const saveSettings = () => {
  chrome.storage.sync.set({
    digitalPosition: positionCenter.checked ? 'absolute' : 'relative',
    digitalSize: digitalSize.value,
    digitalFont: digitalFont.value,
    backgroundImageURL: backgroundImageURL.value,
    barColor: barColor.map(element => element.value),
    backgroundColor: backgroundColor.value,
    digitalColor: digitalColor.value,
    opacity: opacity.value,
    digitalOpacity: digitalOpacity.value,
  }, () => {
    // Let user know options were saved
    save.textContent = 'Saved!';
    setTimeout(() => {
      save.textContent = 'Save Settings';
    }, 2000);
  });
  restoreSettings();
};

const updateMenuContent = () => {
  menuContentDigital.classList.toggle('hidden');
  menuContentPolar.classList.toggle('hidden');
  menuTabPolar.classList.toggle('btn-active');
  menuTabDigital.classList.toggle('btn-active');
};

const toggleMenu = () => {
  menu.classList.toggle('hidden');
};

const toggleMenuContent = (tab) => {
  if (activeTab !== tab) {
    activeTab = tab;
    updateMenuContent();
  }
};

document.body.onload = () => {
  const tick = 1000;
  const timeFormat = 'HH:mm:ss';
  clock.start(tick);
  setInterval(() => {
    digitalTime.innerHTML = moment().format(timeFormat);
  }, tick);
};

document.addEventListener('DOMContentLoaded', restoreSettings);
canvas.addEventListener('click', toggleMenu);
digitalTime.addEventListener('click', toggleMenu);
save.addEventListener('click', saveSettings);
menuTabPolar.addEventListener('click', () => toggleMenuContent('polar'));
menuTabDigital.addEventListener('click', () => toggleMenuContent('digital'));

barColor.forEach((element, index) => {
  element.addEventListener('change', () => {
    clock.color[index] = element.value;
  });
});

opacity.addEventListener('input', () => {
  canvas.style.opacity = opacity.value * 0.01;
});

digitalOpacity.addEventListener('input', () => {
  digitalTime.style.opacity = digitalOpacity.value * 0.01;
});

digitalSize.addEventListener('input', () => {
  digitalTime.style.fontSize = `${digitalSize.value}px`;
});

digitalColor.addEventListener('change', () => {
  digitalTime.style.color = digitalColor.value;
});

backgroundColor.addEventListener('change', () => {
  document.body.style.backgroundColor = backgroundColor.value;
});

backgroundImageURL.addEventListener('keyup', (e) => {
  if (e.which === 13) {
    document.body.style.backgroundImage = `url(${backgroundImageURL.value})`;
  }
});

positionCenter.addEventListener('change', () => {
  digitalTime.style.position = positionCenter.checked ? 'absolute' : 'relative';
});

positionBottom.addEventListener('change', () => {
  digitalTime.style.position = positionCenter.checked ? 'absolute' : 'relative';
});

digitalFont.addEventListener('keyup', (e) => {
  if (e.which === 13) {
    if (digitalFont.value.length > 0) {
      digitalFace.href = `https://fonts.googleapis.com/css?family=${digitalFont.value.split(' ').join('+')}`;
      digitalTime.style.fontFamily = `${digitalFont.value}, monospace`;
    } else {
      digitalTime.style.fontFamily = 'monospace';
    }
  }
});
<commit_msg>remove indexeddb for now - not needed for images, maybe later for font<commit_after>const canvas = document.getElementById('canvas');
const point = new Point(200, 200, 180);
const clock = new PolarClock(canvas, point, 15, 2);
const menu = document.getElementById('menu');
const backgroundImageURL = document.getElementById('backgroundImageURL');
const opacity = document.getElementById('opacity');
const backgroundColor = document.getElementById('backgroundColor');
const save = document.getElementById('save');
const digitalTime = document.getElementById('digitalTime');
const positionCenter = document.getElementById('positionCenter');
const positionBottom = document.getElementById('positionBottom');
const digitalSize = document.getElementById('digitalSize');
const digitalFace = document.getElementById('digitalFace');
const digitalFont = document.getElementById('digitalFont');
const digitalOpacity = document.getElementById('digitalOpacity');
const digitalColor = document.getElementById('digitalColor');
const menuTabPolar = document.getElementById('menu-tab-polar');
const menuTabDigital = document.getElementById('menu-tab-digital');
const menuContentPolar = document.getElementById('menu-content-polar');
const menuContentDigital = document.getElementById('menu-content-digital');
const barColor = [
  document.getElementById('second'),
  document.getElementById('minute'),
  document.getElementById('hour'),
  document.getElementById('weekday'),
  document.getElementById('date'),
  document.getElementById('month'),
];
let activeTab = 'polar';

const restoreSettings = () => {
  chrome.storage.sync.get({
    barColor: ['#000', '#333', '#555', '#777', '#888', '#999'],
    backgroundImageURL: '',
    backgroundColor: '#f8f8f8',
    digitalColor: '#f8f8f8',
    opacity: 80,
    digitalOpacity: 80,
    digitalPosition: 'relative',
    digitalSize: 20,
    digitalFont: 'Roboto Mono',
  }, (res) => {
    digitalTime.style.position = res.digitalPosition;
    digitalTime.style.fontSize = `${res.digitalSize}px`;
    digitalSize.value = res.digitalSize;
    if (res.digitalFont.length > 0) {
      digitalFace.href = `https://fonts.googleapis.com/css?family=${res.digitalFont.split(' ').join('+')}`;
    }
    digitalTime.style.fontFamily = `${res.digitalFont}, monospace`;
    digitalFont.value = res.digitalFont;
    positionCenter.checked = res.digitalPosition === 'absolute';
    positionBottom.checked = res.digitalPosition === 'relative';
    opacity.value = res.opacity;
    digitalOpacity.value = res.digitalOpacity;
    digitalTime.style.opacity = res.digitalOpacity * 0.01;
    canvas.style.opacity = res.opacity * 0.01;
    backgroundColor.value = res.backgroundColor;
    digitalColor.value = res.digitalColor;
    digitalTime.style.color = res.digitalColor;
    document.body.style.backgroundColor = res.backgroundColor;
    res.barColor.forEach((color, index) => {
      clock.color[index] = color;
      barColor[index].value = color;
    });
    if (res.backgroundImageURL.length > 0) {
      backgroundImageURL.value = res.backgroundImageURL;
      document.body.style.backgroundImage = `url(${res.backgroundImageURL})`;
    }
  });
};

const saveSettings = () => {
  chrome.storage.sync.set({
    digitalPosition: positionCenter.checked ? 'absolute' : 'relative',
    digitalSize: digitalSize.value,
    digitalFont: digitalFont.value,
    backgroundImageURL: backgroundImageURL.value,
    barColor: barColor.map(element => element.value),
    backgroundColor: backgroundColor.value,
    digitalColor: digitalColor.value,
    opacity: opacity.value,
    digitalOpacity: digitalOpacity.value,
  }, () => {
    // Let user know options were saved
    save.textContent = 'Saved!';
    setTimeout(() => {
      save.textContent = 'Save Settings';
    }, 2000);
  });
  restoreSettings();
};

const updateMenuContent = () => {
  menuContentDigital.classList.toggle('hidden');
  menuContentPolar.classList.toggle('hidden');
  menuTabPolar.classList.toggle('btn-active');
  menuTabDigital.classList.toggle('btn-active');
};

const toggleMenu = () => {
  menu.classList.toggle('hidden');
};

const toggleMenuContent = (tab) => {
  if (activeTab !== tab) {
    activeTab = tab;
    updateMenuContent();
  }
};

document.body.onload = () => {
  const tick = 1000;
  const timeFormat = 'HH:mm:ss';
  clock.start(tick);
  setInterval(() => {
    digitalTime.innerHTML = moment().format(timeFormat);
  }, tick);
};

document.addEventListener('DOMContentLoaded', restoreSettings);
canvas.addEventListener('click', toggleMenu);
digitalTime.addEventListener('click', toggleMenu);
save.addEventListener('click', saveSettings);
menuTabPolar.addEventListener('click', () => toggleMenuContent('polar'));
menuTabDigital.addEventListener('click', () => toggleMenuContent('digital'));

barColor.forEach((element, index) => {
  element.addEventListener('change', () => {
    clock.color[index] = element.value;
  });
});

opacity.addEventListener('input', () => {
  canvas.style.opacity = opacity.value * 0.01;
});

digitalOpacity.addEventListener('input', () => {
  digitalTime.style.opacity = digitalOpacity.value * 0.01;
});

digitalSize.addEventListener('input', () => {
  digitalTime.style.fontSize = `${digitalSize.value}px`;
});

digitalColor.addEventListener('change', () => {
  digitalTime.style.color = digitalColor.value;
});

backgroundColor.addEventListener('change', () => {
  document.body.style.backgroundColor = backgroundColor.value;
});

backgroundImageURL.addEventListener('keyup', (e) => {
  if (e.which === 13) {
    document.body.style.backgroundImage = `url(${backgroundImageURL.value})`;
  }
});

positionCenter.addEventListener('change', () => {
  digitalTime.style.position = positionCenter.checked ? 'absolute' : 'relative';
});

positionBottom.addEventListener('change', () => {
  digitalTime.style.position = positionCenter.checked ? 'absolute' : 'relative';
});

digitalFont.addEventListener('keyup', (e) => {
  if (e.which === 13) {
    if (digitalFont.value.length > 0) {
      digitalFace.href = `https://fonts.googleapis.com/css?family=${digitalFont.value.split(' ').join('+')}`;
      digitalTime.style.fontFamily = `${digitalFont.value}, monospace`;
    } else {
      digitalTime.style.fontFamily = 'monospace';
    }
  }
});
<|endoftext|>