<commit_before>define('HUD',

['vent', 'util', 'Sprite'],

function( vent, util ){

    'use strict';

    var init,
        ctx,
        canvas,
        update,
        render,
        bindEvents,
        drawItems,
        score,
        draw,
        cooldownTimer,
        checkCooldown,
        cfg;

    cfg = {
        earthEmblem: {
            fillStyle: [
                '#372720',
                'rgba(73, 52, 42, 0.5)',
                'rgba(104, 74, 59, 0.3)'
            ],
            size: 15,
            x: 30,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        waterEmblem: {
            fillStyle: [
                'rgba(0, 0, 220, 1)'
            ],
            size: 15,
            x: 65,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        airEmblem: {
            fillStyle: [
                'rgba(241, 241, 241, 1)'
            ],
            size: 15,
            x: 100,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        fireEmblem: {
            fillStyle: [
                'rgba(255, 0, 0, 1)'
            ],
            size: 15,
            x: 135,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        cooldownTimer: {
            fillStyle: '#f1f1f1',
            font: '20px Courier',
            textAlign: 'right'
        }
    };

    drawItems = {
        bar: function( ctx ){
            ctx.beginPath();
            ctx.rect(0, ctx.canvas.height - 50, ctx.canvas.width, 50);
            ctx.fillStyle = '#333';
            ctx.shadowBlur = 0;
            ctx.fill();

            ctx.beginPath();
            ctx.rect(0, ctx.canvas.height - 52, ctx.canvas.width, 2);
            ctx.fillStyle = '#444';
            ctx.shadowBlur = 0;
            ctx.fill();
        },
        score: function( ctx ) {
            ctx.font = "20px Courier";
            ctx.fillStyle = '#f1f1f1';
            ctx.textAlign = 'right';
            ctx.fillText(
                'Score: ' + score,
                ctx.canvas.width - 25, ctx.canvas.height - 20
            );
        },
        earthEmblem: function( ctx ){
            var c = cfg.earthEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7,
                c.fillStyle[0]
            );
        },
        waterEmblem: function( ctx ){
            var c = cfg.waterEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7, c.fillStyle[0]);
        },
        airEmblem: function( ctx ){
            var c = cfg.airEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7, c.fillStyle[0]);
        },
        fireEmblem: function( ctx ){
            var c = cfg.fireEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7, c.fillStyle[0]);
        },
        cooldownTimer: function( ctx ){
            var c = cfg.cooldownTimer;
            util.text(ctx, cooldownTimer.current || 'Ready',
                220, ctx.canvas.height - 20, c.fillStyle
            );
        }
    };

    init = function(){
        var cvs = util.getById('hud');
        ctx = cvs.getContext('2d');
        canvas = {
            width: cvs.width,
            height: cvs.height,
            ctx: ctx
        };

        score = 0;
        cooldownTimer = {
            current: 10,
            lastChecked: new Date().getTime()
        };

        vent.on('update', update);
        vent.on('render', render);
        vent.on('deactivate', function(){
            cooldownTimer.current = 20;
            cooldownTimer.lastChecked = new Date().getTime();
        });

    };

    bindEvents = function(){
        vent.on('effects-canvas-added', function( obj ){
            init(obj);
        });
        vent.on('enemy-down', function(){
            score += 2;
        });
    };

    checkCooldown = function(){
        if ( cooldownTimer.current - 1 < 0 ) {
            return;
        }

        var now = new Date().getTime(),
            diff = now - cooldownTimer.lastChecked;

        if ( diff >= 1000 ) {
            cooldownTimer.current--;
            cooldownTimer.lastChecked = now;
        }

        // if
    };

    update = function(){
        checkCooldown();
    };

    render = function(){
        ctx.clearRect(0, 0, ctx.canvas.width, 50);
        draw('bar');
        draw('score');
        draw('earthEmblem');
        draw('waterEmblem');
        draw('airEmblem');
        draw('fireEmblem');
        draw('cooldownTimer');
    };

    draw = function( name ){
        drawItems[name](ctx);
    };

    bindEvents();

});
<commit_msg>I like breaking things<commit_after>define('HUD',

['vent', 'util', 'Sprite'],

function( vent, util ){

    'use strict';

    var init,
        ctx,
        canvas,
        update,
        render,
        bindEvents,
        drawItems,
        score,
        draw,
        cooldownTimer,
        checkCooldown,
        cfg;

    cfg = {
        earthEmblem: {
            fillStyle: [
                '#372720',
                'rgba(73, 52, 42, 0.5)',
                'rgba(104, 74, 59, 0.3)'
            ],
            size: 15,
            x: 30,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        waterEmblem: {
            fillStyle: [
                'rgba(0, 0, 220, 1)'
            ],
            size: 15,
            x: 65,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        airEmblem: {
            fillStyle: [
                'rgba(241, 241, 241, 1)'
            ],
            size: 15,
            x: 100,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        fireEmblem: {
            fillStyle: [
                'rgba(255, 0, 0, 1)'
            ],
            size: 15,
            x: 135,
            y: 575,
            angle: 0,
            displayProps: {
                shadowOffsetX: 0,
                shadowOffsetY: 0
            }
        },
        cooldownTimer: {
            fillStyle: '#f1f1f1',
            font: '20px Courier',
            textAlign: 'right'
        }
    };

    drawItems = {
        bar: function( ctx ){
            ctx.beginPath();
            ctx.rect(0, ctx.canvas.height - 50, ctx.canvas.width, 50);
            ctx.fillStyle = '#333';
            ctx.shadowBlur = 0;
            ctx.fill();

            ctx.beginPath();
            ctx.rect(0, ctx.canvas.height - 52, ctx.canvas.width, 2);
            ctx.fillStyle = '#444';
            ctx.shadowBlur = 0;
            ctx.fill();
        },
        score: function( ctx ) {
            ctx.font = "20px Courier";
            ctx.fillStyle = '#f1f1f1';
            ctx.textAlign = 'right';
            ctx.fillText(
                'Score: ' + score,
                ctx.canvas.width - 25, ctx.canvas.height - 20
            );
        },
        earthEmblem: function( ctx ){
            var c = cfg.earthEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7,
                c.fillStyle[0]
            );
        },
        waterEmblem: function( ctx ){
            var c = cfg.waterEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7, c.fillStyle[0]);
        },
        airEmblem: function( ctx ){
            var c = cfg.airEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7, c.fillStyle[0]);
        },
        fireEmblem: function( ctx ){
            var c = cfg.fireEmblem;
            util.polygon(ctx, c.x, c.y, c.size, 7, c.fillStyle[0]);
        },
        cooldownTimer: function( ctx ){
            var c = cfg.cooldownTimer;
            util.text(ctx, cooldownTimer.current || 'Ready',
                220, ctx.canvas.height - 20, c.fillStyle
            );
        }
    };

    init = function(){
        var cvs = util.getById('hud');
        ctx = cvs.getContext('2d');
        canvas = {
            width: cvs.width,
            height: cvs.height,
            ctx: ctx
        };

        score = 0;
        cooldownTimer = {
            current: 10,
            lastChecked: new Date().getTime()
        };

        vent.on('update', update);
        vent.on('render', render);
        vent.on('deactivate', function(){
            cooldownTimer.current = 20;
            cooldownTimer.lastChecked = new Date().getTime();
        });

    };

    bindEvents = function(){
        vent.on('start', function( obj ){
            init(obj);
        });
        vent.on('enemy-down', function(){
            score += 2;
        });
    };

    checkCooldown = function(){
        if ( cooldownTimer.current - 1 < 0 ) {
            return;
        }

        var now = new Date().getTime(),
            diff = now - cooldownTimer.lastChecked;

        if ( diff >= 1000 ) {
            cooldownTimer.current--;
            cooldownTimer.lastChecked = now;
        }

        // if
    };

    update = function(){
        checkCooldown();
    };

    render = function(){
        ctx.clearRect(0, 0, ctx.canvas.width, 50);
        draw('bar');
        draw('score');
        draw('earthEmblem');
        draw('waterEmblem');
        draw('airEmblem');
        draw('fireEmblem');
        draw('cooldownTimer');
    };

    draw = function( name ){
        drawItems[name](ctx);
    };

    bindEvents();

});
<|endoftext|>


<commit_before>// Copyright (c) 2016 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// This widget makes displays the status of selected parameters and
// notes as they are being played.

