<commit_before>define([
  'require',
  './ajax',
  './oauth',
  './session',
  './sync',
  './versioning',
  './webfinger',
  './button'
], function(require, ajax, oauth, session, sync, versioning, webfinger, button) {
  var deadLine;
  var working=false;
  var intervalTimer;
  var options = {
    onChange: function(key, oldValue, newValue) {
      console.log('item "'+key+'" changed from "'+oldValue+'" to "'+newValue+'"');
      console.log('WARNING: Please configure an onChange function! Forcing full page refresh instead');
      window.location = '';
    },
    onStatus: function(oldStatus, newStatus) {
      console.log('remoteStorage status changed from '+oldStatus+' to '+newStatus);
    },
    category: (location.protocol+'__'+location.host).replace(/\./g, '_').replace(/:/g, '_')
  };
  function onError(str) {
    alert(str);
  }
  function connect(userAddress) {
    document.getElementById('remoteStorageSpinner').style.display='inline';
    if(true) {
    //if(false) {
      connectTo(userAddress);
    } else {
      navigator.id.getVerifiedEmail(function(assertion) {
        console.log(assertion);
        ajax.ajax({
          url: 'http://myfavouritesandwich.org/browserid-verifier',
          method: 'POST',
          data: 'assertion='+assertion+'&audience='+window.location,
          success: function(data) {
            console.log(data);
            connectTo(JSON.parse(data).email);
          },
          error: function(status) {
            console.log('error status '+status);
            document.getElementById('remoteStorageSpinner').style.display='none';
          }
        });
      });
    }
  }
  function getBrowseridAccess(url, assertion, audience, cb) {
    ajax.ajax({
      url: url,
      method: 'POST',
      data: 'assertion='+encodeURIComponent(assertion)+'&audience='+audience,
      success: function(data) {
        try {
          var responseObj = JSON.parse(data);
          cb(responseObj.token);
        } catch(e) {
          console.log('something wrong with the browserid2couch token');
        }
      },
      error: function() {
        console.log('error in getBrowseridAccess call');
      }
    });
  }
  function connectTo(userAddress) {
    webfinger.getAttributes(userAddress, {
      allowHttpWebfinger: true,
      allowSingleOriginWebfinger: false,
      allowFakefinger: false
    }, onError, function(attributes) {
      var backendAddress = webfinger.resolveTemplate(attributes.template, options.category);
      if(attributes.api == 'CouchDB') {
        localStorage.setItem('_shadowBackendModuleName', 'couch');
      } else if(attributes.api == 'WebDAV') {
        localStorage.setItem('_shadowBackendModuleName', 'dav');
      } else if(attributes.api == 'simple') {
        localStorage.setItem('_shadowBackendModuleName', 'dav');
      } else {
        console.log('API "'+attributes.api+'" not supported! please try setting api="CouchDB" or "WebDAV" or "simple" in webfinger');
      }
      session.set('backendAddress', backendAddress);
      if(options.requestBrowseridAccess && options.assertion && options.audience && attributes.browseridAccess) {
        console.log('going with browserid access');
        //set backend
        var backendName = localStorage.getItem('_shadowBackendModuleName')
        if(backendName) {
          require(['./' + backendName], function(backendObj) {
            afterLoadingBackend(backendObj);
            getBrowseridAccess(attributes.browseridAccess, options.assertion, options.audience, withToken);
          });
        } else {
          console.log('we got no backend');
        }
      } else {
        oauth.go(attributes.auth, options.category, userAddress);
      }
    });
  }
  function disconnect() {
    session.disconnect();
    options.onStatus({name: 'online'}, {name: 'disconnected'});
    var isConnected = session.isConnected();
    var userAddress = session.get('userAddress');
    button.show(isConnected, userAddress);
  }
  function configure(setOptions) {
    console.log(setOptions);
    if(setOptions) {
      for(var i in setOptions) {
        options[i] = setOptions[i];
      }
      if(setOptions.userAddress) {
        connectTo(setOptions.userAddress);
      }
    }
  }
  function needLoginBox() {
    if(options.suppressDialog) {
      console.log('suppressing dialog');
      return false;
    } else {
      return true;
    }
  }
  function linkButtonToSession() {
    var isConnected = session.isConnected();
    var userAddress = session.get('userAddress');
    if(needLoginBox()) {
      button.on('connect', connect);
      button.on('disconnect', disconnect);
      button.show(isConnected, userAddress);
    }
  }
  function withToken(token) {
    session.set('token', token);
    var backendName = localStorage.getItem('_shadowBackendModuleName')
    if(backendName) {
      require(['./' + backendName], function(backendObj) {
        backendObj.init(session.get('backendAddress'), token);
        console.log('set backendObj');
      });
    } else {
      console.log('got no backend in withToken');
    }
    options.onStatus({name: 'disconnected'}, {name: 'online'});
    sync.start();
  }
  function afterLoadingBackend(backendObj) {
    if(sessionStorage.getItem('onlineEventPending')) {
      sessionStorage.removeItem('onlineEventPending');
      options.onStatus({name: 'disconnected'}, {name: 'online'});
    }
    oauth.harvestToken(withToken);
    sync.setBackend(backendObj);
    if(options.suppressAutoSave) {
      console.log('suppressing autosave');
    } else {
      trigger('timer');
      var autoSaveMilliseconds = 5000;//FIXME: move this to some sort of config
      setInterval(function() {
        trigger('timer');
      }, autoSaveMilliseconds);
    }
    document.getElementById('remoteStorageSpinner').style.display='none';
  }

  function onLoad(setOptions) {
    configure(setOptions);
    if(needLoginBox()) {
      linkButtonToSession();
    }
    var backendName = localStorage.getItem('_shadowBackendModuleName')
    if(backendName) {
      require(['./' + backendName], afterLoadingBackend);
    } else {
      console.log('no backend for sync');
      afterLoadingBackend(null);
    }
  }
  function trigger(event, cb) {
    document.getElementById('remoteStorageSpinner').style.display='inline';
    console.log(event);
    if(!working) {
      var newTimestamp = versioning.takeLocalSnapshot()
      if(newTimestamp) {
        console.log('changes detected');
        if(session.isConnected()) {
          console.log('pushing');
          sync.push(newTimestamp);
        } else {
          console.log('not connected');
        }
      }
      if(session.isConnected()) {
        working = true;
        sync.work(deadLine, function(incomingKey, incomingValue) {
          console.log('incoming value "'+incomingValue+'" for key "'+incomingKey+'".');
          var oldValue = localStorage.getItem(incomingKey);
          versioning.incomingChange(incomingKey, incomingValue);
          options.onChange(incomingKey, oldValue, incomingValue);
        }, function() {
          working = false;
          if(cb) {
            cb();
            }
        });
      } else {
        document.getElementById('remoteStorageSpinner').style.display='none';
      }
    } else {
      console.log('still working?');
    }
  }
  function getStatus() {
    if(session.isConnected()) {
      return {
        name: 'online'
      };
    } else {
      return {
        name: 'disconnected'
      };
    }
  }
  function share(key, cb) {
    var backendName = localStorage.getItem('_shadowBackendModuleName')
    if(backendName) {
      require(['./' + backendName, 'sha1'], function(backend, sha1) {
        var hash=sha1.hash(localStorage.getItem(key));
        backend.set(hash, localStorage.getItem(key), function() {
          cb('something went wrong');
        }, function() {
           cb(hash);
        }, NaN);
      });
    } else {
      console.log('no backend for sync');
      afterLoadingBackend(null);
    }
  }
  function getPublicBackend(userAddress, err, cb) {
    webfinger.getAttributes(userAddress, {
      allowHttpWebfinger: true,
      allowSingleOriginWebfinger: false,
      allowFakefinger: true
    }, err, function(attributes) {
      if(attributes.api == 'CouchDB') {
        var publicCategoryUrl = webfinger.resolveTemplate(attributes.template, 'public');
        cb({
          get: function(key, err, cb) {
            ajax.ajax({
              url: publicCategoryUrl+key,
              error: err,
              success: function(data) {
                try {
                  var obj = JSON.parse(data);
                  cb(obj.value);
                } catch(e) {
                  err(e);
                }
              }
            });
          }
        });
      } else {
        err('dont know api '+attributes.api);
      }
    });
  }
  function receive (senderAddress, hash, cb) {
    getPublicBackend(senderAddress, function() { cb('no good backend'); }, function(backend) {
      backend.get(hash, function() {
        cb('something went wrong');
      }, function(value) {
        cb(value);
      }, NaN);
    });
  }
  return {
    configure: configure,
    onLoad: onLoad,
    trigger: trigger,
    getStatus: getStatus,
    share: share,
    receive: receive
  };
});
<commit_msg>re-enabling fakeFinger<commit_after>define([
  'require',
  './ajax',
  './oauth',
  './session',
  './sync',
  './versioning',
  './webfinger',
  './button'
], function(require, ajax, oauth, session, sync, versioning, webfinger, button) {
  var deadLine;
  var working=false;
  var intervalTimer;
  var options = {
    onChange: function(key, oldValue, newValue) {
      console.log('item "'+key+'" changed from "'+oldValue+'" to "'+newValue+'"');
      console.log('WARNING: Please configure an onChange function! Forcing full page refresh instead');
      window.location = '';
    },
    onStatus: function(oldStatus, newStatus) {
      console.log('remoteStorage status changed from '+oldStatus+' to '+newStatus);
    },
    category: (location.protocol+'__'+location.host).replace(/\./g, '_').replace(/:/g, '_')
  };
  function onError(str) {
    alert(str);
  }
  function connect(userAddress) {
    document.getElementById('remoteStorageSpinner').style.display='inline';
    if(true) {
    //if(false) {
      connectTo(userAddress);
    } else {
      navigator.id.getVerifiedEmail(function(assertion) {
        console.log(assertion);
        ajax.ajax({
          url: 'http://myfavouritesandwich.org/browserid-verifier',
          method: 'POST',
          data: 'assertion='+assertion+'&audience='+window.location,
          success: function(data) {
            console.log(data);
            connectTo(JSON.parse(data).email);
          },
          error: function(status) {
            console.log('error status '+status);
            document.getElementById('remoteStorageSpinner').style.display='none';
          }
        });
      });
    }
  }
  function getBrowseridAccess(url, assertion, audience, cb) {
    ajax.ajax({
      url: url,
      method: 'POST',
      data: 'assertion='+encodeURIComponent(assertion)+'&audience='+audience,
      success: function(data) {
        try {
          var responseObj = JSON.parse(data);
          cb(responseObj.token);
        } catch(e) {
          console.log('something wrong with the browserid2couch token');
        }
      },
      error: function() {
        console.log('error in getBrowseridAccess call');
      }
    });
  }
  function connectTo(userAddress) {
    webfinger.getAttributes(userAddress, {
      allowHttpWebfinger: true,
      allowSingleOriginWebfinger: false,
      allowFakefinger: true
    }, onError, function(attributes) {
      var backendAddress = webfinger.resolveTemplate(attributes.template, options.category);
      if(attributes.api == 'CouchDB') {
        localStorage.setItem('_shadowBackendModuleName', 'couch');
      } else if(attributes.api == 'WebDAV') {
        localStorage.setItem('_shadowBackendModuleName', 'dav');
      } else if(attributes.api == 'simple') {
        localStorage.setItem('_shadowBackendModuleName', 'dav');
      } else {
        console.log('API "'+attributes.api+'" not supported! please try setting api="CouchDB" or "WebDAV" or "simple" in webfinger');
      }
      session.set('backendAddress', backendAddress);
      if(options.requestBrowseridAccess && options.assertion && options.audience && attributes.browseridAccess) {
        console.log('going with browserid access');
        //set backend
        var backendName = localStorage.getItem('_shadowBackendModuleName')
        if(backendName) {
          require(['./' + backendName], function(backendObj) {
            afterLoadingBackend(backendObj);
            getBrowseridAccess(attributes.browseridAccess, options.assertion, options.audience, withToken);
          });
        } else {
          console.log('we got no backend');
        }
      } else {
        oauth.go(attributes.auth, options.category, userAddress);
      }
    });
  }
  function disconnect() {
    session.disconnect();
    options.onStatus({name: 'online'}, {name: 'disconnected'});
    var isConnected = session.isConnected();
    var userAddress = session.get('userAddress');
    button.show(isConnected, userAddress);
  }
  function configure(setOptions) {
    console.log(setOptions);
    if(setOptions) {
      for(var i in setOptions) {
        options[i] = setOptions[i];
      }
      if(setOptions.userAddress) {
        connectTo(setOptions.userAddress);
      }
    }
  }
  function needLoginBox() {
    if(options.suppressDialog) {
      console.log('suppressing dialog');
      return false;
    } else {
      return true;
    }
  }
  function linkButtonToSession() {
    var isConnected = session.isConnected();
    var userAddress = session.get('userAddress');
    if(needLoginBox()) {
      button.on('connect', connect);
      button.on('disconnect', disconnect);
      button.show(isConnected, userAddress);
    }
  }
  function withToken(token) {
    session.set('token', token);
    var backendName = localStorage.getItem('_shadowBackendModuleName')
    if(backendName) {
      require(['./' + backendName], function(backendObj) {
        backendObj.init(session.get('backendAddress'), token);
        console.log('set backendObj');
      });
    } else {
      console.log('got no backend in withToken');
    }
    options.onStatus({name: 'disconnected'}, {name: 'online'});
    sync.start();
  }
  function afterLoadingBackend(backendObj) {
    if(sessionStorage.getItem('onlineEventPending')) {
      sessionStorage.removeItem('onlineEventPending');
      options.onStatus({name: 'disconnected'}, {name: 'online'});
    }
    oauth.harvestToken(withToken);
    sync.setBackend(backendObj);
    if(options.suppressAutoSave) {
      console.log('suppressing autosave');
    } else {
      trigger('timer');
      var autoSaveMilliseconds = 5000;//FIXME: move this to some sort of config
      setInterval(function() {
        trigger('timer');
      }, autoSaveMilliseconds);
    }
    document.getElementById('remoteStorageSpinner').style.display='none';
  }

  function onLoad(setOptions) {
    configure(setOptions);
    if(needLoginBox()) {
      linkButtonToSession();
    }
    var backendName = localStorage.getItem('_shadowBackendModuleName')
    if(backendName) {
      require(['./' + backendName], afterLoadingBackend);
    } else {
      console.log('no backend for sync');
      afterLoadingBackend(null);
    }
  }
  function trigger(event, cb) {
    document.getElementById('remoteStorageSpinner').style.display='inline';
    console.log(event);
    if(!working) {
      var newTimestamp = versioning.takeLocalSnapshot()
      if(newTimestamp) {
        console.log('changes detected');
        if(session.isConnected()) {
          console.log('pushing');
          sync.push(newTimestamp);
        } else {
          console.log('not connected');
        }
      }
      if(session.isConnected()) {
        working = true;
        sync.work(deadLine, function(incomingKey, incomingValue) {
          console.log('incoming value "'+incomingValue+'" for key "'+incomingKey+'".');
          var oldValue = localStorage.getItem(incomingKey);
          versioning.incomingChange(incomingKey, incomingValue);
          options.onChange(incomingKey, oldValue, incomingValue);
        }, function() {
          working = false;
          if(cb) {
            cb();
            }
        });
      } else {
        document.getElementById('remoteStorageSpinner').style.display='none';
      }
    } else {
      console.log('still working?');
    }
  }
  function getStatus() {
    if(session.isConnected()) {
      return {
        name: 'online'
      };
    } else {
      return {
        name: 'disconnected'
      };
    }
  }
  function share(key, cb) {
    var backendName = localStorage.getItem('_shadowBackendModuleName')
    if(backendName) {
      require(['./' + backendName, 'sha1'], function(backend, sha1) {
        var hash=sha1.hash(localStorage.getItem(key));
        backend.set(hash, localStorage.getItem(key), function() {
          cb('something went wrong');
        }, function() {
           cb(hash);
        }, NaN);
      });
    } else {
      console.log('no backend for sync');
      afterLoadingBackend(null);
    }
  }
  function getPublicBackend(userAddress, err, cb) {
    webfinger.getAttributes(userAddress, {
      allowHttpWebfinger: true,
      allowSingleOriginWebfinger: false,
      allowFakefinger: true
    }, err, function(attributes) {
      if(attributes.api == 'CouchDB') {
        var publicCategoryUrl = webfinger.resolveTemplate(attributes.template, 'public');
        cb({
          get: function(key, err, cb) {
            ajax.ajax({
              url: publicCategoryUrl+key,
              error: err,
              success: function(data) {
                try {
                  var obj = JSON.parse(data);
                  cb(obj.value);
                } catch(e) {
                  err(e);
                }
              }
            });
          }
        });
      } else {
        err('dont know api '+attributes.api);
      }
    });
  }
  function receive (senderAddress, hash, cb) {
    getPublicBackend(senderAddress, function() { cb('no good backend'); }, function(backend) {
      backend.get(hash, function() {
        cb('something went wrong');
      }, function(value) {
        cb(value);
      }, NaN);
    });
  }
  return {
    configure: configure,
    onLoad: onLoad,
    trigger: trigger,
    getStatus: getStatus,
    share: share,
    receive: receive
  };
});
<|endoftext|>


