<commit_before>function Actuator (board) {
  this.board = board;

  this.markup = {
    board: document.getElementById('board')
  };

  this.bindEvents();
};

Actuator.prototype.bindEvents = function () {
  window.addEventListener('draw', function () {
    this.markup.board.classList.add('message', 'draw');
  }.bind(this));

  window.addEventListener('loss', function () {
    this.markup.board.classList.add('message', 'loss');
  }.bind(this));
};

Actuator.prototype.render = function () {
  this.sync();
  this.adjustSpacing();
};

Actuator.prototype.sync = function () {
  [].map.call(this.board.markup.cells, function (element, index) {
    if (this.board.isOccupied(index)) {
      element.classList.add('occupied', this.board.getCell(index));
      element.textContent = this.board.getCell(index);
    }
  }.bind(this));
};

Actuator.prototype.adjustSpacing = function () {
  [].map.call(this.board.markup.cells, function (element) {
    element.style.height = element.scrollWidth + 'px';
  });
};

Actuator.prototype.reset = function () {
  this.clearMessage();
  this.clearCells();
};

Actuator.prototype.clearMessage = function () {
  this.markup.board.classList.remove('message', 'loss', 'draw');
};

Actuator.prototype.clearCells = function () {
  [].map.call(this.board.markup.cells, function (element) {
    element.classList.remove('occupied', 'x', 'o');
    element.textContent = null;
  });
};
<commit_msg>Rename Actuator.sync() to updateCells<commit_after>function Actuator (board) {
  this.board = board;

  this.markup = {
    board: document.getElementById('board')
  };

  this.bindEvents();
};

Actuator.prototype.bindEvents = function () {
  window.addEventListener('draw', function () {
    this.markup.board.classList.add('message', 'draw');
  }.bind(this));

  window.addEventListener('loss', function () {
    this.markup.board.classList.add('message', 'loss');
  }.bind(this));
};

Actuator.prototype.render = function () {
  this.updateCells();
  this.adjustSpacing();
};

Actuator.prototype.updateCells = function () {
  [].map.call(this.board.markup.cells, function (element, index) {
    if (this.board.isOccupied(index)) {
      element.classList.add('occupied', this.board.getCell(index));
      element.textContent = this.board.getCell(index);
    }
  }.bind(this));
};

Actuator.prototype.adjustSpacing = function () {
  [].map.call(this.board.markup.cells, function (element) {
    element.style.height = element.scrollWidth + 'px';
  });
};

Actuator.prototype.reset = function () {
  this.clearMessage();
  this.clearCells();
};

Actuator.prototype.clearMessage = function () {
  this.markup.board.classList.remove('message', 'loss', 'draw');
};

Actuator.prototype.clearCells = function () {
  [].map.call(this.board.markup.cells, function (element) {
    element.classList.remove('occupied', 'x', 'o');
    element.textContent = null;
  });
};
<|endoftext|>


<commit_before>/*globals _,window,exports*/
/*exported createBrowser*/

var BrowserInstance;