function StatusMatrix() {
    docById('statusmatrix').style.visibility = 'hidden';

    this.init = function(logo) {
        // Initializes the status matrix. First removes the
        // previous matrix and them make another one in DOM (document
        // object model)
        this._logo = logo;

        docById('statusmatrix').style.display = 'inline';
        docById('statusmatrix').style.visibility = 'visible';
        docById('statusmatrix').style.border = 2;

        var w = window.innerWidth;
        this._cellScale = w / 1200;
        docById('statusmatrix').style.overflowX = 'auto';

        // Used to remove the matrix table
        Element.prototype.remove = function() {
            this.parentElement.removeChild(this);
        }

        NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
            for (var i = 0, len = this.length; i < len; i++) {
                if (this[i] && this[i].parentElement) {
                    this[i].parentElement.removeChild(this[i]);
                }
            }
        };

        var table = docById('statusTable');

        if (table !== null) {
            table.remove();
        }

        var x = document.createElement('TABLE');
        x.setAttribute('id', 'statusTable');
        x.style.textAlign = 'center';

        var statusDiv = docById('statusmatrix');
        statusDiv.style.paddingTop = 0 + 'px';
        statusDiv.style.paddingLeft = 0 + 'px';
        statusDiv.appendChild(x);
        var statusDivPosition = statusDiv.getBoundingClientRect();

        var table = docById('statusTable');
        var header = table.createTHead();
        var row = header.insertRow(0);
        row.style.left = Math.floor(statusDivPosition.left) + 'px';
        row.style.top = Math.floor(statusDivPosition.top) + 'px';

        var iconSize = Math.floor(this._cellScale * 24);

        var cell = row.insertCell(-1);
        cell.innerHTML = '    ';
        cell.style.width = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
        cell.style.minWidth = cell.style.width;
        cell.style.maxWidth = cell.style.width;
        cell.style.height = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
        cell.style.backgroundColor = MATRIXBUTTONCOLOR;

        cell.onclick=function() {
            docById('statusmatrix').style.visibility = 'hidden';
            docById('statusmatrix').style.border = 0;
        }

        cell.onmouseover=function() {
            this.style.backgroundColor = MATRIXBUTTONCOLORHOVER;
        }

        cell.onmouseout=function() {
            this.style.backgroundColor = MATRIXBUTTONCOLOR;
        }

        // One column per field
        for (var i = 0; i < this._logo.statusFields.length; i++) {
            var cell = row.insertCell(i + 1);
            cell.style.fontSize = Math.floor(this._cellScale * 100) + '%';

	    switch (this._logo.statusFields[i][1]) {
            case 'plus':
            case 'minus':
            case 'neg':
            case 'divide':
            case 'multiply':
            case 'sqrt':
            case 'int':
            case 'mod':
		var label = '';
		break;
	    default:
                var label = this._logo.blocks.blockList[this._logo.statusFields[i][0]].protoblock.staticLabels[0];
		break;
	    }

            cell.innerHTML = ' ' + label + ' '
            cell.style.height = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
            cell.style.backgroundColor = MATRIXBUTTONCOLOR;
        }

        var cell = row.insertCell(i + 1);
        cell.style.fontSize = Math.floor(this._cellScale * 100) + '%';
        cell.innerHTML = ' ' + _('note') + ' '
        cell.style.height = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
        cell.style.backgroundColor = MATRIXBUTTONCOLOR;

        // One row per voice (turtle)
        var activeTurtles = 0;
        for (var turtle = 0; turtle < this._logo.turtles.turtleList.length; turtle++) {
            if (this._logo.turtles.turtleList[turtle].trash) {
                continue;
            }

            var row = header.insertRow(activeTurtles + 1);
            var cell = row.insertCell(0);
            cell.style.backgroundColor = MATRIXLABELCOLOR;

            cell.innerHTML = '    ';

            cell.style.height = Math.floor(MATRIXSOLFEHEIGHT * this._cellScale) + 'px';

            // + 1 is for the note column
            for (var i = 0; i < this._logo.statusFields.length + 1; i++) {
                var cell = row.insertCell(-1);
                cell.style.backgroundColor = MATRIXRHYTHMCELLCOLOR;
                cell.style.fontSize = Math.floor(this._cellScale * 100) + '%';
                cell.innerHTML = '';
                cell.style.height = Math.floor(MATRIXSOLFEHEIGHT * this._cellScale) + 'px';
            }

            activeTurtles += 1;
        }
    };

    this.updateAll = function() {
        // Update status of all of the voices in the matrix.
        var table = docById('statusTable');

        var activeTurtles = 0;
        for (var turtle = 0; turtle < this._logo.turtles.turtleList.length; turtle++) {
            if (this._logo.turtles.turtleList[turtle].trash) {
                continue;
            }

            for (var i = 0; i < this._logo.statusFields.length; i++) {
                var saveStatus = this._logo.inStatusMatrix;
                this._logo.inStatusMatrix = false;

                this._logo.parseArg(this._logo, turtle, this._logo.statusFields[i][0]);
                var innerHTML = this._logo.blocks.blockList[this._logo.statusFields[i][0]].value;
                this._logo.inStatusMatrix = saveStatus;

                var cell = table.rows[activeTurtles + 1].cells[i + 1];
                if (cell != null) {
                    cell.innerHTML = innerHTML;
                }
            }

            var note = '';
            var value = '';
            if (this._logo.noteStatus[turtle] != null) {
                var notes = this._logo.noteStatus[turtle][0];
                for (var j = 0; j < notes.length; j++) {
                    note += notes[j];
                    note += ' ';
                }
                var value = this._logo.noteStatus[turtle][1];
                if (value > 1) {
                    // FIXME: Do proper conversion of rational to fraction.
                    note += '1 / ';  // Show note value as fraction.
                    note += value;
                } else {
                    note += 1 / value;
                }
            }

            var cell = table.rows[activeTurtles + 1].cells[i + 1];
            if (cell != null) {
                cell.innerHTML = note.replace(/#/g, '♯').replace(/b/, '♭');
            }

            activeTurtles += 1;
        }
    };
};
<commit_msg>get rid of spaces around /<commit_after>// Copyright (c) 2016 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// This widget makes displays the status of selected parameters and
// notes as they are being played.

function StatusMatrix() {
    docById('statusmatrix').style.visibility = 'hidden';

    this.init = function(logo) {
        // Initializes the status matrix. First removes the
        // previous matrix and them make another one in DOM (document
        // object model)
        this._logo = logo;

        docById('statusmatrix').style.display = 'inline';
        docById('statusmatrix').style.visibility = 'visible';
        docById('statusmatrix').style.border = 2;

        var w = window.innerWidth;
        this._cellScale = w / 1200;
        docById('statusmatrix').style.overflowX = 'auto';

        // Used to remove the matrix table
        Element.prototype.remove = function() {
            this.parentElement.removeChild(this);
        }

        NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
            for (var i = 0, len = this.length; i < len; i++) {
                if (this[i] && this[i].parentElement) {
                    this[i].parentElement.removeChild(this[i]);
                }
            }
        };

        var table = docById('statusTable');

        if (table !== null) {
            table.remove();
        }

        var x = document.createElement('TABLE');
        x.setAttribute('id', 'statusTable');
        x.style.textAlign = 'center';

        var statusDiv = docById('statusmatrix');
        statusDiv.style.paddingTop = 0 + 'px';
        statusDiv.style.paddingLeft = 0 + 'px';
        statusDiv.appendChild(x);
        var statusDivPosition = statusDiv.getBoundingClientRect();

        var table = docById('statusTable');
        var header = table.createTHead();
        var row = header.insertRow(0);
        row.style.left = Math.floor(statusDivPosition.left) + 'px';
        row.style.top = Math.floor(statusDivPosition.top) + 'px';

        var iconSize = Math.floor(this._cellScale * 24);

        var cell = row.insertCell(-1);
        cell.innerHTML = '    ';
        cell.style.width = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
        cell.style.minWidth = cell.style.width;
        cell.style.maxWidth = cell.style.width;
        cell.style.height = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
        cell.style.backgroundColor = MATRIXBUTTONCOLOR;

        cell.onclick=function() {
            docById('statusmatrix').style.visibility = 'hidden';
            docById('statusmatrix').style.border = 0;
        }

        cell.onmouseover=function() {
            this.style.backgroundColor = MATRIXBUTTONCOLORHOVER;
        }

        cell.onmouseout=function() {
            this.style.backgroundColor = MATRIXBUTTONCOLOR;
        }

        // One column per field
        for (var i = 0; i < this._logo.statusFields.length; i++) {
            var cell = row.insertCell(i + 1);
            cell.style.fontSize = Math.floor(this._cellScale * 100) + '%';

	    switch (this._logo.statusFields[i][1]) {
            case 'plus':
            case 'minus':
            case 'neg':
            case 'divide':
            case 'multiply':
            case 'sqrt':
            case 'int':
            case 'mod':
		var label = '';
		break;
	    default:
                var label = this._logo.blocks.blockList[this._logo.statusFields[i][0]].protoblock.staticLabels[0];
		break;
	    }

            cell.innerHTML = ' ' + label + ' '
            cell.style.height = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
            cell.style.backgroundColor = MATRIXBUTTONCOLOR;
        }

        var cell = row.insertCell(i + 1);
        cell.style.fontSize = Math.floor(this._cellScale * 100) + '%';
        cell.innerHTML = ' ' + _('note') + ' '
        cell.style.height = Math.floor(MATRIXBUTTONHEIGHT * this._cellScale) + 'px';
        cell.style.backgroundColor = MATRIXBUTTONCOLOR;

        // One row per voice (turtle)
        var activeTurtles = 0;
        for (var turtle = 0; turtle < this._logo.turtles.turtleList.length; turtle++) {
            if (this._logo.turtles.turtleList[turtle].trash) {
                continue;
            }

            var row = header.insertRow(activeTurtles + 1);
            var cell = row.insertCell(0);
            cell.style.backgroundColor = MATRIXLABELCOLOR;

            cell.innerHTML = '    ';

            cell.style.height = Math.floor(MATRIXSOLFEHEIGHT * this._cellScale) + 'px';

            // + 1 is for the note column
            for (var i = 0; i < this._logo.statusFields.length + 1; i++) {
                var cell = row.insertCell(-1);
                cell.style.backgroundColor = MATRIXRHYTHMCELLCOLOR;
                cell.style.fontSize = Math.floor(this._cellScale * 100) + '%';
                cell.innerHTML = '';
                cell.style.height = Math.floor(MATRIXSOLFEHEIGHT * this._cellScale) + 'px';
            }

            activeTurtles += 1;
        }
    };

    this.updateAll = function() {
        // Update status of all of the voices in the matrix.
        var table = docById('statusTable');

        var activeTurtles = 0;
        for (var turtle = 0; turtle < this._logo.turtles.turtleList.length; turtle++) {
            if (this._logo.turtles.turtleList[turtle].trash) {
                continue;
            }

            for (var i = 0; i < this._logo.statusFields.length; i++) {
                var saveStatus = this._logo.inStatusMatrix;
                this._logo.inStatusMatrix = false;

                this._logo.parseArg(this._logo, turtle, this._logo.statusFields[i][0]);
                var innerHTML = this._logo.blocks.blockList[this._logo.statusFields[i][0]].value;
                this._logo.inStatusMatrix = saveStatus;

                var cell = table.rows[activeTurtles + 1].cells[i + 1];
                if (cell != null) {
                    cell.innerHTML = innerHTML;
                }
            }

            var note = '';
            var value = '';
            if (this._logo.noteStatus[turtle] != null) {
                var notes = this._logo.noteStatus[turtle][0];
                for (var j = 0; j < notes.length; j++) {
                    note += notes[j];
                    note += ' ';
                }
                var value = this._logo.noteStatus[turtle][1];
                if (value > 1) {
                    // FIXME: Do proper conversion of rational to fraction.
                    note += '1/';  // Show note value as fraction.
                    note += value;
                } else {
                    note += 1 / value;
                }
            }

            var cell = table.rows[activeTurtles + 1].cells[i + 1];
            if (cell != null) {
                cell.innerHTML = note.replace(/#/g, '♯').replace(/b/, '♭');
            }

            activeTurtles += 1;
        }
    };
};
<|endoftext|>