<commit_before>var Controller = function(shape) {
  this.elements = generateRandomElements();

  this.gameBoard = new TetrisBoard({
    tetrinimo: new Tetrinimo({
      element: this.elements.pop(),
      shape: getRandomShape()
    }),
    createNextTetrinimo: this.createNextTetrinimo.bind(this),
    showGameOver: this.showGameOver.bind(this)
  });

  this.gameView = new BrowserView({
    gameBoard: this.gameBoard,
    cycleDropBlock: this.cycleDropBlock
  });

  this.gameView.previewBoard.tetrinimo = new Tetrinimo({
    element: this.elements.pop(),
    shape: getRandomShape()
  });
  this.gameView.drawAllBoards();
  this.gameState = 'gameover';

  addEventListener('keydown', function(event) {
    if(this.gameState === 'gameover') {
      var keyPressed = KEY_CODES[event.keyCode];
      if(keyPressed == 'space') {
        event.preventDefault();
        this.startGame();
      }
    }
  }.bind(this));
}
Controller.prototype.startGame = function() {
  this.gameState = 'inProgress';
  this.gameView.animateGame();
  this.gameView.previewBoard.blit();
  this.gameView.tableBoard.showElement(this.gameBoard.tetrinimo.element);
  this.gameView.updateElementDescrip();

  this.cycleDropBlock();
};
Controller.prototype.cycleDropBlock = function (args) {
  var dropDelay = args ? FAST_DROP : DROP_DELAY;
  this.gameBoard.blit();
  if(this.gameBoard.dropInterval) {
    clearInterval(this.gameBoard.dropInterval);
  }
  this.gameBoard.dropInterval = setInterval(
    this.gameBoard.dropBlock.bind(this.gameBoard),
    dropDelay
  );
};
Controller.prototype.createNextTetrinimo = function() {
  this.gameBoard.tetrinimo = this.gameView.previewBoard.tetrinimo;
  if(this.elements.length <= 0) {
    this.elements = generateRandomElements();
  }
  this.gameView.previewBoard.tetrinimo = new Tetrinimo({
    element: this.elements.pop(),
    shape: getRandomShape()
  })
  this.gameView.previewBoard.blit();
  this.gameView.tableBoard.showElement(this.gameBoard.tetrinimo.element);
  this.gameView.updateElementDescrip();
};
Controller.prototype.showGameOver = function() {
  this.gameState = 'gameover';
  this.gameView.isPaused = true;
  this.gameBoard.clearForGameover();
};