function createBrowser() {
  'use strict';

  if (BrowserInstance) {
    return BrowserInstance;
  }

  var homeUrl;
  var webviewDomainLimit;
  var webview;
  var webviewLoaded = false;

  function BrowserControls() {
    this._callbacks = [];

    this.isHome = false;
    this.isBack = false;
    this.isForward = false;
    this.isTop = false;
    this.isReload = false;

    this.scrollTopCan = false;
    window.addEventListener('message', function onMessage() {
      if (event && event.data && event.data.command && event.data.command === 'scroll') {
        if (event.data.value > 100) {
          this.scrollTopCan = true;
        } else {
          this.scrollTopCan = false;
        }

        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('scroll', this);
          }, this);
        }
      }
    }.bind(this));
  }

  BrowserControls.prototype.addChangeCallback = function addChangeCallback(callback) {
    if (typeof callback === 'function') {
      this._callbacks.push(callback);
    }
  };

  BrowserControls.prototype.canBack = function canGoBack() {
    if (webview) {
      this.isBack = webview.canGoBack();
    } else {
      this.isBack = false;
    }

    return this.isBack;
  };

  BrowserControls.prototype.back = function goBack() {
    if (!this.canBack()) {
      return;
    }
    webview.back();
  };

  BrowserControls.prototype.canForward = function canGoForward() {
    if (webview) {
      this.isForward = webview.canGoForward();
    } else {
      this.isForward = false;
    }

    return this.isForward;
  };

  BrowserControls.prototype.forward = function goForward() {
    if (!this.canForward()) {
      return;
    }
    webview.forward();
  };

  BrowserControls.prototype.canReload = function canReloadPage() {
    if (webview) {
      this.isReload = true;
    } else {
      this.isReload = false;
    }
    return this.isReload;
  };

  BrowserControls.prototype.reload = function reloadPage() {
    if (!this.canReload()) {
      return;
    }
    webview.reload();
  };

  BrowserControls.prototype.canHome = function canGoHome() {
    if (webview) {
      this.isHome = webview.src !== homeUrl;
    } else {
      this.isHome = false;
    }
    return this.isHome;
  };

  BrowserControls.prototype.home = function goHome() {
    if (!webview) {
      return;
    }
    webview.src = homeUrl;
  };

  BrowserControls.prototype.go = function goToPage(page) {
    if (!webview) {
      return;
    }
    webview.src = page;
  };

  BrowserControls.prototype.clearData = function clearData(callback) {
    if (!webview) {
      if (callback) {
        callback(false);
      }
      return;
    }
    webview.clearData({}, {
      'appcache': true,
      'cookies': true
    }, function clearDataDone() {
      this.home();
      if (callback) {
        callback(true);
      }
    }.bind(this));
  };

  BrowserControls.prototype.canTop = function canGoTop() {
    if (webview) {
      this.isTop = webviewLoaded && this.scrollTopCan;
    } else {
      this.isTop = false;
    }
    return this.isTop;
  };

  BrowserControls.prototype.top = function goTop() {
    if (!webview) {
      return;
    }
    if (!webviewLoaded) {
      return;
    }
    webview.contentWindow.postMessage({
      command: 'scrollTop'
    }, '*');
  };

  BrowserControls.prototype.check = function () {
    this.canReload();
    this.canHome();
    this.canTop();
    this.canBack();
    this.canForward();
  };

  function Browser() {
    this._callbacks = [];
    this._downloadFrom = '';
    this._allowNewWindows = false;
    this.controls = new BrowserControls();
  }

  Browser.prototype.exec = function exec(v) {
    if (!webview) {
      return;
    }
    if (!webviewLoaded) {
      return;
    }
    webview.focus();
    webview.contentWindow.postMessage({
      command: 'execute',
      value: v
    }, '*');
  };

  Browser.prototype.getControls = function getControls() {
    return this.controls;
  };

  Browser.prototype.allowNewWindows = function allowNewWindows(b) {
    this._allowNewWindows = b;
  };

  Browser.prototype.allowDownloadFrom = function allowDownloadFrom(d) {
    this._downloadFrom = d;
  };

  Browser.prototype.clearWebview = function clearWebview() {
    webview = undefined;
  };

  Browser.prototype.bindWebview = function bindWebview(selecter, partition, userAgent) {
    if (webview) {
      throw new Error('Browser is already bound to Webview!');
    }
    webview = window.document.querySelector(selecter);
    if (!webview) {
      throw new Error('Invalid selector or webview not found!');
    }

    //set where to save cookie and other data
    if (partition) {
      webview.partition = partition;
    }

    //useragent
    if (userAgent) {
      webview.setUserAgentOverride(webview.getUserAgent() + ' ' + userAgent);
    }

    //disable zoom
    webview.setZoomMode('disabled');

    //inject
    webview.addContentScripts([{
      name: 'rule',
      matches: ['http://*/*', 'https://*/*'],
      js: {
        files: ['scripts/inject.js']
      },
      css: {
        files: ['styles/inject.css']
      },
      'run_at': 'document_start'
    }]);

    //on close
    webview.addEventListener('close', function onCloseWebview(e) {
      webview.src = 'about:blank';
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('close', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('loadstart', function onStartWebview(e) {
      if (e.isTopLevel && webviewDomainLimit && (e.url.search(webviewDomainLimit) === -1 && e.url !== 'about:blank' && e.url !== 'data:text/html,chromewebdata')) {
        webview.stop();
        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('loadstart', new Error(e.url), e, this);
          }, this);
        }
        return;
      }

      webviewLoaded = false;
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('loadstart', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('loadstop', function onStopWebview(e) {
      webviewLoaded = true;
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('loadstop', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('loadabort', function onAbortWebview(e) {
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('loadabort', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('contentload', function onLoadWebview(e) {
      //shake hands to send this app id to web
      var handshake = function handshake(event) {
        if (event && event.data && event.data.command && event.data.command === 'handshakereply') {
          if (event.data.url) {
            if (this._callbacks.length > 0) {
              _.each(this._callbacks, function (v) {
                v('handshake', null, event, this);
              }, this);
            }
          }
          window.removeEventListener('message', handshake);
        }
      }.bind(this);
      window.addEventListener('message', handshake);
      webview.contentWindow.postMessage({
        command: 'handshake'
      }, '*');

      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('contentload', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('newwindow', function onNewWindowWebview(e) {
      if (this._allowNewWindows) {
        e.preventDefault();
        window.open(e.targetUrl); //open in chrome
        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('newwindow', null, e, this);
          }, this);
        }
      } else {
        e.window.discard();
        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('newwindow', new Error(e.targetUrl), e, this);
          }, this);
        }
      }
    }.bind(this));

    webview.addEventListener('permissionrequest', function onPermissionWebview(e) {
      if (e.permission === 'download' && this._downloadFrom && e.request.url.search(this._downloadFrom) !== -1) {
        e.request.allow();
      }
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('permissionrequest', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('dialog', function onDialogWebview(e) {
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('dialog', null, e, this);
        }, this);
      }
    }.bind(this));

    // force webview focus from app body
    setInterval(function keepWebviewFocus() {
      if (webview && webviewLoaded) {
        if (window.document.activeElement !== webview && window.document.activeElement.tagName !== 'INPUT' && window.document.activeElement.tagName !== 'TEXTAREA') {
          webview.focus();
        }
      }
    }, 1000);
  };

  Browser.prototype.setHome = function setHome(url) {
    homeUrl = url;
  };
  Browser.prototype.setDomainLimit = function setDomainLimit(reg) {
    webviewDomainLimit = reg;
  };

  Browser.prototype.getUrl = function getUrl() {
    return webview.src;
  };

  Browser.prototype.addChangeCallback = function addChangeCallback(callback) {
    if (typeof callback === 'function') {
      this._callbacks.push(callback);
    }
  };

  Browser.prototype.start = function startBrowser(callback) {
    if (!webview) {
      throw new Error('Use \'bindWebview\' to set webview selector first!');
    }
    if (!homeUrl) {
      throw new Error('Use \'setHome\' to set home page first!');
    }

    var done = function done() {
      if (webview.src === 'about:blank' || webview.src === '') {
        webview.src = homeUrl;
      }
    };

    if (callback) {
      callback(webview, done);
    } else {
      done();
    }
  };

  BrowserInstance = new Browser();
  return BrowserInstance;
}

if (typeof exports !== 'undefined') {
  exports.browser = createBrowser();
}
<commit_msg>retry shaker on fail<commit_after>/*globals _,window,exports*/
/*exported createBrowser*/

var BrowserInstance;

function createBrowser() {
  'use strict';

  if (BrowserInstance) {
    return BrowserInstance;
  }

  var homeUrl;
  var webviewDomainLimit;
  var webview;
  var webviewLoaded = false;

  function BrowserControls() {
    this._callbacks = [];

    this.isHome = false;
    this.isBack = false;
    this.isForward = false;
    this.isTop = false;
    this.isReload = false;

    this.scrollTopCan = false;
    window.addEventListener('message', function onMessage() {
      if (event && event.data && event.data.command && event.data.command === 'scroll') {
        if (event.data.value > 100) {
          this.scrollTopCan = true;
        } else {
          this.scrollTopCan = false;
        }

        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('scroll', this);
          }, this);
        }
      }
    }.bind(this));
  }

  BrowserControls.prototype.addChangeCallback = function addChangeCallback(callback) {
    if (typeof callback === 'function') {
      this._callbacks.push(callback);
    }
  };

  BrowserControls.prototype.canBack = function canGoBack() {
    if (webview) {
      this.isBack = webview.canGoBack();
    } else {
      this.isBack = false;
    }

    return this.isBack;
  };

  BrowserControls.prototype.back = function goBack() {
    if (!this.canBack()) {
      return;
    }
    webview.back();
  };

  BrowserControls.prototype.canForward = function canGoForward() {
    if (webview) {
      this.isForward = webview.canGoForward();
    } else {
      this.isForward = false;
    }

    return this.isForward;
  };

  BrowserControls.prototype.forward = function goForward() {
    if (!this.canForward()) {
      return;
    }
    webview.forward();
  };

  BrowserControls.prototype.canReload = function canReloadPage() {
    if (webview) {
      this.isReload = true;
    } else {
      this.isReload = false;
    }
    return this.isReload;
  };

  BrowserControls.prototype.reload = function reloadPage() {
    if (!this.canReload()) {
      return;
    }
    webview.reload();
  };

  BrowserControls.prototype.canHome = function canGoHome() {
    if (webview) {
      this.isHome = webview.src !== homeUrl;
    } else {
      this.isHome = false;
    }
    return this.isHome;
  };

  BrowserControls.prototype.home = function goHome() {
    if (!webview) {
      return;
    }
    webview.src = homeUrl;
  };

  BrowserControls.prototype.go = function goToPage(page) {
    if (!webview) {
      return;
    }
    webview.src = page;
  };

  BrowserControls.prototype.clearData = function clearData(callback) {
    if (!webview) {
      if (callback) {
        callback(false);
      }
      return;
    }
    webview.clearData({}, {
      'appcache': true,
      'cookies': true
    }, function clearDataDone() {
      this.home();
      if (callback) {
        callback(true);
      }
    }.bind(this));
  };

  BrowserControls.prototype.canTop = function canGoTop() {
    if (webview) {
      this.isTop = webviewLoaded && this.scrollTopCan;
    } else {
      this.isTop = false;
    }
    return this.isTop;
  };

  BrowserControls.prototype.top = function goTop() {
    if (!webview) {
      return;
    }
    if (!webviewLoaded) {
      return;
    }
    webview.contentWindow.postMessage({
      command: 'scrollTop'
    }, '*');
  };

  BrowserControls.prototype.check = function () {
    this.canReload();
    this.canHome();
    this.canTop();
    this.canBack();
    this.canForward();
  };

  function Browser() {
    this._callbacks = [];
    this._downloadFrom = '';
    this._allowNewWindows = false;
    this.controls = new BrowserControls();
  }

  Browser.prototype.exec = function exec(v) {
    if (!webview) {
      return;
    }
    if (!webviewLoaded) {
      return;
    }
    webview.focus();
    webview.contentWindow.postMessage({
      command: 'execute',
      value: v
    }, '*');
  };

  Browser.prototype.getControls = function getControls() {
    return this.controls;
  };

  Browser.prototype.allowNewWindows = function allowNewWindows(b) {
    this._allowNewWindows = b;
  };

  Browser.prototype.allowDownloadFrom = function allowDownloadFrom(d) {
    this._downloadFrom = d;
  };

  Browser.prototype.clearWebview = function clearWebview() {
    webview = undefined;
  };

  Browser.prototype.bindWebview = function bindWebview(selecter, partition, userAgent) {
    if (webview) {
      throw new Error('Browser is already bound to Webview!');
    }
    webview = window.document.querySelector(selecter);
    if (!webview) {
      throw new Error('Invalid selector or webview not found!');
    }

    //set where to save cookie and other data
    if (partition) {
      webview.partition = partition;
    }

    //useragent
    if (userAgent) {
      webview.setUserAgentOverride(webview.getUserAgent() + ' ' + userAgent);
    }

    //disable zoom
    webview.setZoomMode('disabled');

    //inject
    webview.addContentScripts([{
      name: 'rule',
      matches: ['http://*/*', 'https://*/*'],
      js: {
        files: ['scripts/inject.js']
      },
      css: {
        files: ['styles/inject.css']
      },
      'run_at': 'document_start'
    }]);

    //on close
    webview.addEventListener('close', function onCloseWebview(e) {
      webview.src = 'about:blank';
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('close', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('loadstart', function onStartWebview(e) {
      if (e.isTopLevel && webviewDomainLimit && (e.url.search(webviewDomainLimit) === -1 && e.url !== 'about:blank' && e.url !== 'data:text/html,chromewebdata')) {
        webview.stop();
        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('loadstart', new Error(e.url), e, this);
          }, this);
        }
        return;
      }

      webviewLoaded = false;
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('loadstart', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('loadstop', function onStopWebview(e) {
      webviewLoaded = true;
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('loadstop', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('loadabort', function onAbortWebview(e) {
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('loadabort', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('contentload', function onLoadWebview(e) {
      //shake hands to send this app id to web
      var shaked = false;
      var handshake = function handshake(event) {
        if (event && event.data && event.data.command && event.data.command === 'handshakereply') {
          shaked = true;
          window.removeEventListener('message', handshake);
        }
      }.bind(this);
      window.addEventListener('message', handshake);
      var shake = function shake() {
        if (webview && !shaked) {
          webview.contentWindow.postMessage({
            command: 'handshake'
          }, '*');
        } else {
          clearInterval(shaker);
          shaker = undefined;
        }
      };
      var shaker = setInterval(shake, 30000);
      //shake now
      shake();

      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('contentload', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('newwindow', function onNewWindowWebview(e) {
      if (this._allowNewWindows) {
        e.preventDefault();
        window.open(e.targetUrl); //open in chrome
        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('newwindow', null, e, this);
          }, this);
        }
      } else {
        e.window.discard();
        if (this._callbacks.length > 0) {
          _.each(this._callbacks, function (v) {
            v('newwindow', new Error(e.targetUrl), e, this);
          }, this);
        }
      }
    }.bind(this));

    webview.addEventListener('permissionrequest', function onPermissionWebview(e) {
      if (e.permission === 'download' && this._downloadFrom && e.request.url.search(this._downloadFrom) !== -1) {
        e.request.allow();
      }
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('permissionrequest', null, e, this);
        }, this);
      }
    }.bind(this));

    webview.addEventListener('dialog', function onDialogWebview(e) {
      if (this._callbacks.length > 0) {
        _.each(this._callbacks, function (v) {
          v('dialog', null, e, this);
        }, this);
      }
    }.bind(this));

    // force webview focus from app body
    setInterval(function keepWebviewFocus() {
      if (webview && webviewLoaded) {
        if (window.document.activeElement !== webview && window.document.activeElement.tagName !== 'INPUT' && window.document.activeElement.tagName !== 'TEXTAREA') {
          webview.focus();
        }
      }
    }, 1000);
  };

  Browser.prototype.setHome = function setHome(url) {
    homeUrl = url;
  };
  Browser.prototype.setDomainLimit = function setDomainLimit(reg) {
    webviewDomainLimit = reg;
  };

  Browser.prototype.getUrl = function getUrl() {
    return webview.src;
  };

  Browser.prototype.addChangeCallback = function addChangeCallback(callback) {
    if (typeof callback === 'function') {
      this._callbacks.push(callback);
    }
  };

  Browser.prototype.start = function startBrowser(callback) {
    if (!webview) {
      throw new Error('Use \'bindWebview\' to set webview selector first!');
    }
    if (!homeUrl) {
      throw new Error('Use \'setHome\' to set home page first!');
    }

    var done = function done() {
      if (webview.src === 'about:blank' || webview.src === '') {
        webview.src = homeUrl;
      }
    };

    if (callback) {
      callback(webview, done);
    } else {
      done();
    }
  };

  BrowserInstance = new Browser();
  return BrowserInstance;
}

if (typeof exports !== 'undefined') {
  exports.browser = createBrowser();
}
<|endoftext|>


<commit_before>export const cursorStringToCoordinates = (cursorString) => {
  // 1. split cursor strings to lines
  let lines = cursorString.split('\n')

  // 2. remove first and last line because they are empty
  const firstNonEmptyLine = (lines) => {
    let currentIndex = 0
    for (const line of lines) {
      if (line.trim() !== '') return currentIndex
      currentIndex++
    }
    return currentIndex
  }

  const startIndex = firstNonEmptyLine(lines)
  const endIndex = firstNonEmptyLine([...lines].reverse())

  lines = lines.slice(startIndex, lines.length - endIndex)

  // 3. remove trailing spaces from cursors: ['  x', '  x x'] => ['x', 'x x']

  // 3.1 determine shortest whitespace prefix
  const cursorIndentation = lines.reduce((shortestIndentation, line) => {
    if (!line || line.match(/^\s$/)) return shortestIndentation
    const match = line.match(/^\s+/)
    const currentIndentation = match ? match[0].length : 0
    return currentIndentation < shortestIndentation ? currentIndentation : shortestIndentation
  }, Infinity)

  lines = lines
    // 3.2 remove this indentation
    .map(line => line.replace(' '.repeat(cursorIndentation), ''))
    // 4. remove whitespace interlacing: '  x x x' => ' xxx'
    .map(line => line.split('').filter((_, i) => i % 2 === 0).join(''))
    // 5. convert strings to array of booleans: ' x ' => [false, true, false]
    .map(line => line.split('').map(s => s !== ' '))

  // 6. convert to array of xy coordinates
  const coordinates = []

  for (let y = 0; y < lines.length; y++) {
    const line = lines[y]
    for (let x = 0; x < line.length; x++) {
      if (!line[x]) continue
      coordinates.push([x, lines.length - y - 1])
    }
  }

  return coordinates
}

export const convertObjectOfCursors = (object) => {
  const convertedObj = {}
  for (const key in object) {
    if (typeof object[key] === 'string') {
      convertedObj[key] = cursorStringToCoordinates(object[key])
    } else {
      convertedObj[key] = convertObjectOfCursors(object[key])
    }
  }

  return convertedObj
}

export const getRandomCursor = (cursorsObject) => {
  const ignoredCursorTypes = [
    'Brushes',
    'Still lifes'
  ]

  const allCursors = Object.keys(cursorsObject)
    .filter(key => !ignoredCursorTypes.includes(key))
    .map(key => cursorsObject[key])
    .map(group => Object.keys(group).map(key => group[key]))
    .reduce((a, b) => a.concat(b))

  const getRandomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min
  const randomCursor = allCursors[getRandomInt(0, allCursors.length - 1)]

  return randomCursor
}
<commit_msg>fixes for edge<commit_after>export const cursorStringToCoordinates = (cursorString) => {
  // 1. split cursor strings to lines
  let lines = cursorString.split('\n')

  // 2. remove first and last line because they are empty
  const firstNonEmptyLine = (lines) => {
    let currentIndex = 0
    for (let i = 0; i < lines.length; i++) {
      if (lines[i].trim() !== '') return currentIndex
      currentIndex++
    }
    return currentIndex
  }

  const startIndex = firstNonEmptyLine(lines)
  const endIndex = firstNonEmptyLine([...lines].reverse())

  lines = lines.slice(startIndex, lines.length - endIndex)

  // 3. remove trailing spaces from cursors: ['  x', '  x x'] => ['x', 'x x']

  // 3.1 determine shortest whitespace prefix
  const cursorIndentation = lines.reduce((shortestIndentation, line) => {
    if (!line || line.match(/^\s$/)) return shortestIndentation
    const match = line.match(/^\s+/)
    const currentIndentation = match ? match[0].length : 0
    return currentIndentation < shortestIndentation ? currentIndentation : shortestIndentation
  }, Infinity)

  lines = lines
    // 3.2 remove this indentation
    .map(line => line.replace(' '.repeat(cursorIndentation), ''))
    // 4. remove whitespace interlacing: '  x x x' => ' xxx'
    .map(line => line.split('').filter((_, i) => i % 2 === 0).join(''))
    // 5. convert strings to array of booleans: ' x ' => [false, true, false]
    .map(line => line.split('').map(s => s !== ' '))

  // 6. convert to array of xy coordinates
  const coordinates = []

  for (let y = 0; y < lines.length; y++) {
    const line = lines[y]
    for (let x = 0; x < line.length; x++) {
      if (!line[x]) continue
      coordinates.push([x, lines.length - y - 1])
    }
  }

  return coordinates
}

export const convertObjectOfCursors = (object) => {
  const convertedObj = {}
  for (const key in object) {
    if (typeof object[key] === 'string') {
      convertedObj[key] = cursorStringToCoordinates(object[key])
    } else {
      convertedObj[key] = convertObjectOfCursors(object[key])
    }
  }

  return convertedObj
}

export const getRandomCursor = (cursorsObject) => {
  const ignoredCursorTypes = [
    'Brushes',
    'Still lifes'
  ]

  const allCursors = Object.keys(cursorsObject)
    .filter(key => ignoredCursorTypes.indexOf(key) === -1)
    .map(key => cursorsObject[key])
    .map(group => Object.keys(group).map(key => group[key]))
    .reduce((a, b) => a.concat(b))

  const getRandomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min
  const randomCursor = allCursors[getRandomInt(0, allCursors.length - 1)]

  return randomCursor
}
<|endoftext|>


<commit_before>var
	_ = require('underscore'),
	Promise = require('bluebird'),
	fs = require('fs'),
	moment = require('moment'),
	config = require('../../config/config'),
	AnalyticsProvider = require('./analytics').AnalyticsProvider;

var analyticsProvider = new AnalyticsProvider(config);

// TODO: Remove the following
function random (low, high) {
	return Math.random() * (high - low) + low;
}

function randomInt (low, high) {
	return Math.floor(Math.random() * (high - low) + low);
}

// TODO: NOT USED YET!
function randomDate(start, end) {
	return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
}
// TODO: End of the following

var scales = [{
	max: 60,
	granularity: 1
}, {
	max: 360,
	granularity: 5
}, {
	max: 720,
	granularity: 15
}, {
	max: 1440,
	granularity: 30
}];

var actionsReceived = {
  entries: 0,
  exits: 0
};

module.exports = {
  collectAction: function(action) {
    if (action.type == onfig.app.actionTypes.carIn) {
      actionsReceived.entries += 1;
    }
    else if (action.type == onfig.app.actionTypes.carOut) {
      actionsReceived.exits++;
    }
  },

	getEvolution: function(minutes) {
		var endDate = moment();
		var startDate = moment(endDate).subtract(minutes, 'minutes');

		var promise = Promise
			.resolve({
				carsIn: {},
				carsOut: {}
			})

			.then(function(memo) {
				memo.scale = _.find(scales, function (scale) {
					return minutes <= scale.max;
				});

				return memo;
			});

		if (config.app.randomData) {
			promise = promise
				.then(function(memo) {
					memo.nbCarsIn =  randomInt(150, 250);
					memo.nbCarsOut = randomInt(150, 250);
					memo.minDate = startDate.toDate();
					memo.maxDate = endDate.toDate();

					return memo;
				})

				.then(function(memo) {
					var carsIn = {};
					for (var i = 0; i < memo.nbCarsIn; i++) {
						var randDate = randomDate(memo.minDate, memo.maxDate);
						var calcDate = moment(endDate).subtract(moment(randDate));
						var idx = Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

						if (!carsIn[idx]) {
							carsIn[idx] = 0;
						}

						carsIn[idx]++;
					}

					memo.carsIn = _.reduce(carsIn, function (memo, val, key) {
						memo[parseInt(key)] = val;
						return memo;
					}, {});

					return memo;
				})

				.then(function(memo) {
					var carsOut = {};
					for (var i = 0; i < memo.nbCarsOut; i++) {
						var randDate = randomDate(memo.minDate, memo.maxDate);
						var calcDate = moment(endDate).subtract(moment(randDate));
						var idx = Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

						if (!carsOut[idx]) {
							carsOut[idx] = 0;
						}

						carsOut[idx]++;
					}

					memo.carsOut = _.reduce(carsOut, function(memo, val, key) {
						memo[parseInt(key)] = val;
						return memo;
					}, {});

					return memo;
				});
		}
		else {
			promise = promise
				.then(function (memo) {
					var nbSamples = memo.scale.max / memo.scale.granularity;

					return analyticsProvider
						.getMetrics('ch.heigvd.iflux.paleo2015.entries', 'minutely', startDate)
						.then(function (metrics) {
							_.each(metrics, function (metric) {
								var calcDate = moment(endDate).subtract(moment(metric.header.startDate));
								var idx = nbSamples - Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

								if (!memo.carsIn[idx]) {
									memo.carsIn[idx] = 0;
								}

								memo.carsIn[idx] += _.reduce(metric.secondly, function (memo, second) {
									return memo + second.sum;
								}, 0);
							});

							for (var i = 0; i < nbSamples; i++) {
								if (!memo.carsIn[i]) {
									memo.carsIn[i] = 0;
								}
							}

							memo.carsIn = _.reduce(memo.carsIn, function (memo, val, key) {
								//memo.push({ tick: parseInt(key), nbCars: val });
								memo[parseInt(key)] = val;
								return memo;
							}, {});

							return memo;
						});
				})

				.then(function (memo) {
					var nbSamples = memo.scale.max / memo.scale.granularity;

					return analyticsProvider
						.getMetrics('ch.heigvd.iflux.paleo2015.exits', 'minutely', startDate)
						.then(function (metrics) {
							_.each(metrics, function (metric) {
								var calcDate = moment(endDate).subtract(moment(metric.header.startDate));
								var idx = nbSamples - Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

								if (!memo.carsOut[idx]) {
									memo.carsOut[idx] = 0;
								}

								memo.carsOut[idx] += _.reduce(metric.secondly, function (memo, second) {
									return memo + second.sum;
								}, 0);
							});

							for (var i = 0; i < nbSamples; i++) {
								if (!memo.carsOut[i]) {
									memo.carsOut[i] = 0;
								}
							}

							memo.carsOut = _.reduce(memo.carsOut, function (memo, val, key) {
								memo[parseInt(key)] = val;
								return memo;
							}, {});

							return memo;
						});
				})
		}

		return promise
			.then(function(memo) {

				return {
					granularity: memo.scale.granularity,
					carsIn: memo.carsIn,
					carsOut: memo.carsOut
				};
			});
	},

	getTiles: function(type) {
		var days = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

		var promise = Promise.resolve({});

		if (config.app.randomData) {
			promise = promise
				.then(function(memo) {

					var startDay = randomInt(0, 7);

					var max = 0;

					for (var i = 0; i < 7; i++) {
						memo[i] = { day: days[(i + startDay) % 7], values: [] };

						for (var j = 0; j < 24; j++) {
							memo[i].values.push(randomInt(0, 10));

							if (memo[i].values[j] > max) {
								max = memo[i].values[j];
							}
						}
					}

					return { tiles: memo, min: 0, max: max };
				})
		}
		else {
			promise = promise
				.then(function (memo) {
					var endDate = moment();
					var startDate = moment(endDate).subtract(7, 'days');

					return analyticsProvider
						.getMetrics('ch.heigvd.iflux.paleo2015.' + type, 'daily', startDate)
						.then(function (metrics) {
							var countDays = 0;
							var max = 0;

							_.each(metrics, function (metric) {
								var date = moment(metric.header.startDate);
								var dayNumber = date.day();
								memo[countDays] = { day: days[dayNumber], values: [] };

								for (var i = 0; i < 24; i++) {
									if (metric.hourly && metric.hourly[i]) {
										memo[countDays].values.push(metric.hourly[i].sum);

										if (memo[countDays].values[i] > max) {
											max = memo[countDays].values[i];
										}
									}
									else {
										memo[countDays].values.push(0);
									}
								}

								countDays++;
							});

							return { tiles: memo, min: 0, max: max };
						});
				})
		}

		return promise;
	},

  getMovements: function() {
    var promise = Promise.resolve();

    if (config.app.randomData) {
      promise = promise.then(function() {
        return {
          entries: randomInt(0, 10),
          exits: randomInt(0, 10)
        };
      });
    }
    else {
      promise = promise.then(function() {
        return actionsReceived;
      });
    }

    return promise;
  }
};<commit_msg>Fixed small issues<commit_after>var
	_ = require('underscore'),
	Promise = require('bluebird'),
	fs = require('fs'),
	moment = require('moment'),
	config = require('../../config/config'),
	AnalyticsProvider = require('./analytics').AnalyticsProvider;

var analyticsProvider = new AnalyticsProvider(config);

// TODO: Remove the following
function random (low, high) {
	return Math.random() * (high - low) + low;
}

function randomInt (low, high) {
	return Math.floor(Math.random() * (high - low) + low);
}

// TODO: NOT USED YET!
function randomDate(start, end) {
	return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
}
// TODO: End of the following

var scales = [{
	max: 60,
	granularity: 1
}, {
	max: 360,
	granularity: 5
}, {
	max: 720,
	granularity: 15
}, {
	max: 1440,
	granularity: 30
}];

var actionsReceived = {
  entries: 0,
  exits: 0
};

module.exports = {
  collectAction: function(action) {
    if (action.type == config.app.actionTypes.carIn) {
      actionsReceived.entries += 1;
    }
    else if (action.type == config.app.actionTypes.carOut) {
      actionsReceived.exits++;
    }
  },

	getEvolution: function(minutes) {
		var endDate = moment();
		var startDate = moment(endDate).subtract(minutes, 'minutes');

		var promise = Promise
			.resolve({
				carsIn: {},
				carsOut: {}
			})

			.then(function(memo) {
				memo.scale = _.find(scales, function (scale) {
					return minutes <= scale.max;
				});

				return memo;
			});

		if (config.app.randomData) {
			promise = promise
				.then(function(memo) {
					memo.nbCarsIn =  randomInt(150, 250);
					memo.nbCarsOut = randomInt(150, 250);
					memo.minDate = startDate.toDate();
					memo.maxDate = endDate.toDate();

					return memo;
				})

				.then(function(memo) {
					var carsIn = {};
					for (var i = 0; i < memo.nbCarsIn; i++) {
						var randDate = randomDate(memo.minDate, memo.maxDate);
						var calcDate = moment(endDate).subtract(moment(randDate));
						var idx = Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

						if (!carsIn[idx]) {
							carsIn[idx] = 0;
						}

						carsIn[idx]++;
					}

					memo.carsIn = _.reduce(carsIn, function (memo, val, key) {
						memo[parseInt(key)] = val;
						return memo;
					}, {});

					return memo;
				})

				.then(function(memo) {
					var carsOut = {};
					for (var i = 0; i < memo.nbCarsOut; i++) {
						var randDate = randomDate(memo.minDate, memo.maxDate);
						var calcDate = moment(endDate).subtract(moment(randDate));
						var idx = Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

						if (!carsOut[idx]) {
							carsOut[idx] = 0;
						}

						carsOut[idx]++;
					}

					memo.carsOut = _.reduce(carsOut, function(memo, val, key) {
						memo[parseInt(key)] = val;
						return memo;
					}, {});

					return memo;
				});
		}
		else {
			promise = promise
				.then(function (memo) {
					var nbSamples = memo.scale.max / memo.scale.granularity;

					return analyticsProvider
						.getMetrics('ch.heigvd.iflux.paleo2015.entries', 'minutely', startDate)
						.then(function (metrics) {
							_.each(metrics, function (metric) {
								var calcDate = moment(endDate).subtract(moment(metric.header.startDate));
								var idx = nbSamples - Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

								if (!memo.carsIn[idx]) {
									memo.carsIn[idx] = 0;
								}

								memo.carsIn[idx] += _.reduce(metric.secondly, function (memo, second) {
									return memo + second.sum;
								}, 0);
							});

							for (var i = 0; i < nbSamples; i++) {
								if (!memo.carsIn[i]) {
									memo.carsIn[i] = 0;
								}
							}

							memo.carsIn = _.reduce(memo.carsIn, function (memo, val, key) {
								//memo.push({ tick: parseInt(key), nbCars: val });
								memo[parseInt(key)] = val;
								return memo;
							}, {});

							return memo;
						});
				})

				.then(function (memo) {
					var nbSamples = memo.scale.max / memo.scale.granularity;

					return analyticsProvider
						.getMetrics('ch.heigvd.iflux.paleo2015.exits', 'minutely', startDate)
						.then(function (metrics) {
							_.each(metrics, function (metric) {
								var calcDate = moment(endDate).subtract(moment(metric.header.startDate));
								var idx = nbSamples - Math.floor(moment.duration(calcDate).asMinutes() / memo.scale.granularity);

								if (!memo.carsOut[idx]) {
									memo.carsOut[idx] = 0;
								}

								memo.carsOut[idx] += _.reduce(metric.secondly, function (memo, second) {
									return memo + second.sum;
								}, 0);
							});

							for (var i = 0; i < nbSamples; i++) {
								if (!memo.carsOut[i]) {
									memo.carsOut[i] = 0;
								}
							}

							memo.carsOut = _.reduce(memo.carsOut, function (memo, val, key) {
								memo[parseInt(key)] = val;
								return memo;
							}, {});

							return memo;
						});
				})
		}

		return promise
			.then(function(memo) {

				return {
					granularity: memo.scale.granularity,
					carsIn: memo.carsIn,
					carsOut: memo.carsOut
				};
			});
	},

	getTiles: function(type) {
		var days = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

		var promise = Promise.resolve({});

		if (config.app.randomData) {
			promise = promise
				.then(function(memo) {

					var startDay = randomInt(0, 7);

					var max = 0;

					for (var i = 0; i < 7; i++) {
						memo[i] = { day: days[(i + startDay) % 7], values: [] };

						for (var j = 0; j < 24; j++) {
							memo[i].values.push(randomInt(0, 10));

							if (memo[i].values[j] > max) {
								max = memo[i].values[j];
							}
						}
					}

					return { tiles: memo, min: 0, max: max };
				})
		}
		else {
			promise = promise
				.then(function (memo) {
					var endDate = moment();
					var startDate = moment(endDate).subtract(7, 'days');

					return analyticsProvider
						.getMetrics('ch.heigvd.iflux.paleo2015.' + type, 'daily', startDate)
						.then(function (metrics) {
							var countDays = 0;
							var max = 0;

							_.each(metrics, function (metric) {
								var date = moment(metric.header.startDate);
								var dayNumber = date.day();
								memo[countDays] = { day: days[dayNumber], values: [] };

								for (var i = 0; i < 24; i++) {
									if (metric.hourly && metric.hourly[i]) {
										memo[countDays].values.push(metric.hourly[i].sum);

										if (memo[countDays].values[i] > max) {
											max = memo[countDays].values[i];
										}
									}
									else {
										memo[countDays].values.push(0);
									}
								}

								countDays++;
							});

							return { tiles: memo, min: 0, max: max };
						});
				})
		}

		return promise;
	},

  getMovements: function() {
    var promise = Promise.resolve();

    if (config.app.randomData) {
      promise = promise.then(function() {
        return {
          entries: randomInt(0, 10),
          exits: randomInt(0, 10)
        };
      });
    }
    else {
      promise = promise.then(function() {
        return actionsReceived;
      });
    }

    return promise;
  }
};<|endoftext|>


<commit_before>import { $$, remove, getAttr, hasAttr } from 'luett'
import { get } from 'lodash'
import Vue from 'vue'

import Adapters from '../adapters/dom-select'

const insert = (position, node, newNode) => {
  switch (position) {
    case 'beforebegin':
      node.parentNode.insertBefore(newNode, node)
      break
    case 'afterend':
      node.parentNode.insertBefore(newNode, node.nextElementSibling)
      break
  }
}

const insertAfter = insert.bind(null, 'afterend')
const generateChoices = (defaultValue, option) => {
  const value = getAttr(option, 'value')
  return {
    value: value,
    text: option.textContent,
    label: getAttr(option, 'label', ''),
    isCurrent: hasAttr(option, 'selected'),
    isDefault: defaultValue === value
  }
}

export default (el, opts) => {
  const adapter = Adapters[opts.conf.type]
  let vue
  let container
  let data = $$('option', el).map(generateChoices.bind(null, opts.conf.defaultValue || ''))
  const defaultValue = data.reduce((result, option) => option.isDefault ? option.value : result, null)
  const value = data.reduce((result, option) => option.isCurrent ? option.value : result, null)

  if (get(opts, 'skipDefault', true)) {
    data = data.filter(option => !option.isDefault)
  }

  adapter.get(data)
    .then(model => {
      container = document.createElement('div')
      container.id = `${el.id}-container`
      insertAfter(el, container)
      el.style.display = 'none'

      vue = new Vue({
        template: `<sg-select :choices="model.choices" :defaultChoice="model.defaultChoice"
                              :renderer="adapter.renderer" :texts="adapter.texts" :filter="adapter.filter"
                              :defaultValue="defaultValue" v-model="value"></sg-select>`,
        el: `#${container.id}`,
        data: {
          model,
          defaultValue,
          value,
          adapter
        },
        watch: {
          value (value) {
            el.value = value
          }
        }
      })
    })

  return {
    remove () {
      if (vue) vue.$destroy()
      if (container) remove(container)
    }
  }
}
<commit_msg>dispatch event when changing select value through dom api<commit_after>import { $$, remove, getAttr, hasAttr } from 'luett'
import { get } from 'lodash'
import Vue from 'vue'

import Adapters from '../adapters/dom-select'

const insert = (position, node, newNode) => {
  switch (position) {
    case 'beforebegin':
      node.parentNode.insertBefore(newNode, node)
      break
    case 'afterend':
      node.parentNode.insertBefore(newNode, node.nextElementSibling)
      break
  }
}

const insertAfter = insert.bind(null, 'afterend')
const generateChoices = (defaultValue, option) => {
  const value = getAttr(option, 'value')
  return {
    value: value,
    text: option.textContent,
    label: getAttr(option, 'label', ''),
    isCurrent: hasAttr(option, 'selected'),
    isDefault: defaultValue === value
  }
}

export default (el, opts) => {
  const adapter = Adapters[opts.conf.type]
  let vue
  let container
  let data = $$('option', el).map(generateChoices.bind(null, opts.conf.defaultValue || ''))
  const defaultValue = data.reduce((result, option) => option.isDefault ? option.value : result, null)
  const value = data.reduce((result, option) => option.isCurrent ? option.value : result, null)

  if (get(opts, 'skipDefault', true)) {
    data = data.filter(option => !option.isDefault)
  }

  adapter.get(data)
    .then(model => {
      container = document.createElement('div')
      container.id = `${el.id}-container`
      insertAfter(el, container)
      el.style.display = 'none'

      vue = new Vue({
        template: `<sg-select :choices="model.choices" :defaultChoice="model.defaultChoice"
                              :renderer="adapter.renderer" :texts="adapter.texts" :filter="adapter.filter"
                              :defaultValue="defaultValue" v-model="value"></sg-select>`,
        el: `#${container.id}`,
        data: {
          model,
          defaultValue,
          value,
          adapter
        },
        watch: {
          value (value) {
            el.value = value
            el.dispatchEvent(new Event('change'))
          }
        }
      })
    })

  return {
    remove () {
      if (vue) vue.$destroy()
      if (container) remove(container)
    }
  }
}
<|endoftext|>


<commit_before>// Namespace
troppo = {};

troppo.audio = null;

troppo.initialize = function() {

	troppo.audio = new Audio();

	// Listen to key strokes
	$(window).keyup(function(event) {
		// Show the symbol
		var inputSymbol = String.fromCharCode(event.which);
		$('#characterDisplay').html(inputSymbol.toUpperCase() + ' ' + inputSymbol.toLowerCase());

		// Play the sound
		var audio = troppo.audio;
		audio.pause();

		var artist = 'olli';
		if (Math.random() > 0.5) {
			artist = 'alvar';
		}
		var audioPath = 'audio/' + artist + '/v1/' + inputSymbol + '.wav'
		try {
			audio.src = audioPath;
		} catch (exception) {
			// Pokemon!
		}
		audio.play();
	});
};
<commit_msg>Back to keypress to get key codes right<commit_after>// Namespace
troppo = {};

troppo.audio = null;

troppo.initialize = function() {

	troppo.audio = new Audio();

	// Listen to key strokes
	$(window).keypress(function(event) {
		// Show the symbol
		var inputSymbol = String.fromCharCode(event.which);
		$('#characterDisplay').html(inputSymbol.toUpperCase() + ' ' + inputSymbol.toLowerCase());

		// Play the sound
		var audio = troppo.audio;
		audio.pause();

		var artist = 'olli';
		if (Math.random() > 0.5) {
			artist = 'alvar';
		}
		var audioPath = 'audio/' + artist + '/v1/' + inputSymbol + '.wav'
		try {
			audio.src = audioPath;
		} catch (exception) {
			// Pokemon!
		}
		audio.play();
	});
};
<|endoftext|>


<commit_before>(function() {
  var Time = {
    MINUTES_IN_HOUR        : 60,
    MILLISECONDS_IN_MINUTE : 60000,

    OFFSETS : [300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300, 240,
               300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300],
    UNTILS  : [1268550000000, 1289109600000, 1299999600000, 1320559200000,
               1331449200000, 1352008800000, 1362898800000, 1383458400000,
               1394348400000, 1414908000000, 1425798000000, 1446357600000,
               1457852400000, 1478412000000, 1489302000000, 1509861600000,
               1520751600000, 1541311200000, 1552201200000, 1572760800000,
               1583650800000, 1604210400000, null],

    formatDate: function(date) {
      return new Intl.DateTimeFormat(undefined, {
        month   : "long",
        day     : "numeric",
        weekday : "long"
      }).format(date);
    },

    formatTime: function(time) {
      return new Intl.DateTimeFormat(undefined, {
        hour   : "numeric",
        minute : "numeric"
      }).format(time);
    },

    offset: function() {
      var target  = Date.now(),
          untils  = this.UNTILS,
          offsets = this.OFFSETS,
          offset,
          offsetNext,
          offsetPrev;

      for (var index = 0; index < untils.length - 1; index++) {
        offset     = offsets[index];
        offsetNext = offsets[index + 1];
        offsetPrev = offsets[index ? index - 1 : index];

        if (offset < offsetNext && false) {
          offset = offsetNext;
        } else if (offset > offsetPrev && true) {
          offset = offsetPrev;
        }

        if (target < untils[index] - (offset * this.MILLISECONDS_IN_MINUTE)) {
          return offsets[index] / this.MINUTES_IN_HOUR;
        }
      }

      return offsets[untils.length - 1] / this.MINUTES_IN_HOUR;
    }
  };

  var now      = new Date(),
      empty    = document.querySelector(".empty"),
      hours    = now.getUTCHours(),
      slice    = Array.prototype.slice,
      offset   = Time.offset(),
      sections = slice.call(document.querySelectorAll("section"));

  if (navigator.platform.match(/Win/)) {
    document.querySelector("header h1 a").innerHTML = "Hockey";
  }

  if (hours < offset) {
    now.setUTCHours(hours - offset);
  }

  var year  = now.getUTCFullYear(),
      month = now.getUTCMonth() + 1,
      day   = now.getUTCDate(),
      limit = 7,
      count = 1;

  sections.forEach(function(section) {
    section.classList.remove("week");
  });

  var activeSections = sections.filter(function(section) {
    if (!section) {
      return false;
    }

    var time = section.querySelector("h1 time");

    if (!time) {
      return false;
    }

    var parts        = time.getAttribute("datetime").split("-"),
        sectionYear  = parseInt(parts[0], 10),
        sectionMonth = parseInt(parts[1], 10),
        sectionDay   = parseInt(parts[2].split("T")[0], 10);

    return (sectionYear >  year) ||
           (sectionYear >= year && sectionMonth >  month) ||
           (sectionYear >= year && sectionMonth >= month && sectionDay >= day - 1);
  });

  if (activeSections.length === 0) {
    var header     = empty.querySelector("h1"),
        difference = Math.round(
          (new Date("9/16/2019").getTime() - Date.now()) /
          1000 / 60 / 60 / 24
        ),
        duration   = "in " + difference + " days";

    if (Intl.RelativeTimeFormat) {
      duration = new Intl.RelativeTimeFormat({ style: "narrow" }).format(difference, "day");
    }

    header.innerText = "Hockey " + duration + ".";

    empty.classList.remove("hidden");

    return;
  } else if (empty) {
    empty.parentNode.removeChild(empty);
  }

  activeSections.forEach(function(section, index) {
    if (!section.querySelector("tr")) {
      return;
    } else if (count > limit && window.location.pathname === "/") {
      return;
    }

    count++;

    if (window.Intl && window.Intl.DateTimeFormat) {
      var time         = section.querySelector("h1 time");
          parts        = time.getAttribute("datetime").split("-"),
          sectionYear  = parseInt(parts[0], 10),
          sectionMonth = parseInt(parts[1], 10),
          sectionDay   = parseInt(parts[2].split("T")[0], 10);

      if (sectionYear === year && sectionMonth === month && sectionDay === day) {
        time.innerText = "Today";
      } else {
        time.innerText = Time.formatDate(
          new Date(time.getAttribute("datetime"))
        );
      }

      slice.call(section.querySelectorAll("th time")).forEach(function(time) {
        var date = new Date(time.getAttribute("datetime"));

        time.textContent = Time.formatTime(date);
      });
    }

    section.classList.add("week");
  });

  window.addEventListener("load", function(e) {
    if (!window.applicationCache) {
      return;
    }

    window.applicationCache.addEventListener("updateready", function(e) {
      if (window.applicationCache.status !== window.applicationCache.UPDATEREADY) {
        return;
      }

      if (confirm("An updated schedule is available. Load it?")) {
        window.location.reload();
      }
    }, false);
  }, false);
})();
<commit_msg>Remove empty sections to improve rendering.<commit_after>(function() {
  var Time = {
    MINUTES_IN_HOUR        : 60,
    MILLISECONDS_IN_MINUTE : 60000,

    OFFSETS : [300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300, 240,
               300, 240, 300, 240, 300, 240, 300, 240, 300, 240, 300],
    UNTILS  : [1268550000000, 1289109600000, 1299999600000, 1320559200000,
               1331449200000, 1352008800000, 1362898800000, 1383458400000,
               1394348400000, 1414908000000, 1425798000000, 1446357600000,
               1457852400000, 1478412000000, 1489302000000, 1509861600000,
               1520751600000, 1541311200000, 1552201200000, 1572760800000,
               1583650800000, 1604210400000, null],

    formatDate: function(date) {
      return new Intl.DateTimeFormat(undefined, {
        month   : "long",
        day     : "numeric",
        weekday : "long"
      }).format(date);
    },

    formatTime: function(time) {
      return new Intl.DateTimeFormat(undefined, {
        hour   : "numeric",
        minute : "numeric"
      }).format(time);
    },

    offset: function() {
      var target  = Date.now(),
          untils  = this.UNTILS,
          offsets = this.OFFSETS,
          offset,
          offsetNext,
          offsetPrev;

      for (var index = 0; index < untils.length - 1; index++) {
        offset     = offsets[index];
        offsetNext = offsets[index + 1];
        offsetPrev = offsets[index ? index - 1 : index];

        if (offset < offsetNext && false) {
          offset = offsetNext;
        } else if (offset > offsetPrev && true) {
          offset = offsetPrev;
        }

        if (target < untils[index] - (offset * this.MILLISECONDS_IN_MINUTE)) {
          return offsets[index] / this.MINUTES_IN_HOUR;
        }
      }

      return offsets[untils.length - 1] / this.MINUTES_IN_HOUR;
    }
  };

  var now      = new Date(),
      empty    = document.querySelector(".empty"),
      hours    = now.getUTCHours(),
      slice    = Array.prototype.slice,
      offset   = Time.offset(),
      sections = slice.call(document.querySelectorAll("section"));

  if (navigator.platform.match(/Win/)) {
    document.querySelector("header h1 a").innerHTML = "Hockey";
  }

  if (hours < offset) {
    now.setUTCHours(hours - offset);
  }

  var year  = now.getUTCFullYear(),
      month = now.getUTCMonth() + 1,
      day   = now.getUTCDate(),
      limit = 7,
      count = 1;

  sections.forEach(function(section) {
    section.classList.remove("week");
  });

  var activeSections = sections.filter(function(section) {
    if (!section) {
      return false;
    }

    var time = section.querySelector("h1 time");

    if (!time) {
      return false;
    }

    if (!section.querySelector("table tbody")) {
      section.parentNode.removeChild(section);

      return false;
    }

    var parts        = time.getAttribute("datetime").split("-"),
        sectionYear  = parseInt(parts[0], 10),
        sectionMonth = parseInt(parts[1], 10),
        sectionDay   = parseInt(parts[2].split("T")[0], 10);

    return (sectionYear >  year) ||
           (sectionYear >= year && sectionMonth >  month) ||
           (sectionYear >= year && sectionMonth >= month && sectionDay >= day - 1);
  });

  if (activeSections.length === 0) {
    var header     = empty.querySelector("h1"),
        difference = Math.round(
          (new Date("9/16/2019").getTime() - Date.now()) /
          1000 / 60 / 60 / 24
        ),
        duration   = "in " + difference + " days";

    if (Intl.RelativeTimeFormat) {
      duration = new Intl.RelativeTimeFormat({ style: "narrow" }).format(difference, "day");
    }

    header.innerText = "Hockey " + duration + ".";

    empty.classList.remove("hidden");

    return;
  } else if (empty) {
    empty.parentNode.removeChild(empty);
  }

  activeSections.forEach(function(section, index) {
    if (!section.querySelector("tr")) {
      return;
    } else if (count > limit && window.location.pathname === "/") {
      return;
    }

    count++;

    if (window.Intl && window.Intl.DateTimeFormat) {
      var time         = section.querySelector("h1 time");
          parts        = time.getAttribute("datetime").split("-"),
          sectionYear  = parseInt(parts[0], 10),
          sectionMonth = parseInt(parts[1], 10),
          sectionDay   = parseInt(parts[2].split("T")[0], 10);

      if (sectionYear === year && sectionMonth === month && sectionDay === day) {
        time.innerText = "Today";
      } else {
        time.innerText = Time.formatDate(
          new Date(time.getAttribute("datetime"))
        );
      }

      slice.call(section.querySelectorAll("th time")).forEach(function(time) {
        var date = new Date(time.getAttribute("datetime"));

        time.textContent = Time.formatTime(date);
      });
    }

    section.classList.add("week");
  });

  window.addEventListener("load", function(e) {
    if (!window.applicationCache) {
      return;
    }

    window.applicationCache.addEventListener("updateready", function(e) {
      if (window.applicationCache.status !== window.applicationCache.UPDATEREADY) {
        return;
      }

      if (confirm("An updated schedule is available. Load it?")) {
        window.location.reload();
      }
    }, false);
  }, false);
})();
<|endoftext|>


<commit_before>var TreeSvg = function () {
    var ts = Object.create(null);

    ts.extractTreeFromParentField = function (nodes, idField, parentIdField) {
        // internal function to get a node container from the id
        var nodesById = Object.create(null);
        var getContainerById = function (id, node) {
            if (!(id in nodesById)) {
                nodesById[id] = { "children": [] };
            }
            var container = nodesById[id];
            if (node != null) {
                container.node = node;
            }
            return container;
        };

        // build a hash of nodes by id, with children, filling in the children
        // as we walk the tree. assume the nodes are sorted in the desired order
        var root = { id: -1, node: null, parent: null, children: [] };
        for (var i = 0, count = nodes.length; i < count; ++i) {
            var node = nodes[i];
            var id = node[idField];
            var container = getContainerById(id, node);
            var parentId = node[parentIdField];
            if (parentId != null) {
                var parentContainer = getContainerById(parentId, null);
                parentContainer.children.push(container);
                container.parent = parentContainer;
            } else {
                root.children.push (container);
            }
        }

        // return the finished result
        return (root.children.length > 1) ? root : root.children[0];
    };

    ts.render = function (root) {
        // create the raw SVG picture for display, assumes a width/height aspect ratio of 3/2
        var buffer = 0.15;
        var svg = '
' +
                    '<svg class="tree-svg-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" ' +
                    'viewBox="-0.15, -0.1, 1.8, 1.2" ' +
                    'preserveAspectRatio="xMidYMid slice"' +
                    '>';
        svg += '<rect x="0" y="0" width="1.5" height="1.0" fill="none" stroke="blue" stroke-width="0.001"/>';

        // recursive layout in uniform scale space
        var depth = 0;
        var recursiveLayout = function (x, y, node) {
            var childCount = node.children.length;
            var childX = x;
            if (childCount > 0) {
                var nextY = y + 1;
                childX = recursiveLayout(x, nextY, node.children[0]);
                for (var i = 1; i < childCount; ++i) {
                    childX = recursiveLayout(childX + 1, nextY, node.children[i]);
                }
            }

            // compute layout
            node.x = (x + childX) / 2.0;
            node.y = y;
            depth = Math.max(depth, y);
            return childX;
        };
        var width = recursiveLayout(0, 0, root);

        // recursive re-scaling to fit in the drawing space
        var xScale = 1.5 / width;
        var yScale = 1.0 / depth;
        var recursiveScale = function (node) {
            for (var i = 0, childCount = node.children.length; i < childCount; ++i) {
                recursiveScale(node.children[i]);
            }
            node.x *= xScale;
            node.y *= yScale;
        };
        recursiveScale(root);

        // utility function for getting the tension right on the quadratic
        // Bezier curve we'll use for the edges
        var lerp = function (a, b, i) {
            return (a * i) + (b * (1.0 - i));
        };

        // draw the edges
        var recursiveDrawEdges = function (node) {
            for (var i = 0, childCount = node.children.length; i < childCount; ++i) {
                var c = node.children[i];
                //svg += '<line x1="' + node.x + '" y1="' + node.y + '" x2="' + c.x + '" y2="' + c.y + '" stroke="black" stroke-width="0.002" />';
                recursiveDrawEdges(node.children[i]);
                var mid = { x: (node.x + c.x) / 2.0, y: (node.y + c.y) / 2.0 };
                svg += '<path d="M' + node.x + ',' + node.y + ' Q' + node.x + ',' + lerp(node.y, mid.y, 0.4) + ' ' + mid.x + ',' + mid.y + ' T' + c.x + ',' + c.y + '" fill="none" stroke="black" stroke-width="0.002"  />'
            }
        };
        recursiveDrawEdges(root);

        // draw the nodes
        var radius = Math.max(Math.min(xScale * 0.33, yScale * 0.25), 0.01);
        var recursiveDrawNodes = function (node) {
            for (var i = 0, childCount = node.children.length; i < childCount; ++i) {
                recursiveDrawNodes(node.children[i]);
            }
            svg += '<circle cx="' + node.x + '" cy="' + node.y + '" r="' + radius + '" stroke="black" stroke-width="0.002" fill="red" />';
        };
        recursiveDrawNodes(root);

        // close the plot
        svg += "

";
        return svg;
    };

    return ts;
}();
<commit_msg>and changing slice back to meet<commit_after>var TreeSvg = function () {
    var ts = Object.create(null);

    ts.extractTreeFromParentField = function (nodes, idField, parentIdField) {
        // internal function to get a node container from the id
        var nodesById = Object.create(null);
        var getContainerById = function (id, node) {
            if (!(id in nodesById)) {
                nodesById[id] = { "children": [] };
            }
            var container = nodesById[id];
            if (node != null) {
                container.node = node;
            }
            return container;
        };

        // build a hash of nodes by id, with children, filling in the children
        // as we walk the tree. assume the nodes are sorted in the desired order
        var root = { id: -1, node: null, parent: null, children: [] };
        for (var i = 0, count = nodes.length; i < count; ++i) {
            var node = nodes[i];
            var id = node[idField];
            var container = getContainerById(id, node);
            var parentId = node[parentIdField];
            if (parentId != null) {
                var parentContainer = getContainerById(parentId, null);
                parentContainer.children.push(container);
                container.parent = parentContainer;
            } else {
                root.children.push (container);
            }
        }

        // return the finished result
        return (root.children.length > 1) ? root : root.children[0];
    };

    ts.render = function (root) {
        // create the raw SVG picture for display, assumes a width/height aspect ratio of 3/2
        var buffer = 0.15;
        var svg = '
' +
                    '<svg class="tree-svg-svg" xmlns="http://www.w3.org/2000/svg" version="1.1" ' +
                    'viewBox="-0.15, -0.1, 1.8, 1.2" ' +
                    'preserveAspectRatio="xMidYMid meet"' +
                    '>';
        svg += '<rect x="0" y="0" width="1.5" height="1.0" fill="none" stroke="blue" stroke-width="0.001"/>';

        // recursive layout in uniform scale space
        var depth = 0;
        var recursiveLayout = function (x, y, node) {
            var childCount = node.children.length;
            var childX = x;
            if (childCount > 0) {
                var nextY = y + 1;
                childX = recursiveLayout(x, nextY, node.children[0]);
                for (var i = 1; i < childCount; ++i) {
                    childX = recursiveLayout(childX + 1, nextY, node.children[i]);
                }
            }

            // compute layout
            node.x = (x + childX) / 2.0;
            node.y = y;
            depth = Math.max(depth, y);
            return childX;
        };
        var width = recursiveLayout(0, 0, root);

        // recursive re-scaling to fit in the drawing space
        var xScale = 1.5 / width;
        var yScale = 1.0 / depth;
        var recursiveScale = function (node) {
            for (var i = 0, childCount = node.children.length; i < childCount; ++i) {
                recursiveScale(node.children[i]);
            }
            node.x *= xScale;
            node.y *= yScale;
        };
        recursiveScale(root);

        // utility function for getting the tension right on the quadratic
        // Bezier curve we'll use for the edges
        var lerp = function (a, b, i) {
            return (a * i) + (b * (1.0 - i));
        };

        // draw the edges
        var recursiveDrawEdges = function (node) {
            for (var i = 0, childCount = node.children.length; i < childCount; ++i) {
                var c = node.children[i];
                //svg += '<line x1="' + node.x + '" y1="' + node.y + '" x2="' + c.x + '" y2="' + c.y + '" stroke="black" stroke-width="0.002" />';
                recursiveDrawEdges(node.children[i]);
                var mid = { x: (node.x + c.x) / 2.0, y: (node.y + c.y) / 2.0 };
                svg += '<path d="M' + node.x + ',' + node.y + ' Q' + node.x + ',' + lerp(node.y, mid.y, 0.4) + ' ' + mid.x + ',' + mid.y + ' T' + c.x + ',' + c.y + '" fill="none" stroke="black" stroke-width="0.002"  />'
            }
        };
        recursiveDrawEdges(root);

        // draw the nodes
        var radius = Math.max(Math.min(xScale * 0.33, yScale * 0.25), 0.01);
        var recursiveDrawNodes = function (node) {
            for (var i = 0, childCount = node.children.length; i < childCount; ++i) {
                recursiveDrawNodes(node.children[i]);
            }
            svg += '<circle cx="' + node.x + '" cy="' + node.y + '" r="' + radius + '" stroke="black" stroke-width="0.002" fill="red" />';
        };
        recursiveDrawNodes(root);

        // close the plot
        svg += "

";
        return svg;
    };

    return ts;
}();
<|endoftext|>


<commit_before>/* vi:si:et:sw=4:sts=4:ts=4 */

'use strict';
(function() {

    klp.init = function() {
        klp.accordion.init();
        klp.router = new KLPRouter();
        klp.router.init();
        initSelect2();
        loadData();
        //get JS query params from URL

    }

    function initSelect2() {
        $('#select2search').select2({
            placeholder: 'Search for schools and boundaries',
            minimumInputLength: 3,
            ajax: {
                url: "/api/v1/search",
                quietMillis: 300,
                allowClear: true,
                data: function(term, page) {
                    return {
                        text: term,
                        geometry: 'yes'
                    };
                },
                results: function(data, page) {
                    var searchResponse = {
                        results: [{
                            text: "Pre-Schools",
                            children: makeResults(data.pre_schools.features, 'school')
                        }, {
                            text: "Primary Schools",
                            children: makeResults(data.primary_schools.features, 'school')
                        }, {
                            text: "Boundaries",
                            children: makeResults(data.boundaries.features, 'boundary')
                        }]
                    };
                    return {
                        results: searchResponse.results
                    };
                }
            }
        });
        $('#select2search').on("change", function(choice) {
            console.log(choice);
        });
    }

    function makeResults(array, type) {
        var schoolDistrictMap = {
            'primaryschool': 'Primary School',
            'preschool': 'Preschool'
        };
        return _(array).map(function(obj) {
            var name = obj.properties.name;
            if (type === 'boundary') {
                if (obj.properties.type === 'district') {
                    name = obj.properties.name + ' - ' + schoolDistrictMap[obj.properties.school_type] + ' ' + obj.properties.type;
                } else {
                    name = obj.properties.name + ' - ' + obj.properties.type;
                }
            }

            obj.entity_type = type;
            return {
                id: obj.properties.id,
                text: _.str.titleize(name),
                data: obj
            };
        });
    }

    function loadData() {
        var params = klp.router.getHash().queryParams;
        var metaURL = "stories/meta/"; //FIXME: enter API url
        var $metaXHR = klp.api.do(metaURL, params);

        $metaXHR.done(function(data) {
            console.log("summary data", data);
            renderSummary(data);
            renderRespondentChart(data);
        });

        var detailURL = "stories/details/";
        var $detailXHR = klp.api.do(detailURL, params);

        $detailXHR.done(function(data) {
            console.log("detail data", data);
            renderFeatured(data);
            renderIVRS(data);
            renderSurvey(data);
            renderWeb(data);
            //renderComparison(data);
        });

        var volumeURL = "stories/volume/";
        var $volumeXHR = klp.api.do(volumeURL, params);
        $volumeXHR.done(function(data) {
            renderIVRSVolumeChart(data);
        });

        //TODO: do some loading behaviour

    }

    function renderRespondentChart(data) {
        var labels = _.keys(data.respondents);
        var values = _.values(data.respondents);
        //console.log(labels, values);
        var data_respondent = {
            labels: labels,
            series: [
                values
            ]
        };

        renderBarChart('#chart_respondent', data_respondent);

    }

    function renderIVRSVolumeChart(data) {
        var labels = _.keys(data.volumes);
        var values = _.values(data.volumes);
        var data_ivrs = {
            labels: labels,
            series: [
                values
            ]
        };
        renderBarChart('#chart_ivrs', data_ivrs);
    }

    function renderBarChart(elementId, data) {
        var options = {
            axisX: {
                showGrid: false
            },
            axisY: {
                showGrid: false
            }
        };

        var chart_element = Chartist.Bar(elementId, data, options).on('draw', function(data) {
            if (data.type === 'bar') {
                data.element.attr({
                    style: 'stroke-width: 20px'
                });
            }
        });
    }

    function renderSummary(data) {
        var tplTopSummary = swig.compile($('#tpl-topSummary').html());
        var tplCountSummary = swig.compile($('#tpl-countSummary').html());
        var topSummaryHTML = tplTopSummary(data);
        $('#topSummary').html(topSummaryHTML);

        var summaries = {
            'ivrs': [{
                'label': 'Schools',
                'count': data.total.schools
            }, {
                'label': 'Schools with Stories',
                'count': data.ivrs.schools
            }, {
                'label': 'Calls received',
                'count': data.ivrs.stories
            }, {
                'label': 'Academic Year',
                'count': '2015-2016'
            }],
            'survey': [{
                'label': 'Schools',
                'count': data.total.schools
            }, {
                'label': 'Schools with Stories',
                'count': data.community.schools
            }, {
                'label': 'Stories',
                'count': data.community.stories
            }, {
                'label': 'Academic Year',
                'count': '2015-2016'
            }],
            'web': [{
                'label': 'Schools',
                'count': data.total.schools
            }, {
                'label': 'Schools with Stories',
                'count': data.web.schools
            }, {
                'label': 'Verified Stories',
                'count': data.web.verified_stories
            }, {
                'label': 'Academic Year',
                'count': '2015-2016'
            }]
        };
        var html = tplCountSummary({
            'summary': summaries['ivrs']
        });
        $('#ivrssummary').html(html);
        html = tplCountSummary({
            'summary': summaries['survey']
        });
        $('#surveysummary').html(html);
        html = tplCountSummary({
            'summary': summaries['web']
        });
        $('#websummary').html(html);
    }

    function renderFeatured(data) {
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());

        var questions = [{
            'question': 'IVRS: How many schools had all teachers present on the Day of Visit?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'IVRS: How many schools had classes being conducted?',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'Surveys: How many schools had functional toilets?',
            'score': 300,
            'total': 1000,
            'percent': 30
        }, {
            'question': 'Surveys: How many schools had drinking water?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }];

        var html = ''
        for (var pos in questions) {
            html = html + tplPercentGraph(questions[pos]);
        }
        $('#quicksummary').html(html);
    }

    function renderIVRS(data) {
        var tplGradeGraph = swig.compile($('#tpl-gradeGraph').html());
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());
        //define your data
        var grades = [{
            'value': 'A',
            'score': 440,
            'total': 1000,
            'percent': 44,
            'color': 'green-leaf'
        }, {
            'value': 'B',
            'score': 260,
            'total': 1000,
            'percent': 26,
            'color': 'orange-mild'
        }, {
            'value': 'C',
            'score': 300,
            'total': 1000,
            'percent': 30,
            'color': 'pink-salmon'
        }];

        var html = ''
        for (var pos in grades) {
            html = html + "
" + tplGradeGraph(grades[pos]) + "
";
        }
        $('#ivrsgrades').html(html);

        var questions = [{
            'question': 'How many schools were open on the day of visit?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'In how many schools was the Headmaster present?',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'In how many schools were the toilets in good condition?',
            'score': 300,
            'total': 1000,
            'percent': 30
        }];

        html = ''
        for (var pos in questions) {
            html = html + tplPercentGraph(questions[pos]);
        }
        $('#ivrsquestions').html(html);
    }

    function renderSurvey(data) {
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());

        var questions = [{
            'question': 'How many schools are the teachers regular?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'How many schools have sufficient teachers?',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'In how many schools are teachers taking classes regularly?',
            'score': 300,
            'total': 1000,
            'percent': 30
        }, {
            'question': 'How many schools have children getting academic attenction?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'In how many schools are SDMC members involved?',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'In how many schools are there no concerns about Mid-day Meals?',
            'score': 300,
            'total': 1000,
            'percent': 30
        }];

        var html = "
";
        for (var pos in questions) {
            if (pos == questions.length / 2) {
                html = html + "

";
            }
            html = html + tplPercentGraph(questions[pos]);
        }
        html = html + "
";
        $('#surveyquestions').html(html);
    }

    function renderWeb(data) {
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());

        var questions = [{
            'question': 'Where there was evidence of a Mid-day meal served:',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'Where 50% of children enrolled in the school were present:',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'Where all the teachers for all classes were present:',
            'score': 300,
            'total': 1000,
            'percent': 30
        }];

        var html = ''
        for (var pos in questions) {
            html = html + "
" + tplPercentGraph(questions[pos]) + "
";
        }
        $('#webquestions').html(html);

        var tplColorText = swig.compile($('#tpl-colorText').html());

        var facilities = [{
            'facility': 'All weather pucca building',
            'icon': ['fa fa-university'],
            'percent': 44
        }, {
            'facility': 'Playground',
            'icon': ['fa fa-futbol-o'],
            'percent': 45
        }, {
            'facility': 'Drinking Water',
            'icon': ['fa  fa-tint'],
            'percent': 54
        }, {
            'facility': 'Library',
            'icon': ['fa fa-book'],
            'percent': 64
        }, {
            'facility': 'Toilets',
            'icon': ['fa fa-male', 'fa fa-female'],
            'percent': 74
        }, {
            'facility': 'Secure Boundary Wall',
            'icon': ['fa fa-circle-o-notch'],
            'percent': 34
        }];

        var html = ''
        for (var pos in facilities) {
            html = html + tplColorText(facilities[pos]);
        }
        $('#webfacilities').html(html);

    }

    function renderComparison(data) {
        var tplCompareTable = swig.compile($('#tpl-compareTable').html());

        var neighbours = [{
            'name': 'Bangalore North',
            'schools': 1000,
            'stories': 440,
            'needs_volunteer': 'Playground',
            'needs_community': 'Playground',
            'ivrs': 500
        }, {
            'name': 'Bangalore South',
            'schools': 1000,
            'stories': 540,
            'needs_volunteer': 'Drinking Water',
            'needs_community': 'Mid-day Meals',
            'ivrs': 600
        }, {
            'name': 'Bangalore Central',
            'schools': 1000,
            'stories': 640,
            'needs_volunteer': 'Drinking Water',
            'needs_community': 'Playground',
            'ivrs': 600
        }, {
            'name': 'Bangalore Rural',
            'schools': 1000,
            'stories': 740,
            'needs_volunteer': 'Playground',
            'needs_community': 'Mid-day Meals',
            'ivrs': 600
        }];

        var html = tplCompareTable({
            'neighbours': neighbours
        });
        $('#comparison').html(html);

    }

})();<commit_msg>render featured question charts<commit_after>/* vi:si:et:sw=4:sts=4:ts=4 */

'use strict';
(function() {

    klp.init = function() {
        klp.accordion.init();
        klp.router = new KLPRouter();
        klp.router.init();
        initSelect2();
        loadData();
        //get JS query params from URL

    }

    function initSelect2() {
        $('#select2search').select2({
            placeholder: 'Search for schools and boundaries',
            minimumInputLength: 3,
            ajax: {
                url: "/api/v1/search",
                quietMillis: 300,
                allowClear: true,
                data: function(term, page) {
                    return {
                        text: term,
                        geometry: 'yes'
                    };
                },
                results: function(data, page) {
                    var searchResponse = {
                        results: [{
                            text: "Pre-Schools",
                            children: makeResults(data.pre_schools.features, 'school')
                        }, {
                            text: "Primary Schools",
                            children: makeResults(data.primary_schools.features, 'school')
                        }, {
                            text: "Boundaries",
                            children: makeResults(data.boundaries.features, 'boundary')
                        }]
                    };
                    return {
                        results: searchResponse.results
                    };
                }
            }
        });
        $('#select2search').on("change", function(choice) {
            console.log(choice);
        });
    }

    function makeResults(array, type) {
        var schoolDistrictMap = {
            'primaryschool': 'Primary School',
            'preschool': 'Preschool'
        };
        return _(array).map(function(obj) {
            var name = obj.properties.name;
            if (type === 'boundary') {
                if (obj.properties.type === 'district') {
                    name = obj.properties.name + ' - ' + schoolDistrictMap[obj.properties.school_type] + ' ' + obj.properties.type;
                } else {
                    name = obj.properties.name + ' - ' + obj.properties.type;
                }
            }

            obj.entity_type = type;
            return {
                id: obj.properties.id,
                text: _.str.titleize(name),
                data: obj
            };
        });
    }

    function loadData() {
        var params = klp.router.getHash().queryParams;
        var metaURL = "stories/meta/"; //FIXME: enter API url
        var $metaXHR = klp.api.do(metaURL, params);

        $metaXHR.done(function(data) {
            console.log("summary data", data);
            renderSummary(data);
            renderRespondentChart(data);
        });

        var detailURL = "stories/details/";
        var $detailXHR = klp.api.do(detailURL, params);

        $detailXHR.done(function(data) {
            console.log("detail data", data);
            renderFeatured(data);
            renderIVRS(data);
            renderSurvey(data);
            renderWeb(data);
            //renderComparison(data);
        });

        var volumeURL = "stories/volume/";
        var $volumeXHR = klp.api.do(volumeURL, params);
        $volumeXHR.done(function(data) {
            renderIVRSVolumeChart(data);
        });

        //TODO: do some loading behaviour

    }

    function renderRespondentChart(data) {
        var labels = _.keys(data.respondents);
        var values = _.values(data.respondents);
        //console.log(labels, values);
        var data_respondent = {
            labels: labels,
            series: [
                values
            ]
        };

        renderBarChart('#chart_respondent', data_respondent);

    }

    function renderIVRSVolumeChart(data) {
        var labels = _.keys(data.volumes);
        var values = _.values(data.volumes);
        var data_ivrs = {
            labels: labels,
            series: [
                values
            ]
        };
        renderBarChart('#chart_ivrs', data_ivrs);
    }

    function renderBarChart(elementId, data) {
        var options = {
            axisX: {
                showGrid: false
            },
            axisY: {
                showGrid: false
            }
        };

        var chart_element = Chartist.Bar(elementId, data, options).on('draw', function(data) {
            if (data.type === 'bar') {
                data.element.attr({
                    style: 'stroke-width: 20px'
                });
            }
        });
    }

    function renderSummary(data) {
        var tplTopSummary = swig.compile($('#tpl-topSummary').html());
        var tplCountSummary = swig.compile($('#tpl-countSummary').html());
        var topSummaryHTML = tplTopSummary(data);
        $('#topSummary').html(topSummaryHTML);

        var summaries = {
            'ivrs': [{
                'label': 'Schools',
                'count': data.total.schools
            }, {
                'label': 'Schools with Stories',
                'count': data.ivrs.schools
            }, {
                'label': 'Calls received',
                'count': data.ivrs.stories
            }, {
                'label': 'Academic Year',
                'count': '2015-2016'
            }],
            'survey': [{
                'label': 'Schools',
                'count': data.total.schools
            }, {
                'label': 'Schools with Stories',
                'count': data.community.schools
            }, {
                'label': 'Stories',
                'count': data.community.stories
            }, {
                'label': 'Academic Year',
                'count': '2015-2016'
            }],
            'web': [{
                'label': 'Schools',
                'count': data.total.schools
            }, {
                'label': 'Schools with Stories',
                'count': data.web.schools
            }, {
                'label': 'Verified Stories',
                'count': data.web.verified_stories
            }, {
                'label': 'Academic Year',
                'count': '2015-2016'
            }]
        };
        var html = tplCountSummary({
            'summary': summaries['ivrs']
        });
        $('#ivrssummary').html(html);
        html = tplCountSummary({
            'summary': summaries['survey']
        });
        $('#surveysummary').html(html);
        html = tplCountSummary({
            'summary': summaries['web']
        });
        $('#websummary').html(html);
    }

    function renderFeatured(data) {
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());
        var featuredQuestionsPrimary = [
            {
                'source': 'ivrs',
                'key': 'ivrss-teachers-present',
                'source_prefix': 'IVRS: '
            },
            {
                'source': 'ivrs',
                'key': 'ivrss-classes-proper',
                'source_prefix': 'IVRS: '
            },
            {
                'source': 'community',
                'key': 'comms2-functioning-toilets',
                'source_prefix': 'Surveys: '
            },
            {
                'source': 'community',
                'key': 'comms2-drinking-water',
                'source_prefix': 'Surveys: '
            }
        ];
        var featuredQuestions = featuredQuestionsPrimary; //TODO: add preschool
        var questionObjects = _.map(featuredQuestions, function(obj) {
            return getQuestion(data, obj.source, obj.key);
        });

        var questions = getQuestionsArray(questionObjects);
        //console.log("questions", questions);

        // var questions = [{
        //     'question': 'IVRS: How many schools had all teachers present on the Day of Visit?',
        //     'score': 440,
        //     'total': 1000,
        //     'percent': 44
        // }, {
        //     'question': 'IVRS: How many schools had classes being conducted?',
        //     'score': 260,
        //     'total': 1000,
        //     'percent': 26
        // }, {
        //     'question': 'Surveys: How many schools had functional toilets?',
        //     'score': 300,
        //     'total': 1000,
        //     'percent': 30
        // }, {
        //     'question': 'Surveys: How many schools had drinking water?',
        //     'score': 440,
        //     'total': 1000,
        //     'percent': 44
        // }];

        var html = ''
        for (var pos in questions) {
            html = html + tplPercentGraph(questions[pos]);
        }
        $('#quicksummary').html(html);

        function getQuestionsArray(questions) {
            return _.map(questions, function(question, seq) {
                var score = getYesScore(question.answers);
                var total = getTotal(question.answers);
                var percent = getPercent(score, total);
                var qObj = featuredQuestions[seq];
                var displayText = qObj.source_prefix + question.question.display_text;
                return {
                    'question': displayText,
                    'score': score,
                    'total': total,
                    'percent': percent
                };
            });
        }
    }

    function getYesScore(answers) {
        var options = answers.options;
        if (options.hasOwnProperty('Yes')) {
            return options['Yes'];
        } else {
            return 0;
        }
    }

    function getTotal(answers) {
        return _.reduce(_.keys(answers.options), function(memo, answerKey) {
            return memo + answers.options[answerKey];
        }, 0);
    }

    function getPercent(score, total) {
        if (total == 0) {
            return 0;
        }
        return Math.round((score / total) * 100);
    }

    function renderIVRS(data) {
        var tplGradeGraph = swig.compile($('#tpl-gradeGraph').html());
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());
        //define your data
        var grades = [{
            'value': 'A',
            'score': 440,
            'total': 1000,
            'percent': 44,
            'color': 'green-leaf'
        }, {
            'value': 'B',
            'score': 260,
            'total': 1000,
            'percent': 26,
            'color': 'orange-mild'
        }, {
            'value': 'C',
            'score': 300,
            'total': 1000,
            'percent': 30,
            'color': 'pink-salmon'
        }];

        var html = ''
        for (var pos in grades) {
            html = html + "
" + tplGradeGraph(grades[pos]) + "
";
        }
        $('#ivrsgrades').html(html);

        var questions = [{
            'question': 'How many schools were open on the day of visit?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'In how many schools was the Headmaster present?',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'In how many schools were the toilets in good condition?',
            'score': 300,
            'total': 1000,
            'percent': 30
        }];

        html = ''
        for (var pos in questions) {
            html = html + tplPercentGraph(questions[pos]);
        }
        $('#ivrsquestions').html(html);
    }

    function getQuestion(data, source, key) {
        for (var i=0, len=data[source].length; i<len; i++) {
            var question = data[source][i];
            if (question.question.key === key) {
                return question;
            }
        }
        return false;
    }

    function renderSurvey(data) {
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());

        var questions = [{
            'question': 'How many schools are the teachers regular?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'How many schools have sufficient teachers?',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'In how many schools are teachers taking classes regularly?',
            'score': 300,
            'total': 1000,
            'percent': 30
        }, {
            'question': 'How many schools have children getting academic attenction?',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'In how many schools are SDMC members involved?',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'In how many schools are there no concerns about Mid-day Meals?',
            'score': 300,
            'total': 1000,
            'percent': 30
        }];

        var html = "
";
        for (var pos in questions) {
            if (pos == questions.length / 2) {
                html = html + "

";
            }
            html = html + tplPercentGraph(questions[pos]);
        }
        html = html + "
";
        $('#surveyquestions').html(html);
    }

    function renderWeb(data) {
        var tplPercentGraph = swig.compile($('#tpl-percentGraph').html());

        var questions = [{
            'question': 'Where there was evidence of a Mid-day meal served:',
            'score': 440,
            'total': 1000,
            'percent': 44
        }, {
            'question': 'Where 50% of children enrolled in the school were present:',
            'score': 260,
            'total': 1000,
            'percent': 26
        }, {
            'question': 'Where all the teachers for all classes were present:',
            'score': 300,
            'total': 1000,
            'percent': 30
        }];

        var html = ''
        for (var pos in questions) {
            html = html + "
" + tplPercentGraph(questions[pos]) + "
";
        }
        $('#webquestions').html(html);

        var tplColorText = swig.compile($('#tpl-colorText').html());

        var facilities = [{
            'facility': 'All weather pucca building',
            'icon': ['fa fa-university'],
            'percent': 44
        }, {
            'facility': 'Playground',
            'icon': ['fa fa-futbol-o'],
            'percent': 45
        }, {
            'facility': 'Drinking Water',
            'icon': ['fa  fa-tint'],
            'percent': 54
        }, {
            'facility': 'Library',
            'icon': ['fa fa-book'],
            'percent': 64
        }, {
            'facility': 'Toilets',
            'icon': ['fa fa-male', 'fa fa-female'],
            'percent': 74
        }, {
            'facility': 'Secure Boundary Wall',
            'icon': ['fa fa-circle-o-notch'],
            'percent': 34
        }];

        var html = ''
        for (var pos in facilities) {
            html = html + tplColorText(facilities[pos]);
        }
        $('#webfacilities').html(html);

    }

    function renderComparison(data) {
        var tplCompareTable = swig.compile($('#tpl-compareTable').html());

        var neighbours = [{
            'name': 'Bangalore North',
            'schools': 1000,
            'stories': 440,
            'needs_volunteer': 'Playground',
            'needs_community': 'Playground',
            'ivrs': 500
        }, {
            'name': 'Bangalore South',
            'schools': 1000,
            'stories': 540,
            'needs_volunteer': 'Drinking Water',
            'needs_community': 'Mid-day Meals',
            'ivrs': 600
        }, {
            'name': 'Bangalore Central',
            'schools': 1000,
            'stories': 640,
            'needs_volunteer': 'Drinking Water',
            'needs_community': 'Playground',
            'ivrs': 600
        }, {
            'name': 'Bangalore Rural',
            'schools': 1000,
            'stories': 740,
            'needs_volunteer': 'Playground',
            'needs_community': 'Mid-day Meals',
            'ivrs': 600
        }];

        var html = tplCompareTable({
            'neighbours': neighbours
        });
        $('#comparison').html(html);

    }

})();<|endoftext|>