<commit_before>$(function() {
  var refresh_ms = 1000 * 60;

  var rowclass = 'rowodd';

  var guid = get_guid();
  var instance = JSON.parse(localStorage.getItem(guid));

  if (!instance || instance === "" || localStorage.getItem(guid) === undefined) {
    instance = {};
  }

  /* get stored symbols out of google sync */
  chrome.storage.sync.get(guid, function(x) {
    var sync_symbols = JSON.parse(x[guid]);
    if (sync_symbols.toString() != instance.symbols.toString()) {
      instance.symbols = sync_symbols;
      instance.lastUpdate = 0;
      getQuotes(instance.symbols);
    }
  });

  if (!instance.symbols) {
    instance.symbols = ['.SPX', '.DJIA', '.IXIC'];
  }

  instance.symbols.forEach(function(symbol) {
    var rowstr = '
';
    rowstr += '' + symbol + "	";
    rowstr += '	';
    rowstr += '	';
    rowstr += '
';
    $('#quotetablebody').append(rowstr);
    rowclass = rowclass == 'rowodd' ? 'roweven' : 'rowodd';
  });

  if (instance.quoteData) {
    updQuotes(instance.quoteData);
  }
  getQuotes(instance.symbols);

  function jqSelector(str) {
    return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
  }

  function get_guid() {
    try {
      if (window.location.hash) {
        return JSON.parse(decodeURIComponent(window.location.hash).substring(1)).id;
      } else {
        return "default";
      }
    } catch (e) {
      return "default";
    }
  }

  function getQuotes(symbols) {
    if (instance.lastUpdate && instance.lastUpdate > new Date().getTime() - refresh_ms) {
      refreshTimer();
      return;
    }
    chrome.extension.sendMessage({
      action: 'getQuote',
      symbols: symbols,
    }, function(response) {
      if (response && response.data) {
        instance.quoteData = response.data;
        instance.lastUpdate = new Date().getTime();
        localStorage.setItem(guid, JSON.stringify(instance));
        updQuotes(instance.quoteData);
        refreshTimer();
      }
    });
  }

  function updQuotes(data, pct) {
    if (typeof pct === 'undefined') {
      pct = false;
    }

    data.forEach(function(quote) {
      $('#last' + jqSelector(quote.symbol)).html(quote.last);

      if (pct) {
        $('#change' + jqSelector(quote.symbol)).html(parseFloat(quote.change_pct).toFixed(2) + '%');
      } else {
        $('#change' + jqSelector(quote.symbol)).html(quote.change);
      }

      if (quote.change < 0) {
        $('#change' + jqSelector(quote.symbol)).toggleClass('green',false);
        $('#change' + jqSelector(quote.symbol)).toggleClass('red',true);
      } else {
        $('#change' + jqSelector(quote.symbol)).toggleClass('green',true);
        $('#change' + jqSelector(quote.symbol)).toggleClass('red',false);
      }

      $('#symbol' + jqSelector(quote.symbol)).html('' + quote.shortName + '');

      $('#change' + jqSelector(quote.symbol)).off('click');
      $('#change' + jqSelector(quote.symbol)).click(function(e) {
        updQuotes(instance.quoteData, !pct);
      });

    });
  }

  function refreshTimer() {
    setTimeout(function() {
      getQuotes(instance.symbols);
    }, refresh_ms);
  }
});<commit_msg>Add listener for chrome.storage sync<commit_after>$(function() {
  var refresh_ms = 1000 * 60;

  var rowclass = 'rowodd';

  var guid = get_guid();
  var instance = JSON.parse(localStorage.getItem(guid));

  if (!instance || instance === "" || localStorage.getItem(guid) === undefined) {
    instance = {};
  }

  /* get stored symbols out of google sync */
  chrome.storage.sync.get(guid, function(x) {
    var sync_symbols = JSON.parse(x[guid]);
    if (sync_symbols.toString() != instance.symbols.toString()) {
      instance.symbols = sync_symbols;
      instance.lastUpdate = 0;
      getQuotes(instance.symbols);
    }
  });

  chrome.storage.onChanged.addListener(function(changes, namespace) {
    if (changes[guid]) {
      var sync_symbols = JSON.parse(changes[guid].newValue);
      if (sync_symbols.toString() != instance.symbols.toString()) {
        instance.symbols = sync_symbols;
        instance.lastUpdate = 0;
        getQuotes(instance.symbols);
      }
    }
  });

  if (!instance.symbols) {
    instance.symbols = ['.SPX', '.DJIA', '.IXIC'];
  }

  instance.symbols.forEach(function(symbol) {
    var rowstr = '
';
    rowstr += '' + symbol + "	";
    rowstr += '	';
    rowstr += '	';
    rowstr += '
';
    $('#quotetablebody').append(rowstr);
    rowclass = rowclass == 'rowodd' ? 'roweven' : 'rowodd';
  });

  if (instance.quoteData) {
    updQuotes(instance.quoteData);
  }
  getQuotes(instance.symbols);

  function jqSelector(str) {
    return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
  }

  function get_guid() {
    try {
      if (window.location.hash) {
        return JSON.parse(decodeURIComponent(window.location.hash).substring(1)).id;
      } else {
        return "default";
      }
    } catch (e) {
      return "default";
    }
  }

  function getQuotes(symbols) {
    if (instance.lastUpdate && instance.lastUpdate > new Date().getTime() - refresh_ms) {
      refreshTimer();
      return;
    }
    chrome.extension.sendMessage({
      action: 'getQuote',
      symbols: symbols,
    }, function(response) {
      if (response && response.data) {
        instance.quoteData = response.data;
        instance.lastUpdate = new Date().getTime();
        localStorage.setItem(guid, JSON.stringify(instance));
        updQuotes(instance.quoteData);
        refreshTimer();
      }
    });
  }

  function updQuotes(data, pct) {
    if (typeof pct === 'undefined') {
      pct = false;
    }

    data.forEach(function(quote) {
      $('#last' + jqSelector(quote.symbol)).html(quote.last);

      if (pct) {
        $('#change' + jqSelector(quote.symbol)).html(parseFloat(quote.change_pct).toFixed(2) + '%');
      } else {
        $('#change' + jqSelector(quote.symbol)).html(quote.change);
      }

      if (quote.change < 0) {
        $('#change' + jqSelector(quote.symbol)).toggleClass('green', false);
        $('#change' + jqSelector(quote.symbol)).toggleClass('red', true);
      } else {
        $('#change' + jqSelector(quote.symbol)).toggleClass('green', true);
        $('#change' + jqSelector(quote.symbol)).toggleClass('red', false);
      }

      $('#symbol' + jqSelector(quote.symbol)).html('' + quote.shortName + '');

      $('#change' + jqSelector(quote.symbol)).off('click');
      $('#change' + jqSelector(quote.symbol)).click(function(e) {
        updQuotes(instance.quoteData, !pct);
      });

    });
  }

  function refreshTimer() {
    setTimeout(function() {
      getQuotes(instance.symbols);
    }, refresh_ms);
  }
});<|endoftext|>


<commit_before>/*
 * Created 2014 Triangle717
 * <http://Triangle717.WordPress.com/>
 *
 * Licensed under The MIT License
 * <http://opensource.org/licenses/MIT/>
 */

function showSidebar() {
  "use strict";
  /* Display the site sidebar */
  $("#sidebar").toggleClass("sidebar-hidden");
}

function showSidebarBtn() {
  "use strict";
  /* Display the site sidebar button */

  $(window).resize(function() {
    if ($(window).width() >= 320 && $(window).width() <= 480 ) {
      $("#sidebar-btn").addClass("sidebar-btn-visible");
      $("#sidebar").addClass("sidebar-hidden");

    } else {
      $("#sidebar-btn").removeClass("sidebar-btn-visible");
      $("#sidebar").removeClass("sidebar-hidden");
    }
  });
}

function shrinkImages() {
  "use strict";
  /* Resize images on mobile devices */

  $("body").find("img").each(function() {
    var $this = $(this);

    // If this is a mobile browser, third non-exempt image sizes
    if ($.browser.mobile) {
      if (!$this.hasClass("no-mobile-resize") && !$this.hasClass("emoji")) {
        // However, do it only if the image is wider than the screen
        console.log($this.width());
        console.log($(window).width());
        if ($this.width() >= $(window).width()) {
          $this.width($this.width() / 3);
          $this.height($this.height() / 3);
        }
      }
    }
  });
}

$(function() {
  "use strict";

  // Display sidebar toggle button if needed
  showSidebarBtn();

  shrinkImages();

  // Replace the SVG with a PNG on IE (IE HATES SVGs)
  if ($.browser.msie) {
    var $imgSrc = $(".ie-svg").attr("src");
    $(".ie-svg").attr("src", $imgSrc.substring(0, $imgSrc.length - 3) + "png");
  }

  // Hide non-mobile-ready elements
  if ($.browser.mobile) {
    $(".no-mobile").css("display", "none");
  }

  // Fully center the items that need centering
  var $centered = $(".fully-centered");
  $centered.css("margin-left", -$centered.width() / 2);
  $centered.css("margin-top", -$centered.height() / 2);

//  // Get date of last commit using GitHub Pages API
//  $.getJSON("https://api.github.com/repos/le717/le717.github.io", function(data) {
//      var lastUpdate = data.updated_at.replace(/(T(.*))$/g, "");
//      //var lastUpdate = "Right now";
//      $("#last-update").text("Last update: {0}".format(lastUpdate));
//    });
});
<commit_msg>[ci skip]<commit_after>/*
 * Created 2014 Triangle717
 * <http://Triangle717.WordPress.com/>
 *
 * Licensed under The MIT License
 * <http://opensource.org/licenses/MIT/>
 */

function showSidebar() {
  "use strict";
  /* Display the site sidebar */
  $("#sidebar").toggleClass("sidebar-hidden");
}

function showSidebarBtn() {
  "use strict";
  /* Display the site sidebar button */

  $(window).resize(function() {
    if ($(window).width() <= 320 && $(window).width() <= 480 ) {
      $("#sidebar-btn").addClass("sidebar-btn-visible");
      $("#sidebar").addClass("sidebar-hidden");

    } else {
      $("#sidebar-btn").removeClass("sidebar-btn-visible");
      $("#sidebar").removeClass("sidebar-hidden");
    }
  });
}

function shrinkImages() {
  "use strict";
  /* Resize images on mobile devices */

  $("body").find("img").each(function() {
    var $this = $(this);

    // If this is a mobile browser, third non-exempt image sizes
    if ($.browser.mobile) {
      if (!$this.hasClass("no-mobile-resize") && !$this.hasClass("emoji")) {
        // However, do it only if the image is wider than the screen
        console.log($this.width());
        console.log($(window).width());
        if ($this.width() >= $(window).width()) {
          $this.width($this.width() / 3);
          $this.height($this.height() / 3);
        }
      }
    }
  });
}

$(function() {
  "use strict";

  // Display sidebar toggle button if needed
  showSidebarBtn();

  shrinkImages();

  // Replace the SVG with a PNG on IE (IE HATES SVGs)
  if ($.browser.msie) {
    var $imgSrc = $(".ie-svg").attr("src");
    $(".ie-svg").attr("src", $imgSrc.substring(0, $imgSrc.length - 3) + "png");
  }

  // Hide non-mobile-ready elements
  if ($.browser.mobile) {
    $(".no-mobile").css("display", "none");
  }

  // Fully center the items that need centering
  var $centered = $(".fully-centered");
  $centered.css("margin-left", -$centered.width() / 2);
  $centered.css("margin-top", -$centered.height() / 2);

//  // Get date of last commit using GitHub Pages API
//  $.getJSON("https://api.github.com/repos/le717/le717.github.io", function(data) {
//      var lastUpdate = data.updated_at.replace(/(T(.*))$/g, "");
//      //var lastUpdate = "Right now";
//      $("#last-update").text("Last update: {0}".format(lastUpdate));
//    });
});
<|endoftext|>