var generateRandomElements = function() {
  var randElements = new Array;
  var orderedElements = new Array;

  for(var prop in CHEMICAL_ELEMENTS) {
    if(CHEMICAL_ELEMENTS.hasOwnProperty(prop)) {
      if(prop != 0) orderedElements.push(prop);
    }
  }

  var length = new Number(orderedElements.length);

  for(var i = 0; i < length; i++) {
    var randIndex = Math.floor(Math.random() * orderedElements.length);
    randElements.push(orderedElements[randIndex]);
    orderedElements.splice(randIndex, 1);
  }

  return randElements;
}
var getRandomShape = function() {
  var counter = 0;
  var randNum = Math.floor(Math.random() * 7);

  for(var prop in TETRINIMO_SHAPES) {
    if(TETRINIMO_SHAPES.hasOwnProperty(prop)) {
      if(counter == randNum) return TETRINIMO_SHAPES[prop];
      counter++;
    }
  }
}
<commit_msg>Update controller to start game on start button press<commit_after>var Controller = function(shape) {
  this.elements = generateRandomElements();

  this.gameBoard = new TetrisBoard({
    tetrinimo: new Tetrinimo({
      element: this.elements.pop(),
      shape: getRandomShape()
    }),
    createNextTetrinimo: this.createNextTetrinimo.bind(this),
    showGameOver: this.showGameOver.bind(this)
  });

  this.gameView = new BrowserView({
    gameBoard: this.gameBoard,
    cycleDropBlock: this.cycleDropBlock
  });

  this.gameView.previewBoard.tetrinimo = new Tetrinimo({
    element: this.elements.pop(),
    shape: getRandomShape()
  });
  this.gameView.drawAllBoards();
  this.gameState = 'gameover';

  addEventListener('keydown', function(event) {
    if(this.gameState === 'gameover') {
      var keyPressed = KEY_CODES[event.keyCode];
      if(keyPressed == 'space') {
        event.preventDefault();
        this.startGame();
      }
    }
  }.bind(this));
  addEventListener('mousedown', function(event) {
    if(event.target.nodeName == 'BUTTON' && this.gameState === 'gameover') {
      var buttonPressed = event.target.dataset.key;
      if(buttonPressed == 'space') {
        this.startGame();
      }
    }
  }.bind(this));
}
Controller.prototype.startGame = function() {
  this.gameState = 'inProgress';
  this.gameView.animateGame();
  this.gameView.previewBoard.blit();
  this.gameView.tableBoard.showElement(this.gameBoard.tetrinimo.element);
  this.gameView.updateElementDescrip();

  this.cycleDropBlock();
};
Controller.prototype.cycleDropBlock = function (args) {
  var dropDelay = args ? FAST_DROP : DROP_DELAY;
  this.gameBoard.blit();
  if(this.gameBoard.dropInterval) {
    clearInterval(this.gameBoard.dropInterval);
  }
  this.gameBoard.dropInterval = setInterval(
    this.gameBoard.dropBlock.bind(this.gameBoard),
    dropDelay
  );
};
Controller.prototype.createNextTetrinimo = function() {
  this.gameBoard.tetrinimo = this.gameView.previewBoard.tetrinimo;
  if(this.elements.length <= 0) {
    this.elements = generateRandomElements();
  }
  this.gameView.previewBoard.tetrinimo = new Tetrinimo({
    element: this.elements.pop(),
    shape: getRandomShape()
  })
  this.gameView.previewBoard.blit();
  this.gameView.tableBoard.showElement(this.gameBoard.tetrinimo.element);
  this.gameView.updateElementDescrip();
};
Controller.prototype.showGameOver = function() {
  this.gameState = 'gameover';
  this.gameView.isPaused = true;
  this.gameBoard.clearForGameover();
};

var generateRandomElements = function() {
  var randElements = new Array;
  var orderedElements = new Array;

  for(var prop in CHEMICAL_ELEMENTS) {
    if(CHEMICAL_ELEMENTS.hasOwnProperty(prop)) {
      if(prop != 0) orderedElements.push(prop);
    }
  }

  var length = new Number(orderedElements.length);

  for(var i = 0; i < length; i++) {
    var randIndex = Math.floor(Math.random() * orderedElements.length);
    randElements.push(orderedElements[randIndex]);
    orderedElements.splice(randIndex, 1);
  }

  return randElements;
}
var getRandomShape = function() {
  var counter = 0;
  var randNum = Math.floor(Math.random() * 7);

  for(var prop in TETRINIMO_SHAPES) {
    if(TETRINIMO_SHAPES.hasOwnProperty(prop)) {
      if(counter == randNum) return TETRINIMO_SHAPES[prop];
      counter++;
    }
  }
}
<|endoftext|>


<commit_before>var util = require('util');

// See also: <https://github.com/darwin/firelogger/wiki>
module.exports = function (options) {

    options = options || {};
    var levels = options.levels ||
        ['debug', 'info', 'warning', 'error', 'critical'];

    return function (req, res, mw_next) {
        var messages = [],
            orig_writeHead = res.writeHead;

        res.log = function (data) {
            var now = new Date();
            data = data || {};
            data.time = now.toTimeString();
            data.timestamp = now.getTime() * 1000;
            messages.push(data);
        };

        levels.forEach(function (level) {
            res.log[level] = function (msg, data) {
                data = data || {};
                data.level = level;
                data.message = msg;
                res.log(data);
            };
        });

        res.writeHead = function (status, headers) {

            // Wrap up the common exit point
            function wh_next() {
                res.writeHead = orig_writeHead;
                res.writeHead(status, headers);
            }

            // Patch the Vary: header to include X-FireLogger, to indicate that
            // the response changes based on its value.
            var curr_vary = (''+res.header('Vary')),
                fl_vary = 'X-FireLogger';
            if (curr_vary.indexOf(fl_vary) === -1) {
                res.header('Vary', (curr_vary) ? (curr_vary + ',' + fl_vary) :
                                                 fl_vary);
            }

            // Do nothing if there's no X-FireLogger header
            var fl_ver = req.header('X-FireLogger');
            if (!fl_ver) { return wh_next(); }

            // Do nothing, if there are no messages
            if (!messages.length) { return wh_next(); }

            var uid = parseInt(Math.random() * 1000000, 16);
            var d_lines = [];
            if ('plaintext' == fl_ver) {
                // Non-standard `X-FireLogger: plaintext` header skips the
                // base64 part and sticks each JSON-encoded log message into a
                // header. Good for debugging by curl
                d_lines = messages.map(JSON.stringify);
            } else {
                // `X-FireLogger: 1.2` is what's expected from the add-on, but
                // accept anything else.
                var d_logs = { logs: messages },
                    d_json = JSON.stringify(d_logs),
                    d_b64 = (new Buffer(d_json, 'utf-8')).toString('base64');
                d_lines = d_b64.match(/(.{1,75})/g);
            }

            for (var i=0; i<d_lines.length; i++) {
                res.header('FireLogger-' + uid + '-' + i, d_lines[i]);
            }

            wh_next();
        };

        mw_next();
    };

};
<commit_msg>Upgrade to node-firelogger to reduce the number of HTTP headers emitted<commit_after>var util = require('util');