<commit_before>/**
 *  Copyright (C) 2017 3D Repo Ltd
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

"use strict";

const mongoose = require("mongoose");
const schema = mongoose.Schema({
	_id: String,
	color: String
});
const responseCodes = require('../response_codes.js');

const methods = {

	init: function(user, jobs) {

		this.user = user;
		this.jobs = jobs;
		return this;
	},

	findById: function(id){
		return this.jobs.id(id);
	},

	add: function(job) {
		if(!job._id){
			return Promise.reject(responseCodes.JOB_ID_VALID);
		} else if (this.findById(job._id)){
			return Promise.reject(responseCodes.DUP_JOB);
		} else {
			this.jobs.push(job);
			return this.user.save();
		}

	},

	update: function(job) {

		const jobToUpdate = this.findById(job._id);

		if(!job._id){
			return Promise.reject(responseCodes.JOB_ID_VALID);
		}
		else if (!jobToUpdate) {
			return Promise.reject(responseCodes.JOB_NOT_FOUND);
		} else {
			jobToUpdate.color = job.color;
			return this.user.save();
		}

	},

	remove: function(name){

		let job = this.findById(name);

		if(this.user.customData.billing.subscriptions.findByJob(name).length > 0){
			return Promise.reject(responseCodes.JOB_ASSIGNED);
		} else if (!job) {
			return Promise.reject(responseCodes.JOB_NOT_FOUND);
		} else {
			job.remove();
			return this.user.save();
		}

	},

	get: function(){
		return this.jobs;
	}
};

// Mongoose doesn't support subschema static method
module.exports = {
	schema, methods
};

<commit_msg>ISSUE #666 allow jobs used in unseated subscriptions to be deleted.<commit_after>/**
 *  Copyright (C) 2017 3D Repo Ltd
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

"use strict";

const mongoose = require("mongoose");
const schema = mongoose.Schema({
	_id: String,
	color: String
});
const responseCodes = require('../response_codes.js');

const methods = {

	init: function(user, jobs) {

		this.user = user;
		this.jobs = jobs;
		return this;
	},

	findById: function(id){
		return this.jobs.id(id);
	},

	add: function(job) {
		if(!job._id){
			return Promise.reject(responseCodes.JOB_ID_VALID);
		} else if (this.findById(job._id)){
			return Promise.reject(responseCodes.DUP_JOB);
		} else {
			this.jobs.push(job);
			return this.user.save();
		}

	},

	update: function(job) {

		const jobToUpdate = this.findById(job._id);

		if(!job._id){
			return Promise.reject(responseCodes.JOB_ID_VALID);
		}
		else if (!jobToUpdate) {
			return Promise.reject(responseCodes.JOB_NOT_FOUND);
		} else {
			jobToUpdate.color = job.color;
			return this.user.save();
		}

	},

	remove: function(name){

		let job = this.findById(name);
		let isInUse = false;
		this.user.customData.billing.subscriptions.findByJob(name).forEach( sub => {
			//We can ignore empty subscriptions. So only return error code if
			//not empty.
			if(sub.assignedUser) {
				isInUse = true;
			}
		});

		if (!job) {
			return Promise.reject(responseCodes.JOB_NOT_FOUND);
		} else if(isInUse) {
			return Promise.reject(responseCodes.JOB_ASSIGNED);
		}
		else {
			job.remove();
			return this.user.save();
		}

	},

	get: function(){
		return this.jobs;
	}
};

// Mongoose doesn't support subschema static method
module.exports = {
	schema, methods
};

<|endoftext|>


<commit_before>import Client from "../Client.js";

let changeListeners = [];
let coffees = [];
let processings = [];
let productStatuses =[];

let notifyChange = () => {
  changeListeners.forEach((listener) => {
    listener();
  });
}

let fetchCoffees = () => {

  Client.items()
    .type('coffee')
    .orderParameter('elements.product_name')
    .get()
    .subscribe(response => {
      coffees = response.items;
      notifyChange();
    });
}

let fetchFilterProperties = () => {
  Client
    .type('coffee')
    .get()
    .subscribe(response => {
      console.log(response);
      processings = response
        .type
        .elements.find(element => element.codename === "processing")
        .options;
    });
let fetchProcessings = () => {
  Client.taxonomy("processing")
    .get()
    .subscribe(response => {
      processings = response.terms;
      notifyChange();
  });
};

let fetchProductStatuses = () => {
    Client.taxonomy("product_status")
      .get()
      .subscribe(response => {
        productStatuses = response.terms;
        notifyChange();
    });
}

export class Filter {
  constructor() {
    this.processings = [];
    this.productStatuses = [];
  }

  matches(coffee) {
    return this.matchesProcessings(coffee) && this.matchesProductStatuses(coffee);
  }

  matchesProcessings(coffee) {
    if (this.processings.length === 0) {
      return true;
    }

    let processings = coffee.elements.processing.value.map(x => x.codename);

    return this.processings.some(x => processings.includes(x));
  }

  matchesProductStatuses(coffee) {
    if (this.productStatuses.length === 0) {
      return true;
    }

    let statuses = coffee.elements.product_status.value.map(x => x.codename);

    return this.productStatuses.some(x => statuses.includes(x));
  }

  toggleProcessing(processing) {
    let index = this.processings.indexOf(processing);

    if (index < 0) this.processings.push(processing); else this.processings.splice(index, 1);
  }

  toggleProductStatus(status) {
    let index = this.productStatuses.indexOf(status);

    if (index < 0) this.productStatuses.push(status); else this.productStatuses.splice(index, 1);
  }
}

let coffeeFilter = new Filter();

class CoffeeStore {

  // Actions

  provideCoffee(coffeeSlug) {
    fetchCoffees();
  }

  provideCoffees() {
    fetchCoffees();
  }

  provideProcessings() {
    fetchProcessings();
  }

  provideProductStatuses() {
    fetchProductStatuses();
  }

  // Methods

  getCoffee(coffeeSlug) {
    return coffees.find((coffee) => coffee.urlPattern.value === coffeeSlug);
  }

  getCoffees() {
    return coffees;
  }

  getProcessings() {
    return processings;
  }

  getProductStatuses() {
    return productStatuses;
  }

  getFilter() {
    return coffeeFilter;
  }

  setFilter(filter) {
    coffeeFilter = filter;
    notifyChange();
  }

  // Listeners

  addChangeListener(listener) {
    changeListeners.push(listener);
  }

  removeChangeListener(listener) {
    changeListeners = changeListeners.filter((element) => {
      return element !== listener;
    });
  }

}

export default new CoffeeStore();
<commit_msg>remove forgotten consol login<commit_after>import Client from "../Client.js";

let changeListeners = [];
let coffees = [];
let processings = [];
let productStatuses =[];

let notifyChange = () => {
  changeListeners.forEach((listener) => {
    listener();
  });
}

let fetchCoffees = () => {

  Client.items()
    .type('coffee')
    .orderParameter('elements.product_name')
    .get()
    .subscribe(response => {
      coffees = response.items;
      notifyChange();
    });
}

let fetchFilterProperties = () => {
  Client
    .type('coffee')
    .get()
    .subscribe(response => {
      processings = response
        .type
        .elements.find(element => element.codename === "processing")
        .options;
    });
let fetchProcessings = () => {
  Client.taxonomy("processing")
    .get()
    .subscribe(response => {
      processings = response.terms;
      notifyChange();
  });
};

let fetchProductStatuses = () => {
    Client.taxonomy("product_status")
      .get()
      .subscribe(response => {
        productStatuses = response.terms;
        notifyChange();
    });
}

export class Filter {
  constructor() {
    this.processings = [];
    this.productStatuses = [];
  }

  matches(coffee) {
    return this.matchesProcessings(coffee) && this.matchesProductStatuses(coffee);
  }

  matchesProcessings(coffee) {
    if (this.processings.length === 0) {
      return true;
    }

    let processings = coffee.elements.processing.value.map(x => x.codename);

    return this.processings.some(x => processings.includes(x));
  }

  matchesProductStatuses(coffee) {
    if (this.productStatuses.length === 0) {
      return true;
    }

    let statuses = coffee.elements.product_status.value.map(x => x.codename);

    return this.productStatuses.some(x => statuses.includes(x));
  }

  toggleProcessing(processing) {
    let index = this.processings.indexOf(processing);

    if (index < 0) this.processings.push(processing); else this.processings.splice(index, 1);
  }

  toggleProductStatus(status) {
    let index = this.productStatuses.indexOf(status);

    if (index < 0) this.productStatuses.push(status); else this.productStatuses.splice(index, 1);
  }
}

let coffeeFilter = new Filter();

class CoffeeStore {

  // Actions

  provideCoffee(coffeeSlug) {
    fetchCoffees();
  }

  provideCoffees() {
    fetchCoffees();
  }

  provideProcessings() {
    fetchProcessings();
  }

  provideProductStatuses() {
    fetchProductStatuses();
  }

  // Methods

  getCoffee(coffeeSlug) {
    return coffees.find((coffee) => coffee.urlPattern.value === coffeeSlug);
  }

  getCoffees() {
    return coffees;
  }

  getProcessings() {
    return processings;
  }

  getProductStatuses() {
    return productStatuses;
  }

  getFilter() {
    return coffeeFilter;
  }

  setFilter(filter) {
    coffeeFilter = filter;
    notifyChange();
  }

  // Listeners

  addChangeListener(listener) {
    changeListeners.push(listener);
  }

  removeChangeListener(listener) {
    changeListeners = changeListeners.filter((element) => {
      return element !== listener;
    });
  }

}

export default new CoffeeStore();
<|endoftext|>


<commit_before>var port = process.env.PORT || 4000,
    app = require('./app').init(port),
    utils = require('./utils'),
    conf = require('./conf'),
    request = require('request'),
    pageSize = 20;

app.get('/', function(req, res){

    request.get({url:'/api/templates',json:true},function(e,r,b){

        res.render("index",{templates:b.templates,utils:utils});

    });

});

app.get('/api/templates', function(req, res){
    var fs = require('fs');

    //fs.readFile('./static/templates.json', 'utf8', function (err, data) {
    //    res.json(data);
    //});

    //var fileJSON = require('./static/templates.json');
    //res.send(fileJSON);

    fs.readFile('./templates.json', 'utf8', function (err, data) {
        res.send(JSON.parse(data));
    });

    //fs.createReadStream('templates.json').pipe(res);

});

app.get('/:page?', function(req,res){

    var offset = 0
    var page = (req.params.page)||1;

    if (page>1) {
        offset = ((page*pageSize)+1)-pageSize ;
    }

    console.log("page.......");

    request.get({url:'https://api.parse.com/1/classes/Post',json:true,qs:{limit:pageSize,count:1,skip:offset,order:"-createdAt"},headers:{'X-Parse-Application-Id':conf.parse.appKey,'X-Parse-REST-API-Key':conf.parse.restKey}},function(e,r,b){
        if (b.results) {
            res.render("index",{stories:b.results,count:b.count,page:page,utils:utils});
        }
        else {
            //next();
            res.json({error:"no results"});
        }
    });

});

app.get('/tag/:tag/:page?', function(req,res){

    console.log("/tag");

    var tag = req.params.tag;
    var whereClause = {tags:{"$all":[tag]}};
    var offset = 0;
    var page = (req.params.page)||1;

    if (page>1) {
        offset = ((page*pageSize)+1)-pageSize;
    }

    request.get({url:'https://api.parse.com/1/classes/Post',json:true,qs:{limit:pageSize,count:1,where:JSON.stringify(whereClause)},headers:{'X-Parse-Application-Id':conf.parse.appKey,'X-Parse-REST-API-Key':conf.parse.restKey}},function(e,r,b){
        if (b.results && b.results.length>0) {
            res.render("index",{stories:b.results,count:b.count,page:page,utils:utils});
        }
        else {
            res.json({error:"no results for tag"+tag});
            //console.log("no /tag get next");
        }
    });
});

app.post("/post",function(req, res){

    console.log("post /post..");

    var p = req.body;

    request.post({url:'http://in1-api.herokuapp.com/post',json:true,
        body:p}, function (e,r,b){
        console.log("wrote post to in1 api....."+e);

        if (e) {
            res.json({error:"no write"});
        }
        else {
            //var objectId = b.objectId;
            res.json({status:1});
        }

    });
});

/* The 404 Route (ALWAYS Keep this as the last route) */
app.get('/*', function(req, res){
    res.render('404.ejs');
});

<commit_msg>fix json<commit_after>var port = process.env.PORT || 4000,
    app = require('./app').init(port),
    utils = require('./utils'),
    conf = require('./conf'),
    request = require('request'),
    pageSize = 20;

app.get('/', function(req, res){

    request.get({url:'/api/templates',json:true},function(e,r,b){

        res.render("index",{templates:b.templates,utils:utils});

    });

});

app.get('/api/templates', function(req, res){
    var fs = require('fs');

    //fs.readFile('./static/templates.json', 'utf8', function (err, data) {
    //    res.json(data);
    //});

    //var fileJSON = require('./static/templates.json');
    //res.send(fileJSON);

    //fs.readFile('./templates.json', 'utf8', function (err, data) {
    //    res.send(data);
    //});

    fs.createReadStream('templates.json',{flags: 'r', encoding: 'utf-8'}).pipe(res);

});

app.get('/:page?', function(req,res){

    var offset = 0
    var page = (req.params.page)||1;

    if (page>1) {
        offset = ((page*pageSize)+1)-pageSize ;
    }

    console.log("page.......");

    request.get({url:'https://api.parse.com/1/classes/Post',json:true,qs:{limit:pageSize,count:1,skip:offset,order:"-createdAt"},headers:{'X-Parse-Application-Id':conf.parse.appKey,'X-Parse-REST-API-Key':conf.parse.restKey}},function(e,r,b){
        if (b.results) {
            res.render("index",{stories:b.results,count:b.count,page:page,utils:utils});
        }
        else {
            //next();
            res.json({error:"no results"});
        }
    });

});

app.get('/tag/:tag/:page?', function(req,res){

    console.log("/tag");

    var tag = req.params.tag;
    var whereClause = {tags:{"$all":[tag]}};
    var offset = 0;
    var page = (req.params.page)||1;

    if (page>1) {
        offset = ((page*pageSize)+1)-pageSize;
    }

    request.get({url:'https://api.parse.com/1/classes/Post',json:true,qs:{limit:pageSize,count:1,where:JSON.stringify(whereClause)},headers:{'X-Parse-Application-Id':conf.parse.appKey,'X-Parse-REST-API-Key':conf.parse.restKey}},function(e,r,b){
        if (b.results && b.results.length>0) {
            res.render("index",{stories:b.results,count:b.count,page:page,utils:utils});
        }
        else {
            res.json({error:"no results for tag"+tag});
            //console.log("no /tag get next");
        }
    });
});

app.post("/post",function(req, res){

    console.log("post /post..");

    var p = req.body;

    request.post({url:'http://in1-api.herokuapp.com/post',json:true,
        body:p}, function (e,r,b){
        console.log("wrote post to in1 api....."+e);

        if (e) {
            res.json({error:"no write"});
        }
        else {
            //var objectId = b.objectId;
            res.json({status:1});
        }

    });
});

/* The 404 Route (ALWAYS Keep this as the last route) */
app.get('/*', function(req, res){
    res.render('404.ejs');
});

<|endoftext|>


<commit_before>"use strict";

// Load libraries.
var _ = require('underscore');
var wordfilter = require('wordfilter');
var languageDetector = require('cld');
var SC = require('node-soundcloud');
var Twit = require('twit');

// Are we on production? Check if an important environment variable exists.
function isProduction () {
  return (typeof(process.env.TWITTER_CONSUMER_KEY) !== 'undefined');
}

// Use environment variables if we're on production, config files if we're local.
if (isProduction()) {
  SC.init({
    id:     process.env.SOUNDCLOUD_CLIENT_ID,
    secret: process.env.SOUNDCLOUD_SECRET
  });

  var twitter = new Twit({
    consumer_key: process.env.TWITTER_CONSUMER_KEY,
    consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
    access_token: process.env.TWITTER_ACCESS_TOKEN,
    access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
  });
}
else {
  SC.init(require('./soundcloud-config.js'));
  var twitter = new Twit(require('./twitter-config.js'));
}

// Get a handful of comments and choose one.
function makeAndPostTweet () {
  getRandomComment().then(function (results) {
    postTweet(results);
  }).catch(function (err) {
    console.log('ERROR:', err);
    makeAndPostTweet();
  });
}

// Pick a random comment. The API doesn't provide for this, but SoundCloud
// comment IDs are sequential! There are a lot of missing comments (deleted
// spam, etc.), but this has about a 40-50% success rate at finding an actual
// comment, which ain't bad!
function getRandomCommentID () {
  return String(_.random(100000000, 300000000));
}

function getRandomComment () {

  return new Promise (function (resolve, reject) {

    console.log('\n---\n');

    SC.get('/comments/' + getRandomCommentID(), function(err, comment) {
      // console.log('\n\nFULL RESPONSE:\n\n', comment)

      if (typeof(err) !== 'undefined') {
        reject('Comment does not exist.');
      }
      else {
        var comment = comment.body.trim();

        console.log('FOUND A COMMENT:', comment);

        if (comment.length < 1) {
          reject('Comment is too short.');
          return;
        }

        if (comment.length > 141) {
          reject('Comment is too long');
          return;
        }

        if (!isEnglish(comment)) {
          reject('Comment is not in English.');
          return;
        }

        if (wordfilter.blacklisted(comment)) {
          reject('Comment is a reply, contains a bad word, or looks like spam.');
          return;
        }

        console.log('COMMENT IS USEABLE!');

        resolve(comment);
      }

    });

  });

}

function postTweet (tweet) {

  console.log('TWEET:', tweet);

  if (isProduction()) {
    twitter.post('statuses/update', { status: tweet }, function (error) {
      if (error) {
        console.log('ERROR POSTING TWEET:', error);
      }
    });
  }

}

// Tweet on a regular schedule. 8 times a day means every 3 hours. Note that
// Because Heroku cycles dynos once per day, the bot's schedule will not be
// regular: https://devcenter.heroku.com/articles/how-heroku-works#dyno-manager
if (isProduction()) {
  var timesToTweetPerDay = 8;

  setInterval(function () {
    try {
      postTweet();
    }
    catch (err) {
      console.log('PROCESS UNSUCCESSFUL!', err);
    }
  }, (1000 * 60 * 60 * 24) / timesToTweetPerDay);
}

// Go!
makeAndPostTweet();

///

// Is this English?
function isEnglish (string) {

  var options = {
    isHTML       : false,
    encodingHint : 'UTF8UTF8',
    tldHint      : 'com'
  };

  return languageDetector.detect(string, options, function(err, result) {

    if (!_.isEmpty(err)) {
      console.log('LANGUAGE DETECTION ERROR:', err.message);

      // If the language couldn't be detected, just show the tweet. Most of the
      // time this means it's slang or internet-speak and is fine to print.
      if (err.message === 'Failed to identify language') {
        console.log('LANGUAGE DETECTION OVERRIDE: Approving as English anyway, just for kicks.');

        return true;
      }
    }
    else {
      return (result.languages[0].name === 'ENGLISH');
    }

  });

}

// Additional filters.
wordfilter.addWords([

  // To get a better set of comments, I'm filtering out a lot of things.
  // The lists below are used in addition to the default set:
  // https://github.com/dariusk/wordfilter/blob/master/lib/badwords.json

  // Spam.
  'follow',
  'listen to my',
  'check out',
  'subscribe',
  'channel',
  'my cloud',

  'facebook',
  'soundcloud',
  'youtube',
  'instagram',
  'blog',

  'http',
  'www',
  '.co',
  '.net',

  'sex',
  'cam',
  'dollars',

  'free',
  'download',
  'DL',

  // Replies, SoundCloud links, tags, etc.
  'user-',
  '\@',
  '\n',
  '_',
  '#',

  // A few curses.
  'fuck'
]);
<commit_msg>Allow tweeting from local machine is variable is set.<commit_after>"use strict";

// Local tweet test override.
// var canTweetFromLocal = true;

// Load libraries.
var _ = require('underscore');
var wordfilter = require('wordfilter');
var languageDetector = require('cld');
var SC = require('node-soundcloud');
var Twit = require('twit');

// Are we on production? Check if an important environment variable exists.
function isProduction () {
  return (typeof(process.env.TWITTER_CONSUMER_KEY) !== 'undefined');
}

// Use environment variables if we're on production, config files if we're local.
if (isProduction()) {
  SC.init({
    id:     process.env.SOUNDCLOUD_CLIENT_ID,
    secret: process.env.SOUNDCLOUD_SECRET
  });

  var twitter = new Twit({
    consumer_key: process.env.TWITTER_CONSUMER_KEY,
    consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
    access_token: process.env.TWITTER_ACCESS_TOKEN,
    access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET
  });
}
else {
  SC.init(require('./soundcloud-config.js'));
  var twitter = new Twit(require('./twitter-config.js'));
}

// Get a handful of comments and choose one.
function makeAndPostTweet () {
  getRandomComment().then(function (results) {
    postTweet(results);
  }).catch(function (err) {
    console.log('ERROR:', err);
    makeAndPostTweet();
  });
}

// Pick a random comment. The API doesn't provide for this, but SoundCloud
// comment IDs are sequential! There are a lot of missing comments (deleted
// spam, etc.), but this has about a 40-50% success rate at finding an actual
// comment, which ain't bad!
function getRandomCommentID () {
  return String(_.random(100000000, 300000000));
}

function getRandomComment () {

  return new Promise (function (resolve, reject) {

    console.log('\n---\n');

    SC.get('/comments/' + getRandomCommentID(), function(err, comment) {
      // console.log('\n\nFULL RESPONSE:\n\n', comment)

      if (typeof(err) !== 'undefined') {
        reject('Comment does not exist.');
      }
      else {
        var comment = comment.body.trim();

        console.log('FOUND A COMMENT:', comment);

        if (comment.length < 1) {
          reject('Comment is too short.');
          return;
        }

        if (comment.length > 141) {
          reject('Comment is too long');
          return;
        }

        if (!isEnglish(comment)) {
          reject('Comment is not in English.');
          return;
        }

        if (wordfilter.blacklisted(comment)) {
          reject('Comment is a reply, contains a bad word, or looks like spam.');
          return;
        }

        console.log('COMMENT IS USEABLE!');

        resolve(comment);
      }

    });

  });

}