// See also: <https://github.com/darwin/firelogger/wiki>
module.exports = function (options) {

    options = options || {};
    // HACK: Under 8k seems like an arbitrary best guess at a max
    var max_header_length = options.max_header_length || 8000;
    var levels = options.levels ||
        ['debug', 'info', 'warning', 'error', 'critical'];

    return function (req, res, mw_next) {
        var messages = [],
            orig_writeHead = res.writeHead;

        res.log = function (data) {
            var now = new Date();
            data = data || {};
            data.time = now.toTimeString();
            data.timestamp = now.getTime() * 1000;
            messages.push(data);
        };

        levels.forEach(function (level) {
            res.log[level] = function (msg, data) {
                data = data || {};
                data.level = level;
                data.message = msg;
                res.log(data);
            };
        });

        res.writeHead = function (status, headers) {

            // Wrap up the common exit point
            function wh_next() {
                res.writeHead = orig_writeHead;
                res.writeHead(status, headers);
            }

            // Patch the Vary: header to include X-FireLogger, to indicate that
            // the response changes based on its value.
            var curr_vary = (''+res.header('Vary')),
                fl_vary = 'X-FireLogger';
            if (curr_vary.indexOf(fl_vary) === -1) {
                res.header('Vary', (curr_vary) ? (curr_vary + ',' + fl_vary) :
                                                 fl_vary);
            }

            // Do nothing if there's no X-FireLogger header
            var fl_ver = req.header('X-FireLogger');
            if (!fl_ver) { return wh_next(); }

            // Do nothing, if there are no messages
            if (!messages.length) { return wh_next(); }

            var uid = parseInt(Math.random() * 1000000, 16);
            var d_lines = [];
            if ('plaintext' == fl_ver) {
                // Non-standard `X-FireLogger: plaintext` header skips the
                // base64 part and sticks each JSON-encoded log message into a
                // header. Good for debugging by curl
                d_lines = messages.map(JSON.stringify);
            } else {
                // `X-FireLogger: 1.2` is what's expected from the add-on, but
                // accept anything else.
                var d_logs = { logs: messages },
                    d_json = JSON.stringify(d_logs),
                    d_b64 = (new Buffer(d_json, 'utf-8')).toString('base64'),
                    d_re = new RegExp("(.{1," + max_header_length + "})", 'g');
                d_lines = d_b64.match(d_re)
            }

            for (var i=0; i<d_lines.length; i++) {
                res.header('FireLogger-' + uid + '-' + i, d_lines[i]);
            }

            wh_next();
        };

        mw_next();
    };

};
<|endoftext|>


<commit_before>// Base URL
dataurl = "http://sdg-data.github.io/web/data/"
//Read Goals, Targets and Indicators
var sdgs = [];
var stats = {};

files = ["goals","targets","indicators"];
files.forEach(function (f) {
  console.log("Loading "+f);
  d3.json(dataurl+f+".json", function (error, data) {
    //for (var attrname in data) { sdgs[attrname] = data[attrname]; }
    sdgs.push(data);
    if (sdgs.length==3) { data_loaded(sdgs); }
  });
});

function data_loaded(sdgs){
  console.log(sdgs);
  list_goals(sdgs);
  add_targets(sdgs);
  add_indicators(sdgs);
  update_stats(sdgs);
}

function update_stats(sdgs){
 document.getElementById("goals-num").innerHTML = sdgs[0]["goals"].length+" Goals";
 document.getElementById("targets-num").innerHTML = sdgs[1]["targets"].length+" Targets";
 document.getElementById("indicators-num").innerHTML = sdgs[2]["indicators"].length+" Indicators";
 add_stack_plot(stats);
}

function add_stack_plot(stats){
 var data = {
    labels: d3.range(1, sdgs[0]["goals"].length+1).map(function(i){return "Goal "+i}),
    datasets: [
        {
            label: "Targets",
            fillColor: "rgba(220,220,220,0.5)",
            strokeColor: "rgba(220,220,220,0.8)",
            highlightFill: "rgba(220,220,220,0.75)",
            highlightStroke: "rgba(220,220,220,1)",
            data: stats["goal_targets"]
        },
        {
            label: "Indicators",
            fillColor: "rgba(151,187,205,0.5)",
            strokeColor: "rgba(151,187,205,0.8)",
            highlightFill: "rgba(151,187,205,0.75)",
            highlightStroke: "rgba(151,187,205,1)",
            data: stats["goal_indicators"]
        }
    ]
 };
 var options = {
    scaleBeginAtZero : true,
    scaleShowGridLines : true,
    scaleGridLineColor : "rgba(0,0,0,.05)",
    scaleGridLineWidth : 1,
    scaleShowHorizontalLines: true,
    scaleShowVerticalLines: true,
    barShowStroke : true,
    barStrokeWidth : 2,
    barValueSpacing : 5,
    barDatasetSpacing : 1,

}

 var canvas = document.getElementById("barplot")
 var ctx= canvas.getContext("2d");
 Chart.defaults.global.multiTooltipTemplate = "<%= value %> <%= datasetLabel %> ";
 var myBarChart = new Chart(ctx).Bar(data, options);

}

function list_goals(sdgs){
  var sdgList = document.getElementById("sdgList");
  var goals=sdgs[0]["goals"];
  stats["goals"]=goals.length;
  for (var i in goals){
    var goal= goals[i];
    append_li(sdgList,"goal-"+goal["goal"],goal["goal"]+": "+goal["title"]);
  }
}

function append_li(hookElement,id,value){
  var newListItem = document.createElement("li");
  newListItem.setAttribute("id", id);
  var ListValue = document.createTextNode(value);
  newListItem.appendChild(ListValue);
  hookElement.appendChild(newListItem);
}

function append_row(hookElement,row){
 var table = document.getElementById(hookElement);
  var rowObject = table.insertRow(0);
  for (var i in row){
    cell = rowObject.insertCell(i);
    cell.innerHTML = row[i];
  }
}

function array_num(size,num){
  return Array.apply(null, new Array(size)).map(Number.prototype.valueOf,num);
}

function add_targets(sdgs){
  var targets=sdgs[1]["targets"];
  stats["targets"] = targets.length;
  stats["goal_targets"] = array_num(targets.length,0);
  for (var i in targets){
    var target=targets[i];
    stats["goal_targets"][target["goal"]-1]++;
    var goalLi = document.getElementById("goal-"+target["goal"]);
    var targetId="goal-"+target["goal"]+"-targets";
    if ( document.getElementById(targetId) == null) {
      var nestedOl = document.createElement("ul");
      nestedOl.setAttribute("id", targetId);
      goalLi.appendChild(nestedOl);
    }else{
      var goalLiUl = document.getElementById(targetId);
      append_li(goalLiUl,"target-"+target["id"],target["id"]+": "+target["title"]);
    }
  }
}

function add_indicators(sdgs){
  var indicators=sdgs[2]["indicators"];
  stats["indicators"] = indicators.length;
  stats["goal_indicators"] = array_num(indicators.length,0);

  for (var i in indicators){
    var indicator=indicators[i];
    stats["goal_indicators"][indicator["goal"]-1]++;
    var goalLi = document.getElementById("goal-"+indicator["goal"]);
    var indicatorsId="goal-"+indicator["goal"]+"-indicators";
    if (document.getElementById(indicatorsId) == null) {
      var responsiveTable = document.createElement("div");
      responsiveTable.setAttribute("class","table-responsive");
      var nestedTable = document.createElement("table");
      nestedTable.setAttribute("class","table table-striped table-bordered");
      var header = nestedTable.createTHead();
      var rowObject = header.insertRow(0);
      var columns=["Indicator","Leads","Available"]
      for (var i in columns ){
          var th = document.createElement('th');
          th.innerHTML = columns[i];
          rowObject.appendChild(th);
      }
      var body = nestedTable.createTBody();
      body.setAttribute("id", indicatorsId);
      goalLi.appendChild(responsiveTable).appendChild(nestedTable);
     }else{
      append_row(indicatorsId,[indicator["indicator"],indicator["leads"],indicator["available"]]);
    }
  }
}

<commit_msg>dataurl<commit_after>// Base URL
dataurl = "//"+window.location.host+"/web/data/"
//Read Goals, Targets and Indicators
var sdgs = [];
var stats = {};

files = ["goals","targets","indicators"];
files.forEach(function (f) {
  console.log("Loading "+f);
  d3.json(dataurl+f+".json", function (error, data) {
    //for (var attrname in data) { sdgs[attrname] = data[attrname]; }
    sdgs.push(data);
    if (sdgs.length==3) { data_loaded(sdgs); }
  });
});

function data_loaded(sdgs){
  console.log(sdgs);
  list_goals(sdgs);
  add_targets(sdgs);
  add_indicators(sdgs);
  update_stats(sdgs);
}

function update_stats(sdgs){
 document.getElementById("goals-num").innerHTML = sdgs[0]["goals"].length+" Goals";
 document.getElementById("targets-num").innerHTML = sdgs[1]["targets"].length+" Targets";
 document.getElementById("indicators-num").innerHTML = sdgs[2]["indicators"].length+" Indicators";
 add_stack_plot(stats);
}

function add_stack_plot(stats){
 var data = {
    labels: d3.range(1, sdgs[0]["goals"].length+1).map(function(i){return "Goal "+i}),
    datasets: [
        {
            label: "Targets",
            fillColor: "rgba(220,220,220,0.5)",
            strokeColor: "rgba(220,220,220,0.8)",
            highlightFill: "rgba(220,220,220,0.75)",
            highlightStroke: "rgba(220,220,220,1)",
            data: stats["goal_targets"]
        },
        {
            label: "Indicators",
            fillColor: "rgba(151,187,205,0.5)",
            strokeColor: "rgba(151,187,205,0.8)",
            highlightFill: "rgba(151,187,205,0.75)",
            highlightStroke: "rgba(151,187,205,1)",
            data: stats["goal_indicators"]
        }
    ]
 };
 var options = {
    scaleBeginAtZero : true,
    scaleShowGridLines : true,
    scaleGridLineColor : "rgba(0,0,0,.05)",
    scaleGridLineWidth : 1,
    scaleShowHorizontalLines: true,
    scaleShowVerticalLines: true,
    barShowStroke : true,
    barStrokeWidth : 2,
    barValueSpacing : 5,
    barDatasetSpacing : 1,

}

 var canvas = document.getElementById("barplot")
 var ctx= canvas.getContext("2d");
 Chart.defaults.global.multiTooltipTemplate = "<%= value %> <%= datasetLabel %> ";
 var myBarChart = new Chart(ctx).Bar(data, options);

}

function list_goals(sdgs){
  var sdgList = document.getElementById("sdgList");
  var goals=sdgs[0]["goals"];
  stats["goals"]=goals.length;
  for (var i in goals){
    var goal= goals[i];
    append_li(sdgList,"goal-"+goal["goal"],goal["goal"]+": "+goal["title"]);
  }
}

function append_li(hookElement,id,value){
  var newListItem = document.createElement("li");
  newListItem.setAttribute("id", id);
  var ListValue = document.createTextNode(value);
  newListItem.appendChild(ListValue);
  hookElement.appendChild(newListItem);
}

function append_row(hookElement,row){
 var table = document.getElementById(hookElement);
  var rowObject = table.insertRow(0);
  for (var i in row){
    cell = rowObject.insertCell(i);
    cell.innerHTML = row[i];
  }
}

function array_num(size,num){
  return Array.apply(null, new Array(size)).map(Number.prototype.valueOf,num);
}

function add_targets(sdgs){
  var targets=sdgs[1]["targets"];
  stats["targets"] = targets.length;
  stats["goal_targets"] = array_num(targets.length,0);
  for (var i in targets){
    var target=targets[i];
    stats["goal_targets"][target["goal"]-1]++;
    var goalLi = document.getElementById("goal-"+target["goal"]);
    var targetId="goal-"+target["goal"]+"-targets";
    if ( document.getElementById(targetId) == null) {
      var nestedOl = document.createElement("ul");
      nestedOl.setAttribute("id", targetId);
      goalLi.appendChild(nestedOl);
    }else{
      var goalLiUl = document.getElementById(targetId);
      append_li(goalLiUl,"target-"+target["id"],target["id"]+": "+target["title"]);
    }
  }
}

function add_indicators(sdgs){
  var indicators=sdgs[2]["indicators"];
  stats["indicators"] = indicators.length;
  stats["goal_indicators"] = array_num(indicators.length,0);

  for (var i in indicators){
    var indicator=indicators[i];
    stats["goal_indicators"][indicator["goal"]-1]++;
    var goalLi = document.getElementById("goal-"+indicator["goal"]);
    var indicatorsId="goal-"+indicator["goal"]+"-indicators";
    if (document.getElementById(indicatorsId) == null) {
      var responsiveTable = document.createElement("div");
      responsiveTable.setAttribute("class","table-responsive");
      var nestedTable = document.createElement("table");
      nestedTable.setAttribute("class","table table-striped table-bordered");
      var header = nestedTable.createTHead();
      var rowObject = header.insertRow(0);
      var columns=["Indicator","Leads","Available"]
      for (var i in columns ){
          var th = document.createElement('th');
          th.innerHTML = columns[i];
          rowObject.appendChild(th);
      }
      var body = nestedTable.createTBody();
      body.setAttribute("id", indicatorsId);
      goalLi.appendChild(responsiveTable).appendChild(nestedTable);
     }else{
      append_row(indicatorsId,[indicator["indicator"],indicator["leads"],indicator["available"]]);
    }
  }
}

<|endoftext|>


<commit_before>var app = angular.module("idiotic", []);
app.factory("Api", ["$http", "Item", "Scene", function($http, Item, Scene) {
    function Api(api_root, refresh_callback) {
        var api = new Object();
        api.api_url = api_root + 'api/';
        if(refresh_callback) {
            api.refresh_callback = refresh_callback;
        } else {
            api.refresh_callback = function() {};
        }

        api.items = [];

        api.get = function(endpoint) {
            return $http.get(encodeURI(api.api_url + endpoint)).then(function(resp) {
                if(resp.data.status == "success") {
                    console.log('GET', api.api_url + endpoint + ' successful');
                    return resp.data.result;
                } else {
                    console.log('GET', api.api_url + endpoint + ' FAILED')
                    throw resp.data;
                }
            });
        };
        api.post = function(endpoint, data) {
            return $http.post(encodeURI(api.api_url + endpoint), data).then(function(resp) {
                if(resp.data.status == "success") {
                    console.log('POST', api.api_url + endpoint + ' successful');
                    return resp.data.result;
                } else {
                    console.log('POST', api.api_url + endpoint + ' FAILED')
                    throw resp.data;
                }
            });
        };

        api.refresh = function() {
            console.log('Refreshing API from', api.api_url);
            // TODO: Parallelize
            return api.get('items').then(function(items_json) {
                        api.items = [];
                        angular.forEach(items_json, function(item_json) {
                            api.items.push(Item(api, item_json));
                        });
                    }).then(function() {
                    api.get('scenes').then(function(scenes_json) {
                        api.scenes = [];
                        angular.forEach(scenes_json, function(scene_json) {
                            api.scenes.push(Scene(api, scene_json));
                        });
                    })
            }).then(api.refresh_callback);
        };

        api.refresh();
        return api;
    };
    return Api;
}]);

app.factory("Item", ["$http", function($http) {
    function Item(api, itemData) {
        var item = new Object();
        item.type = itemData.type;
        item.id = itemData.id;
        item.name = itemData.name;
        item.state = itemData.state;
        item.tags = itemData.tags;
        item.enabled = itemData.enabled;
        item.api = api;

        // Construct commands from dictionary returned by API
        item.commands = [];
        for (name in itemData.commands) {
            command = itemData.commands[name];
            command['name'] = name;
            item.commands.push(command);
        }

        item.send_state = function() {
            if(item.state === undefined) {
                console.log("Item", item.id, "refusing to send undefined state");
                return;
            }
            return item.send_command("set?val=" + item.state);
        }

        item.send_command = function(command) {
            return api.get("item/" + item.id + "/command/" + command.name)
                .then(function(result) {
                    // Update our models.
                    angular.extend(item, result.item);
                });
        }

        item.enable_graph = function() {
            return item.tags.indexOf("webui.show_sparkline") >= 0;
        }

        item.disabled = function(disabled) {
            if(disabled === undefined) {
                return !item.enabled;
            } else {
                item.enabled = !disabled;
            }
        };
        item.show_disable = function() {
            return item.tags.indexOf("webui.show_disable") >= 0;
        }
        item.send_disable = function() {
          if(item.enabled) {
            return api.get("item/" + item.id + "/enable");
          } else {
            return api.get("item/" + item.id + "/disable");
          }
        }

        return item;
    };

    return Item;
}]);

app.factory("Scene", ["$http", function($http) {
    function Scene(api, sceneData) {
        var scene = new Object();
        angular.extend(scene, sceneData);
        scene.api = api;

        scene.id = scene.name.toLowerCase().replace(/ /g, '_');
        scene.state = scene.active;

        scene.send_activity = function() {
            var enterexit = scene.state ? "enter" : "exit";
            return api.get("scene/" + scene.id + "/command/" + enterexit);
        };

        return scene;
    };

    return Scene;
}]);

app.controller("idioticController", ["$scope", "$http", "Api", function($scope, $http, Api) {
    var idiotic = this;

    // Give empty array until API is loaded.
    idiotic.items = function() { return []; }
    idiotic.scenes = function() { return []; }
    idiotic.conf = new Object();

    idiotic.refresh = function() {
        // Run all refresh functions, and broadcast when complete.
        Promise.all([
                idiotic.refresh_sections()
        ]).then(function() {
                $scope.$broadcast('idioticLoaded');
            });
    }
    idiotic.refresh_sections = function () {
        var sections = [];
        for (section_index in idiotic.conf.sections) {
            var section = idiotic.conf.sections[section_index];
            // Prepare a new section object with an items() method.
            var s = new Object();
            s.include_tags = [];
            s.exclude_tags = [];
            angular.extend(s, section);

            // TODO: this is a hack and awful
            if (section.include_tags.indexOf("_scene") >= 0) {
                s.items = idiotic.scenes;
                sections.push(s);
                continue;
            }

            s.items = function() {
                var items = [];
                for (item_index in idiotic.items()) {
                    var item = idiotic.items()[item_index];
                    // For each item, check its tags against our lists. Include
                    // it only if there is at least one tag matching
                    // include_tags, and exactly zero tags matching
                    // exclude_tags.
                    var include = false;
                    for(tag_index in item.tags) {
                        var tag = item.tags[tag_index];
                        // If the tag is excluded, reject immediately.
                        if(this.exclude_tags.indexOf(tag) >= 0) {
                            include = false;
                            break;
                        }
                        // If the tag is included, mark for inclusion and
                        // continue to look for excluded tags.
                        if(this.include_tags.indexOf(tag) >= 0) {
                            include = true;
                        }
                    }
                    if(include) {
                        items.push(item);
                    }
                }
                return items;
            }

            sections.push(s);
        }

        idiotic.sections = sections;
    }

    $http.get("/webui_conf.json").then(function(resp) {
        console.log('WebUI configuration loaded');
        idiotic.conf = resp.data;

        idiotic.api = Api(idiotic.conf.api_base, idiotic.refresh);
        idiotic.items = function() { return idiotic.api.items; };
        idiotic.scenes = function() { return idiotic.api.scenes; };
    });

    $scope.slug = function(s) {
        return s.toLowerCase().replace(/ /g, '_');
    };
}]);