function postTweet (tweet) {

  console.log('TWEET:', tweet);

  if (isProduction() || canTweetFromLocal) {
    twitter.post('statuses/update', { status: tweet }, function (error) {
      if (error) {
        console.log('ERROR POSTING TWEET:', error);
      }
    });
  }

}

// Tweet on a regular schedule. 8 times a day means every 3 hours. Note that
// Because Heroku cycles dynos once per day, the bot's schedule will not be
// regular: https://devcenter.heroku.com/articles/how-heroku-works#dyno-manager
if (isProduction()) {
  var timesToTweetPerDay = 8;

  setInterval(function () {
    try {
      postTweet();
    }
    catch (err) {
      console.log('PROCESS UNSUCCESSFUL!', err);
    }
  }, (1000 * 60 * 60 * 24) / timesToTweetPerDay);
}

// Go!
makeAndPostTweet();

///

// Is this English?
function isEnglish (string) {

  var options = {
    isHTML       : false,
    encodingHint : 'UTF8UTF8',
    tldHint      : 'com'
  };

  return languageDetector.detect(string, options, function(err, result) {

    if (!_.isEmpty(err)) {
      console.log('LANGUAGE DETECTION ERROR:', err.message);

      // If the language couldn't be detected, just show the tweet. Most of the
      // time this means it's slang or internet-speak and is fine to print.
      if (err.message === 'Failed to identify language') {
        console.log('LANGUAGE DETECTION OVERRIDE: Approving as English anyway, just for kicks.');

        return true;
      }
    }
    else {
      return (result.languages[0].name === 'ENGLISH');
    }

  });

}

// Additional filters.
wordfilter.addWords([

  // To get a better set of comments, I'm filtering out a lot of things.
  // The lists below are used in addition to the default set:
  // https://github.com/dariusk/wordfilter/blob/master/lib/badwords.json

  // Spam.
  'follow',
  'listen to my',
  'check out',
  'check my',
  'subscribe',
  'channel',
  'my cloud',

  'facebook',
  'soundcloud',
  'youtube',
  'instagram',
  'blog',

  'http',
  'www',
  '.co',
  '.net',

  'sex',
  'cam',
  'dollars',

  'free',
  'download',
  'DL',

  // Replies, SoundCloud links, tags, etc.
  'user-',
  '\@',
  '\n',
  '_',
  '#',

  // A few curses.
  'fuck'

]);
<|endoftext|>


<commit_before>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.a<commit_msg>Update character<commit_after>var fs = require('fs');
var child_process = require('child_process')
var max_sleep = 300

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.ar<|endoftext|>


<commit_before>var React = require("react")

export default class Errors extends React.Component {
  displayName = "FriggingBootstrap.Errors"

  static defaultProps = require("../default_props.js")

  render() {
    return (

        {
          (this.props.errors||[]).map((error) => {
            return (
              <div className="col-xs-12" key={`error-${error}`}>
                <div className="frigb-error" ref={`error-${error}`}>

                    Error:
                    {` ${error}`}

            )
          })
        }

    )
  }

}
<commit_msg>Errors component's props.errors must be an array<commit_after>var React = require("react")

export default class Errors extends React.Component {
  displayName = "FriggingBootstrap.Errors"

  static defaultProps = require("../default_props.js")

  static propTypes = {
    errors: React.PropTypes.array.isRequired,
  }

  render() {
    const {errors} = this.props
    return (

        {
          errors.map((error) =>
            <div className="col-xs-12" key={`error-${error}`}>
              <div className="frigb-error" ref={`error-${error}`}>

                  Error:
                  {` ${error}`}

          )
        }

    )
  }
}
<|endoftext|>


<commit_before>import { expect } from 'chai';
import * as utils from '../test/utils';

import config from 'config';
config.clearbit = { key: '***' };

import userlib from '../server/lib/userlib';
import sinon from 'sinon';
import Bluebird from 'bluebird';
import mock from './mocks/clearbit';

/**
 * Variables.
 */
const userData1 = utils.data('user1');
const userData3 = utils.data('user3');

describe('userlib', () => {
  let sandbox, stub;
  beforeEach(() => {
    userlib.memory = {};
    sandbox = sinon.createSandbox();
    stub = sandbox.stub(userlib.clearbit.Enrichment, 'find').callsFake(opts => {
      return new Bluebird((resolve, reject) => {
        switch (opts.email) {
          case userData1.email: {
            const NotFound = new userlib.clearbit.Enrichment.NotFoundError(' NotFound');
            reject(NotFound);
            break;
          }
          case userData3.email:
            return resolve(mock);
          default:
            return reject(new Error());
        }
      });
    });
  });

  afterEach(() => sandbox.restore());

  it("doesn't call clearbit if email invalid", () =>
    userlib.fetchAvatar('email.com').then(() => expect(stub.called).to.be.false));

  it("can't fetch the image of an unknown email", () =>
    userlib.fetchAvatar(userData1.email).then(image => {
      expect(userlib.memory).to.have.property(userData1.email);
      expect(stub.callCount).to.equal(1);
      expect(image).to.equal(null);
    }));

  it('only calls clearbit server once for an email not found', () =>
    userlib
      .fetchAvatar(userData1.email)
      .then(() => userlib.fetchAvatar(userData1.email))
      .then(image => {
        expect(stub.callCount).to.equal(1);
        expect(image).to.be.falsy;
        expect(image).to.equal(null);
      }));
});
<commit_msg>fix(test): remove to.be.falsy<commit_after>import { expect } from 'chai';
import * as utils from '../test/utils';

import config from 'config';
config.clearbit = { key: '***' };

import userlib from '../server/lib/userlib';
import sinon from 'sinon';
import Bluebird from 'bluebird';
import mock from './mocks/clearbit';

/**
 * Variables.
 */
const userData1 = utils.data('user1');
const userData3 = utils.data('user3');

describe('userlib', () => {
  let sandbox, stub;
  beforeEach(() => {
    userlib.memory = {};
    sandbox = sinon.createSandbox();
    stub = sandbox.stub(userlib.clearbit.Enrichment, 'find').callsFake(opts => {
      return new Bluebird((resolve, reject) => {
        switch (opts.email) {
          case userData1.email: {
            const NotFound = new userlib.clearbit.Enrichment.NotFoundError(' NotFound');
            reject(NotFound);
            break;
          }
          case userData3.email:
            return resolve(mock);
          default:
            return reject(new Error());
        }
      });
    });
  });

  afterEach(() => sandbox.restore());

  it("doesn't call clearbit if email invalid", () =>
    userlib.fetchAvatar('email.com').then(() => expect(stub.called).to.be.false));

  it("can't fetch the image of an unknown email", () =>
    userlib.fetchAvatar(userData1.email).then(image => {
      expect(userlib.memory).to.have.property(userData1.email);
      expect(stub.callCount).to.equal(1);
      expect(image).to.equal(null);
    }));

  it('only calls clearbit server once for an email not found', () =>
    userlib
      .fetchAvatar(userData1.email)
      .then(() => userlib.fetchAvatar(userData1.email))
      .then(image => {
        expect(stub.callCount).to.equal(1);
        expect(image).to.equal(null);
      }));
});
<|endoftext|>


<commit_before>module.exports = function( req, res ) {
  res.json({
    http: "okay"
  });
};
<commit_msg>[bug 886515] Added version info to healthcheck route<commit_after>var version = require( "../../package" ).version;

module.exports = function( req, res ) {
  res.json({
    http: "okay",
    version: version
  });
};
<|endoftext|>


<commit_before>/**
 * Pulsar
 *
 * Core UI components that should always be present.
 *
 * Jadu Ltd.
 */

// Fixes issue with dependencies that expect both $ and jQuery to be set
window.jQuery = window.$ = require('jquery');

// Global UI components
var $          = require('jquery'),
    deck       = require('./deck'),
    dropdown   = require('./dropdown'),
    modal      = require('./modal'),
    tab        = require('./tab'),
    popover    = require('./popover'),
    tooltip    = require('./tooltip'),

    clickover  = require('../libs/bootstrapx-clickover/js/bootstrapx-clickover'),
    datatables = require('../libs/datatables/media/js/jquery.dataTables.min'),
    responsive = require('../libs/datatables-responsive/js/dataTables.responsive'),
    svgeezy    = require('../libs/svgeezy/svgeezy.min'),
    select2    = require('../libs/select2/dist/js/select2.min'),
    TableTools = require('../libs/datatables-tabletools/js/dataTables.tableTools'),
    toggles    = require('../libs/jquery-toggles/toggles.min'),

    ButtonComponent = require('./ButtonComponent'),
    FlashMessageComponent = require('./FlashMessageComponent'),
    MasterSwitchComponent = require('./MasterSwitchComponent'),
    NavMainComponent = require('./NavMainComponent'),
    PulsarFormComponent = require('./PulsarFormComponent'),
    SignInComponent = require('./area/signin/signin');

module.exports = {
    ButtonComponent: ButtonComponent,
    FlashMessageComponent: FlashMessageComponent,
    MasterSwitchComponent: MasterSwitchComponent,
    NavMainComponent: NavMainComponent,
    PulsarFormComponent: PulsarFormComponent,
    SignInComponent: SignInComponent,
    svgeezy: svgeezy
};
<commit_msg>Included matchMedia polyfil and new help sidebar<commit_after>/**
 * Pulsar
 *
 * Core UI components that should always be present.
 *
 * Jadu Ltd.
 */

// Fixes issue with dependencies that expect both $ and jQuery to be set
window.jQuery = window.$ = require('jquery');

// Global UI components
var $                     = require('jquery'),
    deck                  = require('./deck'),
    dropdown              = require('./dropdown'),
    modal                 = require('./modal'),
    tab                   = require('./tab'),
    popover               = require('./popover'),
    tooltip               = require('./tooltip'),
    matchMedia            = require('./polyfills/matchMedia'),
    matchMediaAddListener = require('./polyfills/matchMedia.addListener');

    clickover  = require('../libs/bootstrapx-clickover/js/bootstrapx-clickover'),
    datatables = require('../libs/datatables/media/js/jquery.dataTables.min'),
    responsive = require('../libs/datatables-responsive/js/dataTables.responsive'),
    svgeezy    = require('../libs/svgeezy/svgeezy.min'),
    select2    = require('../libs/select2/dist/js/select2.min'),
    TableTools = require('../libs/datatables-tabletools/js/dataTables.tableTools'),
    toggles    = require('../libs/jquery-toggles/toggles.min'),

    ButtonComponent = require('./ButtonComponent'),
    HelpTextComponent = require('./HelpTextComponent'),
    FlashMessageComponent = require('./FlashMessageComponent'),
    MasterSwitchComponent = require('./MasterSwitchComponent'),
    NavMainComponent = require('./NavMainComponent'),
    PulsarFormComponent = require('./PulsarFormComponent'),
    SignInComponent = require('./area/signin/signin');

module.exports = {
    ButtonComponent: ButtonComponent,
    HelpTextComponent: HelpTextComponent,
    FlashMessageComponent: FlashMessageComponent,
    MasterSwitchComponent: MasterSwitchComponent,
    NavMainComponent: NavMainComponent,
    PulsarFormComponent: PulsarFormComponent,
    SignInComponent: SignInComponent,
    svgeezy: svgeezy
};
<|endoftext|>


<commit_before>(function() {
'use strict';

var _ = Timeline.helpers;

function Stream(options) {
	_.copy(this, Stream.source[options.type]);

	this.vars = {};
	_.copy(this.vars, options);

	this.buffer = [];

	this.results = {
		max: 0,
		min: 0,
	};

	if (this.options.paginate)
		this.vars.page = 0;

	var self = this;
	setTimeout(function() {
		self.fill(self.ready);
	}, 1);
}

Stream.type = {};
Stream.source = {};

Stream.prototype.poll = function(callback) {
	this.request('poll', callback);
};

Stream.prototype.fill = function(callback) {
	var self = this;
	this.request(this.results.min ? 'refill' : 'fill', function(messages) {
		self.buffer = messages;
		callback();
	});
};

Stream.prototype.request = function(action, callback) {
	var path;
	action = action || 'fill';

	if (typeof this.options.action == 'string')
		path = this.options.action;
	else
		path = this.options.action[action] || this.options.action['fill'];

	if (this.options.paginate)
		this.vars.page++;

	this.get(_.template(path, this.vars), function(data) {
		var self = this;
		var messages = [];
		var events = this.getEvents(data);

		events.forEach(function(event) {
			var id = self.getEventID(event);
			var message;

			if (action == 'poll' && id < self.results.max)
				return;

			if (action == 'refill' && id > self.results.min)
				return;

			if (!(message = self.getEventMessage(event)))
				return;

			messages.push({
				type: self.vars.type,
				date: self.getEventDate(event),
				message: message,
				link: self.getEventLink(event),
			});
		});

		if (!this.results.max || action == 'poll')
			this.results.max = this.getEventID(events[0]);

		if (!this.results.min || action == 'fill' || action == 'refill')
			this.results.min = this.getEventID(events[events.length - 1]);

		if (typeof callback == 'function')
			callback(messages);
	});
};

/**
 * Get the date for the current message
 * @returns {integer} Date when message was published
 */
Stream.prototype.current = function() {
	if (this.buffer.length)
		return this.buffer[0].date;

	return 0;
};

/**
 * Get the next message in our stream
 * @param {function} callback(message)  Callback with message
 */
Stream.prototype.shift = function(callback) {
	if (this.buffer.length <= 1 && (!this.options.paginate || (this.options.paginate !== true && this.vars.page < this.options.paginate)))
		return this.fill(this.shift.bind(this, callback));
	else if (this.empty())
		return;

	callback(this.buffer.shift());
};

/**
 * Find out if the stream is empty
 * @returns {boolean} True if empty, false otherwise
 */
Stream.prototype.empty = function() {
	return !this.buffer.length &&
	       this.options.paginate &&
	       this.options.paginate !== true &&
	       this.vars.page >= this.options.paginate;
};

/**
 * Generates a global callback from a callback
 *
 * @param {function} callback  Thing to ring
 * @returns {string} Our callback
 */
Stream.prototype._callback = function(callback) {
	var cb = 'timeline_cb_' + Math.random().toString().substr(2);
	var self = this;

	window[cb] = function() {
		callback.apply(self, arguments);
		delete window[cb];
	};

	return cb;
};

Stream.prototype._params = function() {
	var self = this;
	var params = '';

	Object.keys(this.params).forEach(function(key) {
		var val = self.params[key];

		if (typeof val == 'function')
			val = val.call(self);

		if (val == undefined)
			return;

		params += '&' + key + '=' + _.template(val, self.vars);
	});

	return '?' + params.substr(1);
};

Stream.prototype.get = function(path, callback) {
	var url = this.options.url + path + this._params();

	if (this.options.response == 'jsonp') {
		var s = document.createElement('script');
		s.src = url.replace(/([?&][^=]+=)\?(&|$)/, '$1' + this._callback(callback) + '$2');
		document.body.appendChild(s);
	} else {
		var xhr = new XMLHttpRequest();
		xhr.open('GET', url);
		xhr.send();

		var self = this;
		xhr.onreadystatechange = function() {
			if (xhr.readyState == 4 && xhr.status == 200)
				callback.call(self, self.options.response == 'xml' ? xhr.responseXML : JSON.parse(xhr.responseText));
		};
	}
};

Timeline.Stream = Stream;
})();
<commit_msg>Fix pagination<commit_after>(function() {
'use strict';

var _ = Timeline.helpers;

function Stream(options) {
	_.copy(this, Stream.source[options.type]);

	this.vars = {};
	_.copy(this.vars, options);

	this.buffer = [];

	this.results = {
		max: 0,
		min: 0,
	};

	if (this.options.paginate)
		this.vars.page = 0;

	var self = this;
	setTimeout(function() {
		self.fill(self.ready);
	}, 1);
}

Stream.type = {};
Stream.source = {};

Stream.prototype.poll = function(callback) {
	this.request('poll', callback);
};

Stream.prototype.fill = function(callback) {
	var self = this;
	this.request(this.results.min ? 'refill' : 'fill', function(messages) {
		self.buffer = messages;
		callback();
	});
};

Stream.prototype.request = function(action, callback) {
	var path;
	action = action || 'fill';

	if (typeof this.options.action == 'string')
		path = this.options.action;
	else
		path = this.options.action[action] || this.options.action['fill'];

	if (this.options.paginate)
		this.vars.page++;

	this.get(_.template(path, this.vars), action, function(data) {
		var self = this;
		var messages = [];
		var events = this.getEvents(data);

		events.forEach(function(event) {
			var id = self.getEventID(event);
			var message;

			if (action == 'poll' && id < self.results.max)
				return;

			if (action == 'refill' && id > self.results.min)
				return;

			if (!(message = self.getEventMessage(event)))
				return;

			messages.push({
				type: self.vars.type,
				date: self.getEventDate(event),
				message: message,
				link: self.getEventLink(event),
			});
		});

		if (!this.results.max || action == 'poll')
			this.results.max = this.getEventID(events[0]);

		if (!this.results.min || action == 'fill' || action == 'refill')
			this.results.min = this.getEventID(events[events.length - 1]);

		if (typeof callback == 'function')
			callback(messages);
	});
};

/**
 * Get the date for the current message
 * @returns {integer} Date when message was published
 */
Stream.prototype.current = function() {
	if (this.buffer.length)
		return this.buffer[0].date;

	return 0;
};

/**
 * Get the next message in our stream
 * @param {function} callback(message)  Callback with message
 */
Stream.prototype.shift = function(callback) {
	if (this.buffer.length <= 1 && (!this.options.paginate || (this.options.paginate !== true && this.vars.page < this.options.paginate)))
		return this.fill(this.shift.bind(this, callback));
	else if (this.empty())
		return;

	callback(this.buffer.shift());
};

/**
 * Find out if the stream is empty
 * @returns {boolean} True if empty, false otherwise
 */
Stream.prototype.empty = function() {
	return !this.buffer.length &&
	       this.options.paginate &&
	       this.options.paginate !== true &&
	       this.vars.page >= this.options.paginate;
};

/**
 * Generates a global callback from a callback
 *
 * @param {function} callback  Thing to ring
 * @returns {string} Our callback
 */
Stream.prototype._callback = function(callback) {
	var cb = 'timeline_cb_' + Math.random().toString().substr(2);
	var self = this;

	window[cb] = function() {
		callback.apply(self, arguments);
		delete window[cb];
	};

	return cb;
};

Stream.prototype._params = function(action) {
	var self = this;
	var params = '';

	Object.keys(this.params).forEach(function(key) {
		var val = self.params[key];

		if (typeof val == 'function')
			val = val.call(self, action);

		if (val == undefined)
			return;

		params += '&' + key + '=' + _.template(val, self.vars);
	});

	return '?' + params.substr(1);
};

Stream.prototype.get = function(path, action, callback) {
	var url = this.options.url + path + this._params(arguments.length == 3 ? action : '');

	if (typeof callback == 'undefined')
		callback = action;

	if (this.options.response == 'jsonp') {
		var s = document.createElement('script');
		s.src = url.replace(/([?&][^=]+=)\?(&|$)/, '$1' + this._callback(callback) + '$2');
		document.body.appendChild(s);
	} else {
		var xhr = new XMLHttpRequest();
		xhr.open('GET', url);
		xhr.send();

		var self = this;
		xhr.onreadystatechange = function() {
			if (xhr.readyState == 4 && xhr.status == 200)
				callback.call(self, self.options.response == 'xml' ? xhr.responseXML : JSON.parse(xhr.responseText));
		};
	}
};

Timeline.Stream = Stream;
})();
<|endoftext|>


<commit_before>/* Import our Node.js modules */
const gulp = require('gulp'),
    cssmin = require('gulp-cssmin'),
    environments = require('gulp-environments'),
    gulpif = require('gulp-if'),
    imagemin = require('gulp-imagemin'),
    less = require('gulp-less'),
    sass = require('gulp-sass'),
    postcss = require('gulp-postcss'),
    rename = require('gulp-rename'),
    rimraf = require('rimraf'),
    sourcemaps = require('gulp-sourcemaps'),
    path = require('path'),
    config = require('./gulpfile-config');

/* Declare our environments */
const development = environments.development,
    staging = environments.make('staging'),
    production = environments.production;

/* Set gulp.series and gulp.parallel to constants for convenience sake */
const series = gulp.series,
    parallel = gulp.parallel;

/* Extract some config properties for convenience */
const shouldAddSourcemaps = config.sourcemaps,
    shouldMinify = config.minify;

/* Declare our gulp tasks */
gulp.task('build', series(clean, parallel(series(styles, minifyStyles), images)));
gulp.task('default', series('build', watch));

/* Describe our gulp tasks */
gulp.task('build').description = 'Clean out the build folder then compile styles, minify images, and copy assets into the build folder';
gulp.task('default').description = 'Run the build task and watch for any changes';

function clean(done) {
    rimraf(config.buildDir, done);
}
clean.description = 'Cleans the build folder';

function styles() {
    let sConfig = config.styles,
        files = sConfig.sourceFiles,
        source = sConfig.sourceDir,
        dest = sConfig.destinationDir,
        mapsDir = sConfig.mapsDir,
        postcssConfig = sConfig.postcss;

    return compileLess(source, dest, files, mapsDir, postcssConfig);
}
styles.description = 'Compiles SCSS files to CSS; adds source maps if specified';

function minifyStyles(done) {
    if (shouldMinify) {
        let dir = config.styles.destinationDir;
        return minifyCSS(dir, dir, false);
    }
    done();
}
minifyStyles.description = 'Minify CSS files';