app.directive('scrollspy', ['$timeout', function($timeout) {
    return {
        link: function($scope, element, attrs) {
            $timeout(function() {
                $(element).scrollSpy();
            }, 0);
        }
    };
}]);
<commit_msg>Fix bug where item data does not refresh properly<commit_after>var app = angular.module("idiotic", []);
app.factory("Api", ["$http", "Item", "Scene", function($http, Item, Scene) {
    function Api(api_root, refresh_callback) {
        var api = new Object();
        api.api_url = api_root + 'api/';
        if(refresh_callback) {
            api.refresh_callback = refresh_callback;
        } else {
            api.refresh_callback = function() {};
        }

        api.items = [];

        api.get = function(endpoint) {
            return $http.get(encodeURI(api.api_url + endpoint)).then(function(resp) {
                if(resp.data.status == "success") {
                    console.log('GET', api.api_url + endpoint + ' successful');
                    return resp.data.result;
                } else {
                    console.log('GET', api.api_url + endpoint + ' FAILED')
                    throw resp.data;
                }
            });
        };
        api.post = function(endpoint, data) {
            return $http.post(encodeURI(api.api_url + endpoint), data).then(function(resp) {
                if(resp.data.status == "success") {
                    console.log('POST', api.api_url + endpoint + ' successful');
                    return resp.data.result;
                } else {
                    console.log('POST', api.api_url + endpoint + ' FAILED')
                    throw resp.data;
                }
            });
        };

        api.refresh = function() {
            console.log('Refreshing API from', api.api_url);
            // TODO: Parallelize
            return api.get('items').then(function(items_json) {
                        api.items = [];
                        angular.forEach(items_json, function(item_json) {
                            api.items.push(Item(api, item_json));
                        });
                    }).then(function() {
                    api.get('scenes').then(function(scenes_json) {
                        api.scenes = [];
                        angular.forEach(scenes_json, function(scene_json) {
                            api.scenes.push(Scene(api, scene_json));
                        });
                    })
            }).then(api.refresh_callback);
        };

        api.refresh();
        return api;
    };
    return Api;
}]);

app.factory("Item", ["$http", function($http) {
    function Item(api, itemData) {
        var item = new Object();
        item.api = api;

        item.refresh = function(data) {
            item.type = data.type;
            item.id = data.id;
            item.name = data.name;
            item.state = data.state;
            item.tags = data.tags;
            item.enabled = data.enabled;

            // Construct commands from dictionary returned by API
            item.commands = [];
            for (name in data.commands) {
                command = data.commands[name];
                command['name'] = name;
                item.commands.push(command);
            }
        };

        item.send_state = function() {
            if(item.state === undefined) {
                console.log("Item", item.id, "refusing to send undefined state");
                return;
            }
            return item.send_command("set?val=" + item.state);
        }

        item.send_command = function(command) {
            return api.get("item/" + item.id + "/command/" + command.name)
                .then(function(result) {
                    // Update our models.
                    item.refresh(result.item);
                });
        }

        item.enable_graph = function() {
            return item.tags.indexOf("webui.show_sparkline") >= 0;
        }

        item.disabled = function(disabled) {
            if(disabled === undefined) {
                return !item.enabled;
            } else {
                item.enabled = !disabled;
            }
        };
        item.show_disable = function() {
            return item.tags.indexOf("webui.show_disable") >= 0;
        }
        item.send_disable = function() {
          if(item.enabled) {
            return api.get("item/" + item.id + "/enable");
          } else {
            return api.get("item/" + item.id + "/disable");
          }
        }

        item.refresh(itemData);
        return item;
    };

    return Item;
}]);

app.factory("Scene", ["$http", function($http) {
    function Scene(api, sceneData) {
        var scene = new Object();
        angular.extend(scene, sceneData);
        scene.api = api;

        scene.id = scene.name.toLowerCase().replace(/ /g, '_');
        scene.state = scene.active;

        scene.send_activity = function() {
            var enterexit = scene.state ? "enter" : "exit";
            return api.get("scene/" + scene.id + "/command/" + enterexit);
        };

        return scene;
    };

    return Scene;
}]);

app.controller("idioticController", ["$scope", "$http", "Api", function($scope, $http, Api) {
    var idiotic = this;

    // Give empty array until API is loaded.
    idiotic.items = function() { return []; }
    idiotic.scenes = function() { return []; }
    idiotic.conf = new Object();

    idiotic.refresh = function() {
        // Run all refresh functions, and broadcast when complete.
        Promise.all([
                idiotic.refresh_sections()
        ]).then(function() {
                $scope.$broadcast('idioticLoaded');
            });
    }
    idiotic.refresh_sections = function () {
        var sections = [];
        for (section_index in idiotic.conf.sections) {
            var section = idiotic.conf.sections[section_index];
            // Prepare a new section object with an items() method.
            var s = new Object();
            s.include_tags = [];
            s.exclude_tags = [];
            angular.extend(s, section);

            // TODO: this is a hack and awful
            if (section.include_tags.indexOf("_scene") >= 0) {
                s.items = idiotic.scenes;
                sections.push(s);
                continue;
            }

            s.items = function() {
                var items = [];
                for (item_index in idiotic.items()) {
                    var item = idiotic.items()[item_index];
                    // For each item, check its tags against our lists. Include
                    // it only if there is at least one tag matching
                    // include_tags, and exactly zero tags matching
                    // exclude_tags.
                    var include = false;
                    for(tag_index in item.tags) {
                        var tag = item.tags[tag_index];
                        // If the tag is excluded, reject immediately.
                        if(this.exclude_tags.indexOf(tag) >= 0) {
                            include = false;
                            break;
                        }
                        // If the tag is included, mark for inclusion and
                        // continue to look for excluded tags.
                        if(this.include_tags.indexOf(tag) >= 0) {
                            include = true;
                        }
                    }
                    if(include) {
                        items.push(item);
                    }
                }
                return items;
            }

            sections.push(s);
        }

        idiotic.sections = sections;
    }

    $http.get("/webui_conf.json").then(function(resp) {
        console.log('WebUI configuration loaded');
        idiotic.conf = resp.data;

        idiotic.api = Api(idiotic.conf.api_base, idiotic.refresh);
        idiotic.items = function() { return idiotic.api.items; };
        idiotic.scenes = function() { return idiotic.api.scenes; };
    });

    $scope.slug = function(s) {
        return s.toLowerCase().replace(/ /g, '_');
    };
}]);

app.directive('scrollspy', ['$timeout', function($timeout) {
    return {
        link: function($scope, element, attrs) {
            $timeout(function() {
                $(element).scrollSpy();
            }, 0);
        }
    };
}]);
<|endoftext|>


<commit_before>
var timeAPI = "https://api.mocogeeks.com/apis/meetTime.json";

var hackerAPI = "https://api.mocogeeks.com/apis/hackerCount.json";

$(document).ready(function () {
  $('.tooltipped').tooltip({ delay: 50 });
  $(".button-collapse").sideNav();
  hackApi(timeAPI, function (error, data) {
    if (error) {
      document.getElementById("api-fetch").innerHTML = "Failed to fetch next meeting data.";
      console.log('Error found while trying to fetch HackAPI.', error);
    } else {
      if (Object.keys(data.beta).length != 0) {
        document.getElementById("api-time-beta").innerHTML = data.beta.time;
        document.getElementById("api-date-beta").innerHTML = data.beta.date;
        document.getElementById("api-loc-beta").innerHTML = data.beta.location;
        document.getElementById("api-des-beta").innerHTML = data.beta.detail;
      }
      else {
        document.getElementById("api-fetch-beta").innerHTML = "No meeting coming up for Beta Program!"
      }
      if (Object.keys(data.wootton).length != 0) {
        document.getElementById("api-time-wootton").innerHTML = data.wootton.time;
        document.getElementById("api-date-wootton").innerHTML = data.wootton.date;
        document.getElementById("api-loc-wootton").innerHTML = data.wootton.location;
        document.getElementById("api-des-wootton").innerHTML = data.wootton.detail;
      }
      else {
        document.getElementById("api-fetch-wootton").innerHTML = "No meeting coming up for Wootton!"
      }
      if (Object.keys(data.blair).length != 0) {
        document.getElementById("api-time-blair").innerHTML = data.blair.time;
        document.getElementById("api-date-blair").innerHTML = data.blair.date;
        document.getElementById("api-loc-blair").innerHTML = data.blair.location;
        document.getElementById("api-des-blair").innerHTML = data.blair.detail;
      }
      else {
        document.getElementById("api-fetch-blair").innerHTML = "No meeting coming up for Blair!"
      }
      document.getElementById("api-fetch-beta").style.display = "";
      document.getElementById("api-fetch-wootton").style.display = "";
      document.getElementById("api-fetch-blair").style.display = "";
    }
  });
  hackApi(hackerAPI, function (error, data) {
    if (error) {
      document.getElementById("api-fetch-hackerCount").innerHTML = "?";
      document.getElementById("api-fetch-hackerDes").innerHTML = "Mmm... There's gotta be something wrong with our data... Wanna help fixing it?";

      console.log('Error found while trying to fetch HackAPI.', error);
    } else {
      var hackerTotal = data.wootton.officer + data.wootton.hacker + data.blair.officer + data.blair.hacker;
      document.getElementById("api-fetch-hackerCount").innerHTML = hackerTotal;

    }
    document.getElementById("api-fetch-hacker").style.display = "";
  });
});

<commit_msg>Added easter egg<commit_after>
var timeAPI = "https://api.mocogeeks.com/apis/meetTime.json";

var hackerAPI = "https://api.mocogeeks.com/apis/hackerCount.json";

$(document).ready(function () {
  $('.tooltipped').tooltip({ delay: 50 });
  $(".button-collapse").sideNav();
  hackApi(timeAPI, function (error, data) {
    if (error) {
      document.getElementById("api-fetch").innerHTML = "Failed to fetch next meeting data.";
      console.log('Error found while trying to fetch HackAPI.', error);
    } else {
      if (Object.keys(data.beta).length != 0) {
        document.getElementById("api-time-beta").innerHTML = data.beta.time;
        document.getElementById("api-date-beta").innerHTML = data.beta.date;
        document.getElementById("api-loc-beta").innerHTML = data.beta.location;
        document.getElementById("api-des-beta").innerHTML = data.beta.detail;
      }
      else {
        document.getElementById("api-fetch-beta").innerHTML = "No meeting coming up for Beta Program!"
      }
      if (Object.keys(data.wootton).length != 0) {
        document.getElementById("api-time-wootton").innerHTML = data.wootton.time;
        document.getElementById("api-date-wootton").innerHTML = data.wootton.date;
        document.getElementById("api-loc-wootton").innerHTML = data.wootton.location;
        document.getElementById("api-des-wootton").innerHTML = data.wootton.detail;
      }
      else {
        document.getElementById("api-fetch-wootton").innerHTML = "No meeting coming up for Wootton!"
      }
      if (Object.keys(data.blair).length != 0) {
        document.getElementById("api-time-blair").innerHTML = data.blair.time;
        document.getElementById("api-date-blair").innerHTML = data.blair.date;
        document.getElementById("api-loc-blair").innerHTML = data.blair.location;
        document.getElementById("api-des-blair").innerHTML = data.blair.detail;
      }
      else {
        document.getElementById("api-fetch-blair").innerHTML = "No meeting coming up for Blair!"
      }
      document.getElementById("api-fetch-beta").style.display = "";
      document.getElementById("api-fetch-wootton").style.display = "";
      document.getElementById("api-fetch-blair").style.display = "";
    }
  });
  hackApi(hackerAPI, function (error, data) {
    if (error) {
      document.getElementById("api-fetch-hackerCount").innerHTML = "?";
      document.getElementById("api-fetch-hackerDes").innerHTML = "Mmm... There's gotta be something wrong with our data... Wanna help fixing it?";

      console.log('Error found while trying to fetch HackAPI.', error);
    } else {
      var hackerTotal = data.wootton.officer + data.wootton.hacker + data.blair.officer + data.blair.hacker;
      document.getElementById("api-fetch-hackerCount").innerHTML = hackerTotal;

    }
    document.getElementById("api-fetch-hacker").style.display = "";
  });
});

console.log('%cHEY PEOPLE ', 'color: #ff0000');
console.log('%cIF YOU ARE READING THIS... ', 'color: #ff7F00');
console.log('%cYOU ARE DEFINITELY ENCOURAGED TO JOIN HACK CLUB ', 'color: #ffBB11');
console.log('%cYOU MAY WANT TO SAY... WHY? I JUST CLICKED IN BY ACCIDENT ', 'color: #55AA00');
console.log('%cNO. IT\'S THE CURIOSITY URGING YOU TO CLICK THAT BUTTON', 'color: #4B0082');
console.log('%cTHAT\'S WHAT WE\'RE LOOKING FOR ', 'color: #8F00FF');
console.log('');
console.log('%cYOUR CHOICE :-) ', 'color: #000000');
console.log('%cTO JOIN: Call function \"join()\"', 'color: #000000');
console.log('%cTO GIVE UP: Simply close this panel', 'color: #000000');

function join() {
  console.clear();
  console.log('%cYAAAAAAYYYYYYYYYY! ', 'color: #ff0000');
  console.log('%cYou are special. Don\'t use the application form - that\'s for noobs.  ', 'color: #ff0000');
  console.log('%cI mean... You probably can, here\'s the link: https://mocogeeks.com/apply.html', 'color: #ff0000');
  console.log('%cBut to make yourself special, send an email directly to jiang@mingjie.info', 'color: #8F00FF');
  console.log('%cWith the subject \"Mr. Rainbow\" and attach your information/resume', 'color: #8F00FF');
  console.log('')
  console.log('%cLOOKING FORWARD TO UR EMAIL!', 'color: #8F00FF');
  console.log('Written by Mingjie, Hack Club MD President');
}<|endoftext|>


<commit_before>function do_command(item, command, val) {
    var data = {};
    data[item] = command;

    if (val != undefined) {
	data["value"] = val;
    }
    $.get("/CMD", data);
}

function do_scene(scene, action) {
    $.get("/api/scene/" + scene + "/command/" + (action?action:""));
}

$(function() {
    $(".command").each(function() {
	var elm = $(this);
	elm.on(elm.data("event"), function() {
	    if (elm.data("use-val") == "true") {
		do_command(elm.data("item"), elm.data("command"), elm.val());
	    } else {
		do_command(elm.data("item"), elm.data("command"));
	    }
	});
    });

    $(".scene-control").each(function() {
	var elm = $(this);
	elm.click(function(evt) {
	    do_scene(elm.data("scene"), elm.data("action"));
	});
    });
});
<commit_msg>Update javascript to use native API<commit_after>function do_command(item, command, val) {
    var data = {};

    if (val != undefined) {
	data["val"] = val;
    }
    $.get("/api/item/" + item + "/command/" + command, data);
}

function do_scene(scene, action) {
    $.get("/api/scene/" + scene + "/command/" + (action?action:""));
}

$(function() {
    $(".command").each(function() {
	var elm = $(this);
	elm.on(elm.data("event"), function() {
	    if (elm.data("use-val")) {
		do_command(elm.data("item"), elm.data("command"), elm.val());
	    } else {
		do_command(elm.data("item"), elm.data("command"));
	    }
	});
    });

    $(".scene-control").each(function() {
	var elm = $(this);
	elm.click(function(evt) {
	    do_scene(elm.data("scene"), elm.data("action"));
	});
    });
});
<|endoftext|>


<commit_before>function initTable() {
  $('.table-container').load('./assets/paste.html', function() {
    // Tweak some of the pasted html from https://darkestdungeon.gamepedia.com/Party_Combos
    $(this).find('table').css('width', 'auto');
    $(this).find('table a img').unwrap().each(function(index, img) {
      var $img = $(img);
      var cls = $img.attr('alt').replace(' portrait roster.png', '').toLowerCase();
      $img.attr('alt', cls).attr('src', 'assets/images/' + cls + '.png');
    });
  });
}

function initFilters() {
  $('.filters select').on('change', function() {
    updateRows();
  });
}

function updateRows() {
  var includeClasses = $('.filters select').map(function() {
    var v = $(this).val();
    if (v !== 'Select') return v.toLowerCase();
  }).toArray();
  $('.table-container tr').slice(1).each(function(index, row) {
    var rowClasses = $(row).find('img').map(function() { return $(this).attr('alt'); }).toArray();
    $(row).toggle(includeClasses.every(function(cls) {
      var rowClassIndex = rowClasses.indexOf(cls);
      if (rowClassIndex > -1) rowClasses.splice(rowClassIndex, 1);
      return rowClassIndex > -1;
    }));
  });
  var count = $('.table-container tr:visible').slice(1).length;
  $('.filters .results').text(count + (count === 1 ? ' result' : ' results'));
}