function images() {
    let iConfig = config.images,
        sourceDir = iConfig.sourceDir,
        destDir = iConfig.destinationDir;

    return minifyImages(sourceDir, destDir);
}
images.description = 'Minify images back into the same (source) folder';

function watch(done) {
    if (development()) {
        gulp.watch(config.styles.sourceFiles, styles);
    }
    done();
}
watch.description = 'Watch relevant files and re-run their tasks (only in development environment)';

/**
 * Generic function to compile LESS files
 * @param {String} sourceDir a string representing the path to the directory for the LESS files
 * @param {String} destDir a string representing the path to the directory where the compiled files would be saved
 * @param {String|Array} files string or array of strings representing the glob match for the source files
 * @param {String} mapsDir the directory where sourcemaps would be stored (relative to the destination directory)
 * @param {Array} postcssConfig an array of postcss processors
 * @returns {*} the gulp stream
 */
function compileLess(sourceDir, destDir, files, mapsDir, postcssConfig) {
    return compileStyles(sourceDir, destDir, files, mapsDir, less, postcssConfig);
}

/**
 * Generic function to compile Sass files
 * @param {String} sourceDir a string representing the path to the directory for the Sass files
 * @param {String} destDir a string representing the path to the directory where the compiled files would be saved
 * @param {String|Array} files string or array of strings representing the glob match for the source files
 * @param {String} mapsDir the directory where sourcemaps would be stored (relative to the destination directory)
 * @param {Array} postcssConfig an array of postcss processors
 * @returns {*} the gulp stream
 */
function compileSass(sourceDir, destDir, files, mapsDir, postcssConfig) {
    return compileStyles(sourceDir, destDir, files, mapsDir, function () {
        return sass().on('error', sass.logError);
    }, postcssConfig);
}

/**
 * A generic function to compile both LESS and Sass files
 * @param {String} sourceDir a string representing the path to the directory for the source files
 * @param {String} destDir a string representing the path to the directory where the compiled files would be saved
 * @param {String|Array} files string or array of strings representing the glob match for the source files
 * @param {String} mapsDir the directory where sourcemaps would be stored (relative to the destination directory)
 * @param {Function} buildFxn the build function to use. could be less or sass functions
 * @param {Array} postcssConfig an array of postcss processors
 */
function compileStyles(sourceDir, destDir, files, mapsDir, buildFxn, postcssConfig) {
    return gulp.src(files, {base: sourceDir})
        .pipe(gulpif(shouldAddSourcemaps, sourcemaps.init()))
        .pipe(buildFxn())
        .pipe(postcss(postcssConfig))
        .pipe(gulpif(shouldAddSourcemaps, sourcemaps.write(mapsDir)))
        .pipe(gulp.dest(destDir));
}

/**
 * A generic function to copy files/directories to a different directory
 * @param {String|Array} source a string or array of string representing the glob match for the source files/folders
 * @param {String} destination the new directory to copy
 */
function copy(source, destination) {
    return gulp.src(source)
        .pipe(gulp.dest(destination));
}

/**
 * Generic function to minify CSS files
 * @param {string} sourceDir a string representing the path to the directory for the source files
 * @param {string} destDir a string representing the path to the directory where the minified files would be saved
 * @param {boolean} shouldRename determine whether the new file should be renamed or not
 * @returns {*} the gulp stream
 */
function minifyCSS(sourceDir, destDir, shouldRename) {
    let files = [path.join(sourceDir, '**/*.css'), path.join('!' + sourceDir, '**/*.min.css')];
    return minify(files, destDir, cssmin, shouldRename);
}

/**
 * A generic function to minify images
 * @param {string} sourceDir a string representing the path to the directory for the source files
 * @param {string} destDir a string representing the path to the directory where the minified files would be saved
 * @returns {*} the gulp stream
 */
function minifyImages(sourceDir, destDir) {
    let files = path.join(sourceDir, '**/*');
    return minify(files, destDir, imagemin, false);
}

/**
 * A generic function to minify different types of files
 * @param {string|array} source a string or array of strings representing the glob match for the source files/folders
 * @param {string} destDir a string representing the path to the directory where the minified files would be saved
 * @param {function} minifyFxn the minify function to use
 * @param {boolean} shouldRename determine whether the new file should be renamed or not
 */
function minify(source, destDir, minifyFxn, shouldRename) {
    if ('undefined' === typeof shouldRename) {
        shouldRename = true;
    }
    return gulp.src(source)
        .pipe(minifyFxn())
        .pipe(gulpif((shouldRename), rename({suffix: '.min'})))
        .pipe(gulp.dest(destDir));
}
<commit_msg>Modified the gulp build task<commit_after>/* Import our Node.js modules */
const gulp = require('gulp'),
    cssmin = require('gulp-cssmin'),
    environments = require('gulp-environments'),
    gulpif = require('gulp-if'),
    imagemin = require('gulp-imagemin'),
    less = require('gulp-less'),
    sass = require('gulp-sass'),
    postcss = require('gulp-postcss'),
    rename = require('gulp-rename'),
    rimraf = require('rimraf'),
    sourcemaps = require('gulp-sourcemaps'),
    path = require('path'),
    config = require('./gulpfile-config');

/* Declare our environments */
const development = environments.development,
    staging = environments.make('staging'),
    production = environments.production;

/* Set gulp.series and gulp.parallel to constants for convenience sake */
const series = gulp.series,
    parallel = gulp.parallel;

/* Extract some config properties for convenience */
const shouldAddSourcemaps = config.sourcemaps,
    shouldMinify = config.minify;

/* Declare our gulp tasks */
gulp.task('build', parallel(series(styles, minifyStyles), images));
gulp.task('default', series('build', watch));

/* Describe our gulp tasks */
gulp.task('build').description = 'Clean out the build folder then compile styles, minify images, and copy assets into the build folder';
gulp.task('default').description = 'Run the build task and watch for any changes';

function clean(done) {
    rimraf(config.buildDir, done);
}
clean.description = 'Cleans the build folder';

function styles() {
    let sConfig = config.styles,
        files = sConfig.sourceFiles,
        source = sConfig.sourceDir,
        dest = sConfig.destinationDir,
        mapsDir = sConfig.mapsDir,
        postcssConfig = sConfig.postcss;

    return compileLess(source, dest, files, mapsDir, postcssConfig);
}
styles.description = 'Compiles SCSS files to CSS; adds source maps if specified';

function minifyStyles(done) {
    if (shouldMinify) {
        let dir = config.styles.destinationDir;
        return minifyCSS(dir, dir, false);
    }
    done();
}
minifyStyles.description = 'Minify CSS files';

function images() {
    let iConfig = config.images,
        sourceDir = iConfig.sourceDir,
        destDir = iConfig.destinationDir;

    return minifyImages(sourceDir, destDir);
}
images.description = 'Minify images back into the same (source) folder';

function watch(done) {
    if (development()) {
        gulp.watch(config.styles.sourceFiles, styles);
    }
    done();
}
watch.description = 'Watch relevant files and re-run their tasks (only in development environment)';

/**
 * Generic function to compile LESS files
 * @param {String} sourceDir a string representing the path to the directory for the LESS files
 * @param {String} destDir a string representing the path to the directory where the compiled files would be saved
 * @param {String|Array} files string or array of strings representing the glob match for the source files
 * @param {String} mapsDir the directory where sourcemaps would be stored (relative to the destination directory)
 * @param {Array} postcssConfig an array of postcss processors
 * @returns {*} the gulp stream
 */
function compileLess(sourceDir, destDir, files, mapsDir, postcssConfig) {
    return compileStyles(sourceDir, destDir, files, mapsDir, less, postcssConfig);
}

/**
 * Generic function to compile Sass files
 * @param {String} sourceDir a string representing the path to the directory for the Sass files
 * @param {String} destDir a string representing the path to the directory where the compiled files would be saved
 * @param {String|Array} files string or array of strings representing the glob match for the source files
 * @param {String} mapsDir the directory where sourcemaps would be stored (relative to the destination directory)
 * @param {Array} postcssConfig an array of postcss processors
 * @returns {*} the gulp stream
 */
function compileSass(sourceDir, destDir, files, mapsDir, postcssConfig) {
    return compileStyles(sourceDir, destDir, files, mapsDir, function () {
        return sass().on('error', sass.logError);
    }, postcssConfig);
}

/**
 * A generic function to compile both LESS and Sass files
 * @param {String} sourceDir a string representing the path to the directory for the source files
 * @param {String} destDir a string representing the path to the directory where the compiled files would be saved
 * @param {String|Array} files string or array of strings representing the glob match for the source files
 * @param {String} mapsDir the directory where sourcemaps would be stored (relative to the destination directory)
 * @param {Function} buildFxn the build function to use. could be less or sass functions
 * @param {Array} postcssConfig an array of postcss processors
 */
function compileStyles(sourceDir, destDir, files, mapsDir, buildFxn, postcssConfig) {
    return gulp.src(files, {base: sourceDir})
        .pipe(gulpif(shouldAddSourcemaps, sourcemaps.init()))
        .pipe(buildFxn())
        .pipe(postcss(postcssConfig))
        .pipe(gulpif(shouldAddSourcemaps, sourcemaps.write(mapsDir)))
        .pipe(gulp.dest(destDir));
}

/**
 * A generic function to copy files/directories to a different directory
 * @param {String|Array} source a string or array of string representing the glob match for the source files/folders
 * @param {String} destination the new directory to copy
 */
function copy(source, destination) {
    return gulp.src(source)
        .pipe(gulp.dest(destination));
}

/**
 * Generic function to minify CSS files
 * @param {string} sourceDir a string representing the path to the directory for the source files
 * @param {string} destDir a string representing the path to the directory where the minified files would be saved
 * @param {boolean} shouldRename determine whether the new file should be renamed or not
 * @returns {*} the gulp stream
 */
function minifyCSS(sourceDir, destDir, shouldRename) {
    let files = [path.join(sourceDir, '**/*.css'), path.join('!' + sourceDir, '**/*.min.css')];
    return minify(files, destDir, cssmin, shouldRename);
}

/**
 * A generic function to minify images
 * @param {string} sourceDir a string representing the path to the directory for the source files
 * @param {string} destDir a string representing the path to the directory where the minified files would be saved
 * @returns {*} the gulp stream
 */
function minifyImages(sourceDir, destDir) {
    let files = path.join(sourceDir, '**/*');
    return minify(files, destDir, imagemin, false);
}

/**
 * A generic function to minify different types of files
 * @param {string|array} source a string or array of strings representing the glob match for the source files/folders
 * @param {string} destDir a string representing the path to the directory where the minified files would be saved
 * @param {function} minifyFxn the minify function to use
 * @param {boolean} shouldRename determine whether the new file should be renamed or not
 */
function minify(source, destDir, minifyFxn, shouldRename) {
    if ('undefined' === typeof shouldRename) {
        shouldRename = true;
    }
    return gulp.src(source)
        .pipe(minifyFxn())
        .pipe(gulpif((shouldRename), rename({suffix: '.min'})))
        .pipe(gulp.dest(destDir));
}
<|endoftext|>