$(function() {
  initTable();
  initFilters();
});
<commit_msg>Fix for houndmaster naming inconsistency<commit_after>function initTable() {
  $('.table-container').load('./assets/paste.html', function() {
    // Tweak some of the pasted html from https://darkestdungeon.gamepedia.com/Party_Combos
    $(this).find('table').css('width', 'auto');
    $(this).find('table a img').unwrap().each(function(index, img) {
      var $img = $(img);
      var cls = $img.attr('alt').replace(' portrait roster.png', '').toLowerCase();
      // Fix naming consistency for houndmaster
      cls = cls === 'hound master' ? 'houndmaster' : cls;
      $img.attr('alt', cls).attr('src', 'assets/images/' + cls + '.png');
    });
  });
}

function initFilters() {
  $('.filters select').on('change', function() {
    updateRows();
  });
}

function updateRows() {
  var includeClasses = $('.filters select').map(function() {
    var v = $(this).val();
    if (v !== 'Select') return v.toLowerCase();
  }).toArray();
  $('.table-container tr').slice(1).each(function(index, row) {
    var rowClasses = $(row).find('img').map(function() { return $(this).attr('alt'); }).toArray();
    $(row).toggle(includeClasses.every(function(cls) {
      var rowClassIndex = rowClasses.indexOf(cls);
      if (rowClassIndex > -1) rowClasses.splice(rowClassIndex, 1);
      return rowClassIndex > -1;
    }));
  });
  var count = $('.table-container tr:visible').slice(1).length;
  $('.filters .results').text(count + (count === 1 ? ' result' : ' results'));
}

$(function() {
  initTable();
  initFilters();
});
<|endoftext|>


<commit_before>$(function() {

	'use strict';

	var

		client = ZAFClient.init(),

		attachments = [],

		path = "ticket.comments",

		$download = $('#download'),
		$list = $('#list'),
		$message = $('#message'),
		$status = $('#status'),
		$progress = $('#progress'),

		findAttachments = function() {
			return client.get(path).then(function(response) {
				var allComments = response[path];
				attachments = $.map($.makeArray(allComments), function(comment) {
					return [].concat(comment.imageAttachments).concat(comment.nonImageAttachments);
				});
				return new Promise(function(resolve, reject) {
					if (!$.isArray(attachments) || attachments.length === 0) {
						reject("No attachments found in this ticket.");
					} else {
						resolve();
					}
				});
			});
		},

		displayAttachments = function() {
			var html = $.map(attachments, function(attachment) {
				return (
					"
" +
					""+attachment.filename+"" +
					"
"
				)
			});
			$list.
				append(html).
				toggle()
			;
			message("" + attachments.length + " attachment" + (attachments.length == 1 ? "" : "s") + " found in this ticket.");
		},

		makeZip = function() {
			var zip = new JSZip();
			$.each(attachments, function(index, attachment) {
				zip.file(
					attachment.filename,
					urlToPromise(attachment.contentUrl),
					{
						binary:true
					}
				);
			});
			return zip;
		},

		downloadAttachments = function() {
			var first = true;
			return makeZip()
			.generateAsync({type:"blob"}, function updateCallback(metadata) {

				if (first) {
					$progress.show();
					first = false;
				}

				var percent = metadata.percent;
				$progress.percent = percent;
				status("Making ZIP: " + percent.toFixed(2) + "%");
			})
			.then(function (blob) {
				client.context().then(function(context) {
					var filename = "Zendesk-";
					filename += context.ticketId;
					filename += "-attachments-";
					filename += new Date().getTime();
					filename += ".zip";
					saveAs(blob, filename);
				})
			});
		},

		message = function(message) {
			display($message, message);
		},

		status = function(message) {
			display($status, message);
		},

		display = function($element, message) {
			$element.html(message);
		},

		show = function($element) {
			$element.show(600);
		},

		hide = function($element) {
			$element.hide(600);
		}
	;

	/**
	* Set the width of the colored part of the progress bar.
	*/
	Object.defineProperty($progress, "percent", {
		set: function(percent) {
			this
			.find("#progress-bar")
			.attr('aria-valuenow', percent)
			.width(percent+"%");
		}
	});

	// EVENT HANDLERS //

	client.on('app.registered', function appRegistered(event) {
		$progress.hide();
		findAttachments()
		.then(function() {
			attachments.sort(function(a,b) {
				return a.filename > b.filename ? 1 : a.filename < b.filename ? -1 : 0;
			});
			displayAttachments();
			$download.show();
		})
		.catch(function(err) {
			message(err);
			$download.hide();
		})
		.then(function() {
			$('#container').show();
		});
	});

	client.on('ticket.comments.changed', function(event) {
		console.log(event);
	});

	$download.on("click", function() {
		hide($message);
		$download.hide();
		show($status);
		status("Fetching attachments...");
		downloadAttachments().
		then(function() {
			status("ZIP done!");
			setTimeout(function() {
				hide($status);
				hide($progress);
				$progress.percent = 0;
				show($message);
				show($download);
			}, 2000);
		});
	});

	$message.on("click", function() {
		$list.slideToggle();
	});

	/**
	 * Fetch the content and return the associated promise.
	 * @param {String} url the url of the content to fetch.
	 * @return {Promise} the promise containing the data.
	 */
	function urlToPromise(url) {
		return new Promise(function(resolve, reject) {
			JSZipUtils.getBinaryContent(url, function (err, data) {
				if(err) {
					reject(err);
				} else {
					resolve(data);
				}
			});
		});
	}

});

<commit_msg>Move function declarations below event handler registration<commit_after>$(function() {

	'use strict';

	var

		client = ZAFClient.init(),

		attachments = [],

		comment_path = "ticket.comments"

		$download = $('#download'),
		$list = $('#list'),
		$message = $('#message'),
		$status = $('#status'),
		$progress = $('#progress')

	;

	client.on('app.registered', function appRegistered(event) {
		$progress.hide();
		findAttachments()
		.then(function() {
			attachments.sort(function(a,b) {
				return a.filename > b.filename ? 1 : a.filename < b.filename ? -1 : 0;
			});
			displayAttachments();
			$download.show();
		})
		.catch(function(err) {
			message(err);
			$download.hide();
		})
		.then(function() {
			$('#container').show();
		});
	});

	client.on('ticket.comments.changed', function(event) {
		console.log(event);
	});

	$download.on("click", function() {
		hide($message);
		$download.hide();
		show($status);
		status("Fetching attachments...");
		downloadAttachments().
		then(function() {
			status("ZIP done!");
			setTimeout(function() {
				hide($status);
				hide($progress);
				$progress.percent = 0;
				show($message);
				show($download);
			}, 2000);
		});
	});

	$message.on("click", function() {
		$list.slideToggle();
	});

	function findAttachments() {
		return client.get(comment_path).then(function(response) {
			var allComments = response[comment_path];
			attachments = $.map($.makeArray(allComments), function(comment) {
				return [].concat(comment.imageAttachments).concat(comment.nonImageAttachments);
			});
			return new Promise(function(resolve, reject) {
				if (!$.isArray(attachments) || attachments.length === 0) {
					reject("No attachments found in this ticket.");
				} else {
					resolve();
				}
			});
		});
	}

	function displayAttachments() {
		var html = $.map(attachments, function(attachment) {
			return (
				"
" +
				""+attachment.filename+"" +
				"
"
			)
		});
		$list.
			append(html).
			toggle()
		;
		message("" + attachments.length + " attachment" + (attachments.length == 1 ? "" : "s") + " found in this ticket.");
	}

	function makeZip() {
		var zip = new JSZip();
		$.each(attachments, function(index, attachment) {
			zip.file(
				attachment.filename,
				urlToPromise(attachment.contentUrl),
				{
					binary:true
				}
			);
		});
		return zip;
	},

	function downloadAttachments() {
		var first = true;
		return makeZip()
		.generateAsync({type:"blob"}, function updateCallback(metadata) {

			if (first) {
				$progress.show();
				first = false;
			}

			var percent = metadata.percent;
			$progress.percent = percent;
			status("Making ZIP: " + percent.toFixed(2) + "%");
		})
		.then(function (blob) {
			client.context().then(function(context) {
				var filename = "Zendesk-";
				filename += context.ticketId;
				filename += "-attachments-";
				filename += new Date().getTime();
				filename += ".zip";
				saveAs(blob, filename);
			})
		});
	}

	function message(message) {
		display($message, message);
	}

	function status(message) {
		display($status, message);
	}

	function display($element, message) {
		$element.html(message);
	}

	function show($element) {
		$element.show(600);
	}

	function hide($element) {
		$element.hide(600);
	}

	/**
	* Set the width of the colored part of the progress bar.
	*/
	Object.defineProperty($progress, "percent", {
		set: function(percent) {
			this
			.find("#progress-bar")
			.attr('aria-valuenow', percent)
			.width(percent+"%");
		}
	});

	/**
	 * Fetch the content and return the associated promise.
	 * @param {String} url the url of the content to fetch.
	 * @return {Promise} the promise containing the data.
	 */
	function urlToPromise(url) {
		return new Promise(function(resolve, reject) {
			JSZipUtils.getBinaryContent(url, function (err, data) {
				if(err) {
					reject(err);
				} else {
					resolve(data);
				}
			});
		});
	}

});

<|endoftext|>


<commit_before><commit_msg>Correct mistranslated reference to super in Results fetch call<commit_after><|endoftext|>