<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return Math.floor(Math.random()*(max-min+1)+min);
}

function commit(t_offset, outFD, outFile, data, counter, length)
{
  if (counter < length)
  {
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    if (counter + step >= length) step = length - counter
    process.stdout.write("\033[2K Writing " + counter + "/" + length + " bytes: " + message + "\r");
    fs.writeSync(outFD, data.slice(counter, counter+step), 0, step)
    child_process.execFileSync('/Applications/Xcode.app/Contents/Developer/usr/bin/git', args)
    var timeout = randomIntFromInterval(0, max_sleep)
    counter = counter + step
    if (process.env.FAKETIME) {
      t_offset = t_offset + timeout;
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = timeout * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  } else {
    var args = ['push']
    c<commit_msg>Updated the readme again<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return Math.floor(Math.random()*(max-min+1)+min);
}

function commit(t_offset, outFD, outFile, data, counter, length)
{
  if (counter < length)
  {
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    if (counter + step >= length) step = length - counter
    process.stdout.write("\033[2K Writing " + counter + "/" + length + " bytes: " + message + "\r");
    fs.writeSync(outFD, data.slice(counter, counter+step), 0, step)
    child_process.execFileSync('/Applications/Xcode.app/Contents/Developer/usr/bin/git', args)
    var timeout = randomIntFromInterval(0, max_sleep)
    counter = counter + step
    if (process.env.FAKETIME) {
      t_offset = t_offset + timeout;
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = timeout * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  } else {
    var args = ['push']
    ch<|endoftext|>


<commit_before>/*
	HUMANIZED MESSAGES 1.0
	idea - http://www.humanized.com/weblog/2006/09/11/monolog_boxes_and_transparent_messages
	home - http://humanmsg.googlecode.com
  modified by livibeter; 2009-11-29T04:56:38+799
*/

var humanMsg = {
	setup: function(appendTo, logName, msgOpacity) {
		humanMsg.msgID = 'humanMsg';
		humanMsg.logID = 'humanMsgLog';

		// appendTo is the element the msg is appended to
		if (appendTo == undefined)
			appendTo = 'body';

		// The text on the Log tab
		if (logName == undefined)
			logName = 'Message Log';

		// Opacity of the message
		humanMsg.msgOpacity = .8;

		if (msgOpacity != undefined)
			humanMsg.msgOpacity = parseFloat(msgOpacity);

		// Inject the message structure
		jQuery(appendTo).append('

'+logName+'

')

		jQuery('#'+humanMsg.logID+' p').click(
			function() { jQuery(this).siblings('ul').slideToggle() }
		)
	},

	displayMsg: function(msg, theme) {
		if (msg == '')
			return;

		clearTimeout(humanMsg.t2);

		// Inject message
		jQuery('#'+humanMsg.msgID+' p').html('' + msg + '')

		// Show message
		jQuery('#'+humanMsg.msgID+'').show().animate({ opacity: humanMsg.msgOpacity}, 200, function() {
			jQuery('#'+humanMsg.logID)
				.show().children('ul').prepend('
'+msg+'
')	// Prepend message to log
				.children('li:first').slideDown(200)				// Slide it down

			if ( jQuery('#'+humanMsg.logID+' ul').css('display') == 'none') {
				jQuery('#'+humanMsg.logID+' p').animate({ bottom: 40 }, 200, 'linear', function() {
					jQuery(this).animate({ bottom: 0 }, 300, 'easeOutBounce', function() { jQuery(this).css({ bottom: 0 }) })
				})
			}

		})

		// Watch for mouse & keyboard in .5s
		humanMsg.t1 = setTimeout("humanMsg.bindEvents()", 700)
		// Remove message after 5s
		humanMsg.t2 = setTimeout("humanMsg.removeMsg()", 5000)
	},

	bindEvents: function() {
	// Remove message if mouse is moved or key is pressed
		jQuery(window)
			.mousemove(humanMsg.removeMsg)
			.click(humanMsg.removeMsg)
			.keypress(humanMsg.removeMsg)
	},

	removeMsg: function() {
		// Unbind mouse & keyboard
		jQuery(window)
			.unbind('mousemove', humanMsg.removeMsg)
			.unbind('click', humanMsg.removeMsg)
			.unbind('keypress', humanMsg.removeMsg)

		// If message is fully transparent, fade it out
		if (jQuery('#'+humanMsg.msgID).css('opacity') == humanMsg.msgOpacity)
			jQuery('#'+humanMsg.msgID).animate({ opacity: 0 }, 500, function() { jQuery(this).hide() })
	}
};

jQuery(document).ready(function(){
	humanMsg.setup();
})
<commit_msg>Removed x perm<commit_after>/*
	HUMANIZED MESSAGES 1.0
	idea - http://www.humanized.com/weblog/2006/09/11/monolog_boxes_and_transparent_messages
	home - http://humanmsg.googlecode.com
  modified by livibeter; 2009-11-29T04:56:38+799
*/

var humanMsg = {
	setup: function(appendTo, logName, msgOpacity) {
		humanMsg.msgID = 'humanMsg';
		humanMsg.logID = 'humanMsgLog';

		// appendTo is the element the msg is appended to
		if (appendTo == undefined)
			appendTo = 'body';

		// The text on the Log tab
		if (logName == undefined)
			logName = 'Message Log';

		// Opacity of the message
		humanMsg.msgOpacity = .8;

		if (msgOpacity != undefined)
			humanMsg.msgOpacity = parseFloat(msgOpacity);

		// Inject the message structure
		jQuery(appendTo).append('

'+logName+'

')

		jQuery('#'+humanMsg.logID+' p').click(
			function() { jQuery(this).siblings('ul').slideToggle() }
		)
	},

	displayMsg: function(msg, theme) {
		if (msg == '')
			return;

		clearTimeout(humanMsg.t2);

		// Inject message
		jQuery('#'+humanMsg.msgID+' p').html('' + msg + '')

		// Show message
		jQuery('#'+humanMsg.msgID+'').show().animate({ opacity: humanMsg.msgOpacity}, 200, function() {
			jQuery('#'+humanMsg.logID)
				.show().children('ul').prepend('
'+msg+'
')	// Prepend message to log
				.children('li:first').slideDown(200)				// Slide it down

			if ( jQuery('#'+humanMsg.logID+' ul').css('display') == 'none') {
				jQuery('#'+humanMsg.logID+' p').animate({ bottom: 40 }, 200, 'linear', function() {
					jQuery(this).animate({ bottom: 0 }, 300, 'easeOutBounce', function() { jQuery(this).css({ bottom: 0 }) })
				})
			}

		})

		// Watch for mouse & keyboard in .5s
		humanMsg.t1 = setTimeout("humanMsg.bindEvents()", 700)
		// Remove message after 5s
		humanMsg.t2 = setTimeout("humanMsg.removeMsg()", 5000)
	},

	bindEvents: function() {
	// Remove message if mouse is moved or key is pressed
		jQuery(window)
			.mousemove(humanMsg.removeMsg)
			.click(humanMsg.removeMsg)
			.keypress(humanMsg.removeMsg)
	},

	removeMsg: function() {
		// Unbind mouse & keyboard
		jQuery(window)
			.unbind('mousemove', humanMsg.removeMsg)
			.unbind('click', humanMsg.removeMsg)
			.unbind('keypress', humanMsg.removeMsg)

		// If message is fully transparent, fade it out
		if (jQuery('#'+humanMsg.msgID).css('opacity') == humanMsg.msgOpacity)
			jQuery('#'+humanMsg.msgID).animate({ opacity: 0 }, 500, function() { jQuery(this).hide() })
	}
};

jQuery(document).ready(function(){
	humanMsg.setup();
})
<|endoftext|>


<commit_before>'use strict'

// -----------------------------------------------------------------------------
// NODE MODULES
// -----------------------------------------------------------------------------

// Express dependencies
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')

// Initiate Express
const app = express()
const router = express.Router()

// -----------------------------------------------------------------------------
// APP CONFIGURATION
// -----------------------------------------------------------------------------

// req.body
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
app.use(cors())

const books = require('./data.js')

// -----------------------------------------------------------------------------
// ROUTING
// -----------------------------------------------------------------------------

router.get('/ping', (req, res) => {
  res.json({ 'message': 'PONG!' })
})

router.get('/books', (req, res) => {
  res.json(books)
})

router.post('/books', (req, res) => {
  const book = {
    id: Number(req.body.id),
    name: req.body.name,
    price: Number(req.body.price)
  }
  books.push(book)
  res.json(book)
})

// -----------------------------------------------------------------------------
// REGISTER ROUTES
// -----------------------------------------------------------------------------

app.use('/', router)

// -----------------------------------------------------------------------------
// RUN THE APP
// -----------------------------------------------------------------------------

const host = process.env.HOST || "localhost"
const port = process.env.PORT || "3000"

app.listen(port, host, (err) => {
  if (err) console.log(err)
  console.log(`Server is running on ${host}:${port}`)
})
<commit_msg>router get by id<commit_after>'use strict'

// -----------------------------------------------------------------------------
// NODE MODULES
// -----------------------------------------------------------------------------

// Express dependencies
const express = require('express')
const bodyParser = require('body-parser')
const cors = require('cors')

// Initiate Express
const app = express()
const router = express.Router()

// -----------------------------------------------------------------------------
// APP CONFIGURATION
// -----------------------------------------------------------------------------

// req.body
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
app.use(cors())

const books = require('./data.js')

// -----------------------------------------------------------------------------
// ROUTING
// -----------------------------------------------------------------------------

router.get('/ping', (req, res) => {
  res.json({ 'message': 'PONG!' })
})

router.get('/books', (req, res) => {
  res.json(books)
})

router.post('/books', (req, res) => {
  const book = {
    id: Number(req.body.id),
    name: req.body.name,
    price: Number(req.body.price)
  }
  books.push(book)
  res.json(book)
})

router.get('/books/:id', (req, res) => {
  // req.body   >>> /data + { id: 0 }
  // req.params >>> /data/:id
  // req.query  >>> /data?q={id}
  let book = books.filter(book => {
    return book.id === req.params.id
  })

  res.json(book)
})

// -----------------------------------------------------------------------------
// REGISTER ROUTES
// -----------------------------------------------------------------------------

app.use('/', router)

// -----------------------------------------------------------------------------
// RUN THE APP
// -----------------------------------------------------------------------------

const host = process.env.HOST || "localhost"
const port = process.env.PORT || "3000"

app.listen(port, host, (err) => {
  if (err) console.log(err)
  console.log(`Server is running on ${host}:${port}`)
})
<|endoftext|>


<commit_before>var _ = require('underscore');
var WidgetContent = require('../standard/widget_content_view');
var WidgetSearchTitleView = require('./search_title_view');
var WidgetCategoryFilterView = require('./filter_view');
var WidgetCategoryItemsView = require('./items_view');
var WidgetCategoryViewModel = require('./view_model');
var WidgetCategoryInfoView = require('./info_view');
var WidgetCategoryPaginatorView = require('./paginator_view');
var WidgetSearchCategoryItemsView = require('./search_items_view');
var WidgetSearchCategoryPaginatorView = require('./search_paginator_view');
var template = require('./content.tpl');

/**
 * Category content view
 */
module.exports = WidgetContent.extend({

  _ITEMS_PER_PAGE: 6,

  initialize: function(opts) {
    this.viewModel = new WidgetCategoryViewModel();
    this.search = this.model.getSearch();
    WidgetContent.prototype.initialize.call(this, arguments);
  },

  render: function() {
    this.clearSubViews();
    this.$el.html(
      template({
        title: this.model.get('title')
      })
    );
    this._initViews();
    return this;
  },

  _initBinds: function() {
    this.viewModel.bind('change:search', this._onToggleSearch, this);
  },

  _onToggleSearch: function() {
    // If search is disabled, get selected items and set them
    // in accept filter. Then reset search.
    var searchEnabled = this.viewModel.isSearchEnabled();
    if (!searchEnabled) {
      this.model.cleanSearch();
    }
  },

  _initViews: function() {
    // Title or search
    var searchTitle = new WidgetSearchTitleView({
      model: this.viewModel,
      dataModel: this.model,
      title: this.model.get('title'),
      search: this.search
    });
    this.$('.js-header').append(searchTitle.render().el);
    this.addView(searchTitle);

    // Stats info
    var info = new WidgetCategoryInfoView({
      viewModel: this.viewModel,
      dataModel: this.model
    });
    this.$('.js-header').append(info.render().el);
    this.addView(info);

    // Actions over data view
    var filters = new WidgetCategoryFilterView({
      dataModel: this.model,
      search: this.search,
      viewModel: this.viewModel,
      filter: this.filter
    });
    this.$('.js-content').html(filters.render().el);
    this.addView(filters);

    // Data list view
    var dataList = new WidgetCategoryItemsView({
      model: this.viewModel,
      dataModel: this.model,
      filter: this.filter,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-content').append(dataList.render().el);
    this.addView(dataList);

    // Data paginator
    var pagination = new WidgetCategoryPaginatorView({
      $target: dataList.$el,
      viewModel: this.viewModel,
      dataModel: this.model,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-footer').append(pagination.render().el);
    this.addView(pagination);

    ////////////////////////////////
    // Hello search functionality //
    ////////////////////////////////

    // Search list view
    var searchList = new WidgetSearchCategoryItemsView({
      model: this.viewModel,
      dataModel: this.search,
      originModel: this.model,
      filter: this.filter,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-content').append(searchList.render().el);
    this.addView(searchList);

    // Search paginator
    var searchPagination = new WidgetSearchCategoryPaginatorView({
      $target: searchList.$el,
      viewModel: this.viewModel,
      dataModel: this.search,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-footer').append(searchPagination.render().el);
    this.addView(searchPagination);
  }

});
<commit_msg>Removed unnecessary bind within content view<commit_after>var _ = require('underscore');
var WidgetContent = require('../standard/widget_content_view');
var WidgetSearchTitleView = require('./search_title_view');
var WidgetCategoryFilterView = require('./filter_view');
var WidgetCategoryItemsView = require('./items_view');
var WidgetCategoryViewModel = require('./view_model');
var WidgetCategoryInfoView = require('./info_view');
var WidgetCategoryPaginatorView = require('./paginator_view');
var WidgetSearchCategoryItemsView = require('./search_items_view');
var WidgetSearchCategoryPaginatorView = require('./search_paginator_view');
var template = require('./content.tpl');

/**
 * Category content view
 */
module.exports = WidgetContent.extend({

  _ITEMS_PER_PAGE: 6,

  initialize: function(opts) {
    this.viewModel = new WidgetCategoryViewModel();
    this.search = this.model.getSearch();
    WidgetContent.prototype.initialize.call(this, arguments);
  },

  render: function() {
    this.clearSubViews();
    this.$el.html(
      template({
        title: this.model.get('title')
      })
    );
    this._initViews();
    return this;
  },

  _initViews: function() {
    // Title or search
    var searchTitle = new WidgetSearchTitleView({
      viewModel: this.viewModel,
      dataModel: this.model,
      title: this.model.get('title'),
      search: this.search
    });
    this.$('.js-header').append(searchTitle.render().el);
    this.addView(searchTitle);

    // Stats info
    var info = new WidgetCategoryInfoView({
      viewModel: this.viewModel,
      dataModel: this.model,
      search: this.search
    });
    this.$('.js-header').append(info.render().el);
    this.addView(info);

    // Actions over data view
    var filters = new WidgetCategoryFilterView({
      dataModel: this.model,
      viewModel: this.viewModel,
      filter: this.filter
    });
    this.$('.js-content').html(filters.render().el);
    this.addView(filters);

    // Data list view
    var dataList = new WidgetCategoryItemsView({
      model: this.viewModel,
      dataModel: this.model,
      filter: this.filter,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-content').append(dataList.render().el);
    this.addView(dataList);

    // Data paginator
    var pagination = new WidgetCategoryPaginatorView({
      $target: dataList.$el,
      viewModel: this.viewModel,
      dataModel: this.model,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-footer').append(pagination.render().el);
    this.addView(pagination);

    ////////////////////////////////
    // Hello search functionality //
    ////////////////////////////////

    // Search list view
    var searchList = new WidgetSearchCategoryItemsView({
      model: this.viewModel,
      dataModel: this.search,
      originModel: this.model,
      filter: this.filter,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-content').append(searchList.render().el);
    this.addView(searchList);

    // Search paginator
    var searchPagination = new WidgetSearchCategoryPaginatorView({
      $target: searchList.$el,
      viewModel: this.viewModel,
      originModel: this.model,
      dataModel: this.search,
      itemsPerPage: this._ITEMS_PER_PAGE
    });
    this.$('.js-footer').append(searchPagination.render().el);
    this.addView(searchPagination);
  }

});
<|endoftext|>


<commit_before>import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import qs from 'qs';

import { openDownloadModal as openDownloadModalAction } from '../../actions/action-creators';
import config from '../../config';
import { HeaderMessage } from '../../components/header';
import Header from '../../components/header';

import DetailsCard from '../../components/dashboard/details-card';
import NearbyLocations from './nearby-locations';
import LatestMeasurementsCard from '../../components/dashboard/lastest-measurements-card';
import SourcesCard from '../../components/dashboard/sources-card';
import MeasureandsCard from '../../components/dashboard/measurands-card';
import TemporalCoverageCard from '../../components/dashboard/temporal-coverage-card';
import TimeSeriesCard from '../../components/dashboard/time-series-card';
import MobileDataLocationsCard from '../../components/dashboard/mobile-data-locations-card';
import DateSelector from '../../components/date-selector';
import { formatValueByUnit, renderUnit } from '../../utils/format';

import { buildQS } from '../../utils/url';
import { NO_CITY } from '../../utils/constants';

const defaultState = {
  fetched: false,
  fetching: false,
  error: null,
  data: null,
};

function Location({ location, history, match, openDownloadModal }) {
  const { id } = match.params;

  const [dateRange, setDateRange] = useState(
    qs.parse(location.search, { ignoreQueryPrefix: true }).dateRange
  );

  useEffect(() => {
    let query = qs.parse(location.search, {
      ignoreQueryPrefix: true,
    });
    query.dateRange = dateRange;
    history.push(`${location.pathname}?${buildQS(query)}`);
  }, [dateRange]);

  const [{ fetched, fetching, error, data }, setState] = useState(defaultState);

  useEffect(() => {
    const fetchData = id => {
      setState(state => ({ ...state, fetching: true, error: null }));

      fetch(`${config.api}/locations/${encodeURIComponent(id)}`)
        .then(response => {
          if (response.status >= 400) {
            throw new Error('Bad response');
          }
          return response.json();
        })
        .then(
          json => {
            const dat = json.results[0];
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              data: {
                ...dat,
                parameters: dat.parameters.map(p => ({
                  ...p,
                  average: formatValueByUnit(
                    p.average,
                    p.unit,
                    renderUnit(p.unit)
                  ),
                  lastValue: formatValueByUnit(
                    p.lastValue,
                    p.unit,
                    renderUnit(p.unit)
                  ),
                  unit: renderUnit(p.unit),
                })),
              },
            }));
          },
          e => {
            console.log('e', e);
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              error: e,
            }));
          }
        );
    };

    fetchData(id);

    return () => {
      setState(defaultState);
    };
  }, [id]);

  if (!fetched && !fetching) {
    return null;
  }

  if (fetching) {
    return (
      <HeaderMessage>

Take a deep breath.

Location data is loading...

      </HeaderMessage>
    );
  }

  if (error || !data) {
    return (
      <HeaderMessage>

Uh oh, something went wrong.

            There was a problem getting the data. If you continue to have
            problems, please let us know.

              Send us an Email

      </HeaderMessage>
    );
  }

  function onDownloadClick() {
    openDownloadModal({
      country: data.country,
      area: data.city || NO_CITY,
      location: data.id,
    });
  }

  //
  // Lifecycle stage of different sources.
  const lifecycle = (data.sources || [])
    .map(s => s.lifecycle_stage)
    .filter(Boolean);

  return (

      <Header
        tagline="Location"
        title={data.name}
        subtitle={`in ${data.city || NO_CITY}, ${data.country}`}
        action={{
          api: `${config.apiDocs}`,
          download: onDownloadClick,
          compare: `/compare/${encodeURIComponent(data.id)}`,
        }}
        sourceType={data.sensorType}
        entity={data.entity}
        isMobile={data.isMobile}
      />

        <DateSelector setDateRange={setDateRange} dateRange={dateRange} />

          <DetailsCard
            measurements={data.measurements}
            lifecycle={lifecycle}
            coords={{
              lat: data.coordinates.latitude,
              lng: data.coordinates.longitude,
            }}
            date={{
              start: data.firstUpdated,
              end: data.lastUpdated,
            }}
          />
          <LatestMeasurementsCard parameters={data.parameters} />
          <SourcesCard sources={data.sources} />
          <TimeSeriesCard
            locationId={data.id}
            parameters={data.parameters}
            xUnit="day"
            dateRange={dateRange}
            titleInfo={
              'The value of a pollutant over time during the specified window. While locations have varying time intervals over which they report, all time series charts show data at the same intervals. For one day or one month of data the hourly average is shown. For the project lifetime the daily averages are shown for the most recent week of data.'
            }
          />
          {data.isMobile && (
            <MobileDataLocationsCard
              locationId={data.id}
              bbox={data.bounds}
              firstUpdated={data.firstUpdated}
              lastUpdated={data.lastUpdated}
            />
          )}
          <TemporalCoverageCard
            parameters={data.parameters}
            spatial="location"
            id={data.id}
            dateRange={dateRange}
            titleInfo={
              'The average number of measurements for each pollutant by hour, day, or month. In some views a window may be turned off if that view is not applicable to the selected time window.'
            }
            isMobile={data.isMobile}
          />
          <MeasureandsCard
            parameters={data.parameters}
            titleInfo={
              'The average of all values and total number of measurements for each pollutant during the chosen time window.'
            }
          />

        <NearbyLocations
          locationId={data.id}
          center={[data.coordinates.longitude, data.coordinates.latitude]}
          city={data.city || NO_CITY}
          country={data.country}
          parameters={data.parameters}
          initialActiveParameter={data.parameters[0]}
        />

  );
}

Location.propTypes = {
  location: PropTypes.object.isRequired,
  history: PropTypes.object.isRequired,
  match: PropTypes.object.isRequired,

  openDownloadModal: PropTypes.func.isRequired,
};

// /////////////////////////////////////////////////////////////////// //
// Connect functions

function dispatcher(dispatch) {
  return {
    openDownloadModal: (...args) => dispatch(openDownloadModalAction(...args)),
  };
}

export default connect(null, dispatcher)(Location);
<commit_msg>filters null values<commit_after>import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import qs from 'qs';

import { openDownloadModal as openDownloadModalAction } from '../../actions/action-creators';
import config from '../../config';
import { HeaderMessage } from '../../components/header';
import Header from '../../components/header';

import DetailsCard from '../../components/dashboard/details-card';
import NearbyLocations from './nearby-locations';
import LatestMeasurementsCard from '../../components/dashboard/lastest-measurements-card';
import SourcesCard from '../../components/dashboard/sources-card';
import MeasureandsCard from '../../components/dashboard/measurands-card';
import TemporalCoverageCard from '../../components/dashboard/temporal-coverage-card';
import TimeSeriesCard from '../../components/dashboard/time-series-card';
import MobileDataLocationsCard from '../../components/dashboard/mobile-data-locations-card';
import DateSelector from '../../components/date-selector';
import { formatValueByUnit, renderUnit } from '../../utils/format';

import { buildQS } from '../../utils/url';
import { NO_CITY } from '../../utils/constants';

const defaultState = {
  fetched: false,
  fetching: false,
  error: null,
  data: null,
};

function Location({ location, history, match, openDownloadModal }) {
  const { id } = match.params;

  const [dateRange, setDateRange] = useState(
    qs.parse(location.search, { ignoreQueryPrefix: true }).dateRange
  );

  useEffect(() => {
    let query = qs.parse(location.search, {
      ignoreQueryPrefix: true,
    });
    query.dateRange = dateRange;
    history.push(`${location.pathname}?${buildQS(query)}`);
  }, [dateRange]);

  const [{ fetched, fetching, error, data }, setState] = useState(defaultState);

  useEffect(() => {
    const fetchData = id => {
      setState(state => ({ ...state, fetching: true, error: null }));

      fetch(`${config.api}/locations/${encodeURIComponent(id)}`)
        .then(response => {
          if (response.status >= 400) {
            throw new Error('Bad response');
          }
          return response.json();
        })
        .then(
          json => {
            const dat = json.results[0];
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              data: {
                ...dat,
                parameters: dat.parameters
                  .filter(p => p) // removes null values
                  .map(p => ({
                    ...p,
                    average: formatValueByUnit(
                      p.average,
                      p.unit,
                      renderUnit(p.unit)
                    ),
                    lastValue: formatValueByUnit(
                      p.lastValue,
                      p.unit,
                      renderUnit(p.unit)
                    ),
                    unit: renderUnit(p.unit),
                  })),
              },
            }));
          },
          e => {
            console.log('e', e);
            setState(state => ({
              ...state,
              fetched: true,
              fetching: false,
              error: e,
            }));
          }
        );
    };

    fetchData(id);

    return () => {
      setState(defaultState);
    };
  }, [id]);

  if (!fetched && !fetching) {
    return null;
  }

  if (fetching) {
    return (
      <HeaderMessage>

Take a deep breath.

Location data is loading...

      </HeaderMessage>
    );
  }

  if (error || !data) {
    return (
      <HeaderMessage>

Uh oh, something went wrong.

            There was a problem getting the data. If you continue to have
            problems, please let us know.

              Send us an Email

      </HeaderMessage>
    );
  }

  function onDownloadClick() {
    openDownloadModal({
      country: data.country,
      area: data.city || NO_CITY,
      location: data.id,
    });
  }

  //
  // Lifecycle stage of different sources.
  const lifecycle = (data.sources || [])
    .map(s => s.lifecycle_stage)
    .filter(Boolean);

  return (

      <Header
        tagline="Location"
        title={data.name}
        subtitle={`in ${data.city || NO_CITY}, ${data.country}`}
        action={{
          api: `${config.apiDocs}`,
          download: onDownloadClick,
          compare: `/compare/${encodeURIComponent(data.id)}`,
        }}
        sourceType={data.sensorType}
        entity={data.entity}
        isMobile={data.isMobile}
      />

        <DateSelector setDateRange={setDateRange} dateRange={dateRange} />

          <DetailsCard
            measurements={data.measurements}
            lifecycle={lifecycle}
            coords={{
              lat: data.coordinates.latitude,
              lng: data.coordinates.longitude,
            }}
            date={{
              start: data.firstUpdated,
              end: data.lastUpdated,
            }}
          />
          <LatestMeasurementsCard parameters={data.parameters} />
          <SourcesCard sources={data.sources} />
          <TimeSeriesCard
            locationId={data.id}
            parameters={data.parameters}
            xUnit="day"
            dateRange={dateRange}
            titleInfo={
              'The value of a pollutant over time during the specified window. While locations have varying time intervals over which they report, all time series charts show data at the same intervals. For one day or one month of data the hourly average is shown. For the project lifetime the daily averages are shown for the most recent week of data.'
            }
          />
          {data.isMobile && (
            <MobileDataLocationsCard
              locationId={data.id}
              bbox={data.bounds}
              firstUpdated={data.firstUpdated}
              lastUpdated={data.lastUpdated}
            />
          )}
          <TemporalCoverageCard
            parameters={data.parameters}
            spatial="location"
            id={data.id}
            dateRange={dateRange}
            titleInfo={
              'The average number of measurements for each pollutant by hour, day, or month. In some views a window may be turned off if that view is not applicable to the selected time window.'
            }
            isMobile={data.isMobile}
          />
          <MeasureandsCard
            parameters={data.parameters}
            titleInfo={
              'The average of all values and total number of measurements for each pollutant during the chosen time window.'
            }
          />

        <NearbyLocations
          locationId={data.id}
          center={[data.coordinates.longitude, data.coordinates.latitude]}
          city={data.city || NO_CITY}
          country={data.country}
          parameters={data.parameters}
          initialActiveParameter={data.parameters[0]}
        />

  );
}

Location.propTypes = {
  location: PropTypes.object.isRequired,
  history: PropTypes.object.isRequired,
  match: PropTypes.object.isRequired,

  openDownloadModal: PropTypes.func.isRequired,
};

// /////////////////////////////////////////////////////////////////// //
// Connect functions

function dispatcher(dispatch) {
  return {
    openDownloadModal: (...args) => dispatch(openDownloadModalAction(...args)),
  };
}

export default connect(null, dispatcher)(Location);
<|endoftext|>


<commit_before>require('dotenv').config();

const users = {}; // store users in memory for now

if (!process.env.SONGKICK_API_KEY || !process.env.SERVER_IP || !process.env.FCM_API_KEY ||
	  !process.env.VAPID_EMAIL || !process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
  return console.error('❗ Failed to load in the environment variables. Are they missing from the `.env` file?');
}

const express = require('express');
const bodyParser = require('body-parser');
const fetch = require('node-fetch');
const path = require('path');
const webPush = require('web-push');

webPush.setGCMAPIKey(process.env.FCM_API_KEY);
webPush.setVapidDetails(
  `mailto:${process.env.VAPID_EMAIL}`,
  process.env.VAPID_PUBLIC_KEY,
  process.env.VAPID_PRIVATE_KEY
);

const uriPrefix = 'https://api.songkick.com/api/3.0/users';

const apiKey = process.env.SONGKICK_API_KEY;
const inDevelopment = process.env.NODE_ENV !== 'production';

const app = express();

const jsonParser = bodyParser.json();

if (inDevelopment) {
  const webpack = require('webpack');
  const devMiddleware = require('webpack-dev-middleware');
  const hotMiddleware = require('webpack-hot-middleware');
  const config = require('./webpack.config');

  const compiler = webpack(config);

  app.use(devMiddleware(compiler, {
    publicPath: config.output.publicPath,
    historyApiFallback: true
  }));

  app.use(hotMiddleware(compiler));
}

// Static files
app.use(express.static(path.resolve(path.resolve('.'), inDevelopment ? 'src' : 'build')));

const loadData = (options) => new Promise((resolve, reject) => {
  if (!options.uri) {
    return reject('No uri');
  }

  const uri = options.uri;
  const page = options.page || 1;

  return fetch(`${uri}&page=${page}`)
    .then(response => response.json())
    .then(data => {
      if (!data.resultsPage || data.resultsPage.totalEntries <= 0) {
        return reject('No results');
      }

      const pageAmount = Math.ceil(data.resultsPage.totalEntries / data.resultsPage.perPage);

      if (data.resultsPage.page !== pageAmount) {
        return loadData({ uri, page: page + 1 })
          .then(newData => {
            if (typeof data.resultsPage.results.artist !== 'undefined') {
              data.resultsPage.results.artist = data.resultsPage.results.artist.concat(newData.resultsPage.results.artist);
            }

            if (typeof data.resultsPage.results.calendarEntry !== 'undefined') {
              data.resultsPage.results.calendarEntry = data.resultsPage.results.calendarEntry.concat(newData.resultsPage.results.calendarEntry);
            }

            return resolve(data);
          });
      }

      return resolve(data);
    })
    .catch(reject);
});

const getResults = (data) => data.resultsPage.results;

const getEvents = (data) => new Promise((resolve, reject) => {
  if (data.calendarEntry.length <= 0) {
    return reject('No events');
  }

  const events = data.calendarEntry.map(entry => {
    const event = entry.event;
    event.reason = entry.reason;
    return event;
  });

  resolve(events);
});

const getArtists = (data) => new Promise((resolve, reject) => {
  if (data.artist.length <= 0) {
    return reject('No artists');
  }

  const artists = data.artist.map(artist => {
    artist.name = artist.displayName;
    artist.image = getImage(artist);
    return artist;
  });

  resolve(artists);
});

const getImage = (data) => {
  const IMAGE_PREFIX = 'https://images.sk-static.com/images/media/profile_images';

  if (typeof data.billing !== 'undefined' ) {
    return `${IMAGE_PREFIX}/artists/${data.artist.id}/huge_avatar`;
  }

  if (typeof data.onTourUntil !== 'undefined' ) {
    return `${IMAGE_PREFIX}/artists/${data.id}/huge_avatar`;
  }

  if (data.type === 'Festival') {
    return `${IMAGE_PREFIX}/events/${data.id}/huge_avatar`;
  }

  if (data.performance && data.performance.length > 0) {
    return `${IMAGE_PREFIX}/artists/${data.performance[0].artist.id}/huge_avatar`;
  }

  return '';
};

const processPerformances = (performances) => {
  return performances.map(performance => {
    return {
      id: performance.artist.id,
      type: performance.billing,
      name: performance.artist.displayName,
      image: getImage(performance)
    };
  });
};

function getOrdinal(n) {
  const s = ['th', 'st', 'nd', 'rd'];
  const v = n % 100;
  return s[(v - 20) % 10] || s[v] || s[0];
}

function formatDate(date, type) {
  date = date.trim(); // trim whitespace

  // if we only have the year add some time
  if (date.length === 10) {
    date += ' 00:00:00';
  }

  // replace - with /
  date = date.replace(/-/g, "/");

  // convert strings to date objects
  date = new Date(date);

  const monthNames = [
    'January', 'February', 'March',
    'April', 'May', 'June', 'July',
    'August', 'September', 'October',
    'November', 'December'
  ];

  let amPm = 'AM';
  let minutes = date.getMinutes();

  if (minutes < 10) {
    minutes = '0' + minutes;
  }

  let hours = date.getHours();

  if (hours >= 12) {
    hours -= 12;
    amPm = 'PM';
  }

  const dateString = date.toDateString();
  const dayName = dateString.split(' ')[0];
  const day = date.getDate();
  const dayWithOrdinal = `${day}${getOrdinal(day)}`;
  const monthIndex = date.getMonth();
  const month = monthNames[monthIndex];
  const year = date.getFullYear();

  if (type === 'long') {
    return `${dayName} ${dayWithOrdinal} ${month} ${year}`;
  } else if ( type === 'short') {
    return `${dayName} ${dayWithOrdinal} ${month.substr(0, 3)} `;
  } else if ( type === 'time') {
    return `${hours}:${minutes} ${amPm}`;
  }

  return dateString;
}

const processEvents = (events) => events.map(event => {
  const date = `${event.start.date} ${event.start.time || ''}`;
  const newEvent = {
    id: event.id,
    reason: event.reason,
    type: event.type.toLowerCase(),
    performances: processPerformances(event.performance),
    time: {
      iso: date,
      pretty: {
        short: date ? formatDate(date, 'short') : 'Date TBC',
        full:  date ? formatDate(date, 'long') : 'Date to be confirmed',
        doors: date ? formatDate(date, 'time') : 'Doors to be confirmed'
      }
    },
    place: {
      name: `${event.venue.displayName}, ${event.location.city}`,
      id: event.venue.id,
      uri: event.venue.uri,
      lat: event.venue.lat,
      lon: event.venue.lng
    },
    image: getImage(event),
    uri: event.uri
  };

  if (newEvent.type === 'festival') {
    newEvent.title = event.displayName;
  }

  return newEvent;
});

function sortUniqueResults(arr) {
  if (arr.length === 0) {
    return arr;
  }

  // sort by id for removing duplicates
  arr = arr.sort((a, b) => {
    return a.id - b.id;
  });

  const newArr = [arr[0]];

  for (let i = 1; i < arr.length; i++) { // start loop at 1 as element 0 can never be a duplicate
    if (arr[i - 1].id !== arr[i].id) {
      newArr.push(arr[i]);
    }
  }

  arr = newArr;

  // sort by date
  arr = arr.sort((a, b) => {
    return new Date(a.start.date) - new Date(b.start.date);
  });

  return arr;
}

function artists(username) {
  const uri = `${uriPrefix}/${username}/artists/tracked.json?apikey=${apiKey}`;
  return loadData({ uri }).then(getResults).then(getArtists);
}

function events(username) {
  return new Promise((resolve, reject) => {
    let uri = `${uriPrefix}/${username}/calendar.json?apikey=${apiKey}&reason=attendance`;
    const events = loadData({ uri }).then(getResults).then(getEvents);

    uri = `${uriPrefix}/${username}/calendar.json?apikey=${apiKey}&reason=tracked_artist`;
    const upcomingEvents = loadData({ uri }).then(getResults).then(getEvents);

    Promise.all([upcomingEvents, events]).then(results => {
      results = [].concat(...results);
      results = sortUniqueResults(results);

      resolve(processEvents(results));
    }).catch(reject);
  });
}

// allow CORS
// TODO: do i need this if im on the same domain anyway?
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

if (process.env.NODE_ENV === 'production') {
  // only allow from this ip address
  app.use((req, res, next) => {
    if (req.ip !== process.env.SERVER_IP) { // Wrong IP address
      res.status(401);
      return res.send('Permission denied');
    }
    next(); // correct IP address, continue middleware chain
  });
}

app.get('/', (req, res, next) => {
  res.status(404).json({ error: 'No username' });
});

app.get('/events', (req, res, next) => {
  const { username } = req.query;
  if (!username) {
    return res.status(404).json({ error: 'No username sent' });
  }

  events(username)
    .then(events => res.json(events))
    .catch(error => res.status(500).json({ error }));
});

app.get('/artists', (req, res) => {
  const { username } = req.query;
  if (!username) {
    return res.status(404).json({ error: 'No username sent' });
  }

  artists(username)
    .then(artists => res.json(artists))
    .catch(error => res.status(500).json({ error }));
});

app.post('/register', jsonParser, (req, res) => {
  console.log('req.body', req.body);
  const { subscription, username } = req.body;

  // if no user
  if (!users[username]) {
    // add subscription
    return users[username] = [subscription];
  }

  // check if already subscribed
  const alreadySubscribed = users[username].find(s => s.endpoint = subscription.endpoint);

  if (!alreadySubscribed) {
    // add new subscription
    users[username].push(subscription);
  }

  // A real world application would store the subscription info.
  // we'd stick this data into subscriptions
  res.sendStatus(201);
});

app.get('/postNotif', (req, res) => {
  console.log('/postNotif', users);
  Object.keys(users).forEach(username => {
    const pushSubscriptions = users[username];

    events(username)
      .then(events => {
        const event = events[0];

        const data = {
          title: `${event.performances[0].name}`,
          body: `${event.place.name} | ${event.time.pretty.short}`,
          icon: event.image
        };

        for (let i = 0; i < pushSubscriptions.length; i++) {
          const pushSubscription = pushSubscriptions[i];
          webPush.sendNotification(pushSubscription, JSON.stringify(data), { TTL: 0 });
        }

        return res.json(data);
      })
      .catch(error => res.send('error'));
  });
});

// Send everything else to react-router
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, inDevelopment ? 'src' : 'build', 'index.html'));
});

app.listen(process.env.PORT || 8000, (err) => {
  if (err) {
    return console.error(err);
  }

  console.log(`🌐 Listening at http://localhost:${process.env.PORT || 8000}/`);
  console.log(`${inDevelopment ? '🛠 Development' : '🚀 Production'} mode   `);
});
<commit_msg>Fix subscriptions check<commit_after>require('dotenv').config();

const users = {}; // store users in memory for now

if (!process.env.SONGKICK_API_KEY || !process.env.SERVER_IP || !process.env.FCM_API_KEY ||
	  !process.env.VAPID_EMAIL || !process.env.VAPID_PUBLIC_KEY || !process.env.VAPID_PRIVATE_KEY) {
  return console.error('❗ Failed to load in the environment variables. Are they missing from the `.env` file?');
}

const express = require('express');
const bodyParser = require('body-parser');
const fetch = require('node-fetch');
const path = require('path');
const webPush = require('web-push');

webPush.setGCMAPIKey(process.env.FCM_API_KEY);
webPush.setVapidDetails(
  `mailto:${process.env.VAPID_EMAIL}`,
  process.env.VAPID_PUBLIC_KEY,
  process.env.VAPID_PRIVATE_KEY
);

const uriPrefix = 'https://api.songkick.com/api/3.0/users';

const apiKey = process.env.SONGKICK_API_KEY;
const inDevelopment = process.env.NODE_ENV !== 'production';

const app = express();

const jsonParser = bodyParser.json();

if (inDevelopment) {
  const webpack = require('webpack');
  const devMiddleware = require('webpack-dev-middleware');
  const hotMiddleware = require('webpack-hot-middleware');
  const config = require('./webpack.config');

  const compiler = webpack(config);

  app.use(devMiddleware(compiler, {
    publicPath: config.output.publicPath,
    historyApiFallback: true
  }));

  app.use(hotMiddleware(compiler));
}

// Static files
app.use(express.static(path.resolve(path.resolve('.'), inDevelopment ? 'src' : 'build')));

const loadData = (options) => new Promise((resolve, reject) => {
  if (!options.uri) {
    return reject('No uri');
  }

  const uri = options.uri;
  const page = options.page || 1;

  return fetch(`${uri}&page=${page}`)
    .then(response => response.json())
    .then(data => {
      if (!data.resultsPage || data.resultsPage.totalEntries <= 0) {
        return reject('No results');
      }

      const pageAmount = Math.ceil(data.resultsPage.totalEntries / data.resultsPage.perPage);

      if (data.resultsPage.page !== pageAmount) {
        return loadData({ uri, page: page + 1 })
          .then(newData => {
            if (typeof data.resultsPage.results.artist !== 'undefined') {
              data.resultsPage.results.artist = data.resultsPage.results.artist.concat(newData.resultsPage.results.artist);
            }

            if (typeof data.resultsPage.results.calendarEntry !== 'undefined') {
              data.resultsPage.results.calendarEntry = data.resultsPage.results.calendarEntry.concat(newData.resultsPage.results.calendarEntry);
            }

            return resolve(data);
          });
      }

      return resolve(data);
    })
    .catch(reject);
});

const getResults = (data) => data.resultsPage.results;

const getEvents = (data) => new Promise((resolve, reject) => {
  if (data.calendarEntry.length <= 0) {
    return reject('No events');
  }

  const events = data.calendarEntry.map(entry => {
    const event = entry.event;
    event.reason = entry.reason;
    return event;
  });

  resolve(events);
});

const getArtists = (data) => new Promise((resolve, reject) => {
  if (data.artist.length <= 0) {
    return reject('No artists');
  }

  const artists = data.artist.map(artist => {
    artist.name = artist.displayName;
    artist.image = getImage(artist);
    return artist;
  });

  resolve(artists);
});

const getImage = (data) => {
  const IMAGE_PREFIX = 'https://images.sk-static.com/images/media/profile_images';

  if (typeof data.billing !== 'undefined' ) {
    return `${IMAGE_PREFIX}/artists/${data.artist.id}/huge_avatar`;
  }

  if (typeof data.onTourUntil !== 'undefined' ) {
    return `${IMAGE_PREFIX}/artists/${data.id}/huge_avatar`;
  }

  if (data.type === 'Festival') {
    return `${IMAGE_PREFIX}/events/${data.id}/huge_avatar`;
  }

  if (data.performance && data.performance.length > 0) {
    return `${IMAGE_PREFIX}/artists/${data.performance[0].artist.id}/huge_avatar`;
  }

  return '';
};

const processPerformances = (performances) => {
  return performances.map(performance => {
    return {
      id: performance.artist.id,
      type: performance.billing,
      name: performance.artist.displayName,
      image: getImage(performance)
    };
  });
};

function getOrdinal(n) {
  const s = ['th', 'st', 'nd', 'rd'];
  const v = n % 100;
  return s[(v - 20) % 10] || s[v] || s[0];
}

function formatDate(date, type) {
  date = date.trim(); // trim whitespace

  // if we only have the year add some time
  if (date.length === 10) {
    date += ' 00:00:00';
  }

  // replace - with /
  date = date.replace(/-/g, "/");

  // convert strings to date objects
  date = new Date(date);

  const monthNames = [
    'January', 'February', 'March',
    'April', 'May', 'June', 'July',
    'August', 'September', 'October',
    'November', 'December'
  ];

  let amPm = 'AM';
  let minutes = date.getMinutes();

  if (minutes < 10) {
    minutes = '0' + minutes;
  }

  let hours = date.getHours();

  if (hours >= 12) {
    hours -= 12;
    amPm = 'PM';
  }

  const dateString = date.toDateString();
  const dayName = dateString.split(' ')[0];
  const day = date.getDate();
  const dayWithOrdinal = `${day}${getOrdinal(day)}`;
  const monthIndex = date.getMonth();
  const month = monthNames[monthIndex];
  const year = date.getFullYear();

  if (type === 'long') {
    return `${dayName} ${dayWithOrdinal} ${month} ${year}`;
  } else if ( type === 'short') {
    return `${dayName} ${dayWithOrdinal} ${month.substr(0, 3)} `;
  } else if ( type === 'time') {
    return `${hours}:${minutes} ${amPm}`;
  }

  return dateString;
}

const processEvents = (events) => events.map(event => {
  const date = `${event.start.date} ${event.start.time || ''}`;
  const newEvent = {
    id: event.id,
    reason: event.reason,
    type: event.type.toLowerCase(),
    performances: processPerformances(event.performance),
    time: {
      iso: date,
      pretty: {
        short: date ? formatDate(date, 'short') : 'Date TBC',
        full:  date ? formatDate(date, 'long') : 'Date to be confirmed',
        doors: date ? formatDate(date, 'time') : 'Doors to be confirmed'
      }
    },
    place: {
      name: `${event.venue.displayName}, ${event.location.city}`,
      id: event.venue.id,
      uri: event.venue.uri,
      lat: event.venue.lat,
      lon: event.venue.lng
    },
    image: getImage(event),
    uri: event.uri
  };

  if (newEvent.type === 'festival') {
    newEvent.title = event.displayName;
  }

  return newEvent;
});

function sortUniqueResults(arr) {
  if (arr.length === 0) {
    return arr;
  }

  // sort by id for removing duplicates
  arr = arr.sort((a, b) => {
    return a.id - b.id;
  });

  const newArr = [arr[0]];

  for (let i = 1; i < arr.length; i++) { // start loop at 1 as element 0 can never be a duplicate
    if (arr[i - 1].id !== arr[i].id) {
      newArr.push(arr[i]);
    }
  }

  arr = newArr;

  // sort by date
  arr = arr.sort((a, b) => {
    return new Date(a.start.date) - new Date(b.start.date);
  });

  return arr;
}

function artists(username) {
  const uri = `${uriPrefix}/${username}/artists/tracked.json?apikey=${apiKey}`;
  return loadData({ uri }).then(getResults).then(getArtists);
}

function events(username) {
  return new Promise((resolve, reject) => {
    let uri = `${uriPrefix}/${username}/calendar.json?apikey=${apiKey}&reason=attendance`;
    const events = loadData({ uri }).then(getResults).then(getEvents);

    uri = `${uriPrefix}/${username}/calendar.json?apikey=${apiKey}&reason=tracked_artist`;
    const upcomingEvents = loadData({ uri }).then(getResults).then(getEvents);

    Promise.all([upcomingEvents, events]).then(results => {
      results = [].concat(...results);
      results = sortUniqueResults(results);

      resolve(processEvents(results));
    }).catch(reject);
  });
}

// allow CORS
// TODO: do i need this if im on the same domain anyway?
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

if (process.env.NODE_ENV === 'production') {
  // only allow from this ip address
  app.use((req, res, next) => {
    if (req.ip !== process.env.SERVER_IP) { // Wrong IP address
      res.status(401);
      return res.send('Permission denied');
    }
    next(); // correct IP address, continue middleware chain
  });
}

app.get('/', (req, res, next) => {
  res.status(404).json({ error: 'No username' });
});

app.get('/events', (req, res, next) => {
  const { username } = req.query;
  if (!username) {
    return res.status(404).json({ error: 'No username sent' });
  }

  events(username)
    .then(events => res.json(events))
    .catch(error => res.status(500).json({ error }));
});

app.get('/artists', (req, res) => {
  const { username } = req.query;
  if (!username) {
    return res.status(404).json({ error: 'No username sent' });
  }

  artists(username)
    .then(artists => res.json(artists))
    .catch(error => res.status(500).json({ error }));
});

app.post('/register', jsonParser, (req, res) => {
  console.log('req.body', req.body);
  const { subscription, username } = req.body;

  // if no user
  if (!users[username]) {
    // add subscription
    return users[username] = [subscription];
  }

  // check if already subscribed
  const alreadySubscribed = users[username].find(s => s.endpoint === subscription.endpoint);

  if (!alreadySubscribed) {
    // add new subscription
    users[username].push(subscription);
  }

  // A real world application would store the subscription info.
  // we'd stick this data into subscriptions
  res.sendStatus(201);
});

app.get('/postNotif', (req, res) => {
  console.log('/postNotif', users);
  Object.keys(users).forEach(username => {
    const pushSubscriptions = users[username];

    events(username)
      .then(events => {
        const event = events[0];

        const data = {
          title: `${event.performances[0].name}`,
          body: `${event.place.name} | ${event.time.pretty.short}`,
          icon: event.image
        };

        for (let i = 0; i < pushSubscriptions.length; i++) {
          const pushSubscription = pushSubscriptions[i];
          webPush.sendNotification(pushSubscription, JSON.stringify(data), { TTL: 0 });
        }

        return res.json(data);
      })
      .catch(error => res.send('error'));
  });
});

// Send everything else to react-router
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, inDevelopment ? 'src' : 'build', 'index.html'));
});

app.listen(process.env.PORT || 8000, (err) => {
  if (err) {
    return console.error(err);
  }

  console.log(`🌐 Listening at http://localhost:${process.env.PORT || 8000}/`);
  console.log(`${inDevelopment ? '🛠 Development' : '🚀 Production'} mode   `);
});
<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return Math.floor(Math.random()*(max-min+1)+min);
}

function commit(t_offset, outFD, outFile, data, counter, length)
{
  if (counter < length)
  {
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    if (counter + step >= length) step = length - counter
    process.stdout.write("\033[2K Writing " + counter + "/" + length + " bytes: " + message + "\r");
    fs.writeSync(outFD, data.slice(counter, counter+step), 0, step)
    child_process.execFileSync('/Applications/Xcode.app/Contents/Developer/usr/bin/git', args)
    var timeout = randomIntFromInterval(0, max_sleep)
    counter = counter + step
    if (process.env.FAKETIME) {
      t_offset = t_offset + timeout;
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = timeout * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  } else {
    va<commit_msg>Updated the readme<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return Math.floor(Math.random()*(max-min+1)+min);
}

function commit(t_offset, outFD, outFile, data, counter, length)
{
  if (counter < length)
  {
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    if (counter + step >= length) step = length - counter
    process.stdout.write("\033[2K Writing " + counter + "/" + length + " bytes: " + message + "\r");
    fs.writeSync(outFD, data.slice(counter, counter+step), 0, step)
    child_process.execFileSync('/Applications/Xcode.app/Contents/Developer/usr/bin/git', args)
    var timeout = randomIntFromInterval(0, max_sleep)
    counter = counter + step
    if (process.env.FAKETIME) {
      t_offset = t_offset + timeout;
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = timeout * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  } else {
    var<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import {Editor} from 'slate'
import {pick, isEqual} from 'lodash'
import InsertBlockOnEnter from 'slate-insert-block-on-enter'

import prepareSlateSchema from './util/prepareSlateSchema'
import createLocalStatePatch from './util/createLocalStatePatch'
import styles from './styles/BlockEditor.css'

import SlateValueContainer from './SlateValueContainer'

import FormBuilderNodeOnDrop from './plugins/FormBuilderNodeOnDrop'
import FormBuilderNodeOnPaste from './plugins/FormBuilderNodeOnPaste'
import TextFormattingOnKeyDown from './plugins/TextFormattingOnKeyDown'
import ListItemOnEnterKey from './plugins/ListItemOnEnterKey'
import TextBlockOnEnterKey from './plugins/TextBlockOnEnterKey'

import {
  SLATE_BLOCK_FORMATTING_OPTION_KEYS,
  SLATE_LIST_BLOCKS,
  SLATE_LIST_ITEM_TYPE,
  SLATE_DEFAULT_NODE,
  SLATE_TEXT_BLOCKS
} from './constants'

import Toolbar from './toolbar/Toolbar'

export default class BlockEditor extends React.Component {
  static valueContainer = SlateValueContainer

  static propTypes = {
    type: PropTypes.any,
    field: PropTypes.any,
    value: PropTypes.instanceOf(SlateValueContainer),
    validation: PropTypes.shape({
      errors: PropTypes.array
    }),
    onChange: PropTypes.func
  }

  static defaultProps = {
    onChange() {}
  }

  static contextTypes = {
    formBuilder: PropTypes.object
  }

  constructor(props, context) {
    super(props, context)

    const slateSchema = prepareSlateSchema(this.props.field)
    this.slateSchema = slateSchema.schema
    this.groupedFields = slateSchema.fields
    this.slatePlugins = [
      InsertBlockOnEnter({kind: 'block', type: 'paragraph', nodes: [{kind: 'text', text: '', ranges: []}]}),
      FormBuilderNodeOnDrop(),
      FormBuilderNodeOnPaste(this.context.formBuilder, this.props.field.of),
      TextFormattingOnKeyDown(),
      ListItemOnEnterKey(),
      TextBlockOnEnterKey()
    ]

    this.state = {
      fullscreen: false
    }
  }

  handleInsertBlock = item => {
    const {value, onChange, field} = this.props

    const type = item.type
    const ofField = field.of.find(it => it.type === type)
    const addItemValue = this.context.formBuilder.createFieldValue(undefined, ofField)

    const nextState = value.state
      .transform()
      .insertBlock({
        type: type,
        isVoid: true,
        data: {
          value: addItemValue
        }
      })
      .apply()

    onChange({patch: createLocalStatePatch(nextState)})
  }

  handleOnClickMarkButton = (event, type) => {
    event.preventDefault()
    const {value, onChange} = this.props
    const nextState = value.state
      .transform()
      .toggleMark(type)
      .apply()
    onChange({patch: createLocalStatePatch(nextState)})
  }

  handleOnClickListFormattingButton = (event, listStyle, active) => {
    const {value, onChange} = this.props
    const {state} = value
    const field = this.groupedFields.slate
      .find(sfield => SLATE_LIST_BLOCKS.includes(sfield.type) && sfield.listStyle === listStyle)
    const setBlock = {
      type: field.type,
      data: pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS)
    }
    let transform = state.transform()
    SLATE_LIST_BLOCKS.forEach(type => {
      transform = transform.unwrapBlock(type)
    })
    if (active) {
      if (setBlock.type === SLATE_DEFAULT_NODE) {
        transform.setBlock(setBlock)
      } else {
        transform = transform
          .setBlock(SLATE_LIST_ITEM_TYPE)
          .wrapBlock(setBlock)
      }
    } else {
      transform = transform
        .setBlock(SLATE_DEFAULT_NODE)
    }
    const nextState = transform.apply()
    onChange({patch: createLocalStatePatch(nextState)})
  }

  handleSelectBlockFormatting = selectedValue => {
    const {field} = selectedValue
    const {value, onChange} = this.props
    const {state} = value
    const {selection, startBlock, endBlock} = state
    const block = {
      type: field.type,
      data: pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS)
    }
    let transform = state.transform()

    if (this.isWithinList()) {
      SLATE_LIST_BLOCKS.forEach(type => {
        transform = transform.unwrapBlock(type)
      })
      transform = transform
        .setBlock(block)
      const nextState = transform.apply()
      onChange({patch: createLocalStatePatch(nextState)})
      return
    }

    // If a single block is selected partially, split block conditionally (selection in start, middle or end of text)
    if (startBlock === endBlock
      && selection.isExpanded
      && !(
        selection.hasStartAtStartOf(startBlock)
        && selection.hasEndAtEndOf(startBlock
      )
    )) {
      const hasTextBefore = !selection.hasStartAtStartOf(startBlock)
      const hasTextAfter = !selection.hasEndAtEndOf(startBlock)
      if (hasTextAfter) {
        const extendForward = selection.isForward
          ? (selection.focusOffset - selection.anchorOffset)
          : (selection.anchorOffset - selection.focusOffset)
        transform
          .collapseToStart()
          .splitBlock()
          .moveForward()
          .extendForward(extendForward)
          .collapseToEnd()
          .splitBlock()
          .collapseToStartOfPreviousText()
      } else {
        transform = hasTextBefore ? (
          transform
            .collapseToStart()
            .splitBlock()
            .moveForward()
        ) : (
          transform
            .collapseToEnd()
            .splitBlock()
            .moveTo(selection)
        )
      }
    }
    transform
      .setBlock(block)
    const nextState = transform.apply()
    onChange({patch: createLocalStatePatch(nextState)})
  }

  hasMark(type) {
    const {value} = this.props
    return value.state.marks.some(mark => mark.type == type)
  }

  hasBlock(field) {
    const {value} = this.props
    return value.state.blocks.some(node => node.type === field.type
        && isEqual(
          pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS),
          pick(node.data.toObject(), SLATE_BLOCK_FORMATTING_OPTION_KEYS)
        )
    )
  }

  isWithinList() {
    const {value} = this.props
    const {state} = value
    return state.blocks.some(block => block.type === SLATE_LIST_ITEM_TYPE)
  }

  hasParentBlock(field) {
    const {value} = this.props
    const {state} = value
    const {document} = state
    return state.blocks.some(node => {
      const parent = document.getParent(node)
      return parent && parent.data && parent.type === field.type
        && isEqual(
          pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS),
          pick(parent.data.toObject(), SLATE_BLOCK_FORMATTING_OPTION_KEYS)
        )
    })
  }

  getActiveMarks() {
    const {value} = this.props
    if (!value.state.blocks) {
      return []
    }
    const anchorBlock = value.state.blocks
      .filter(node => SLATE_TEXT_BLOCKS.concat(SLATE_LIST_ITEM_TYPE)
        .includes(node.type) && value.state.selection.hasAnchorIn(node)
      )
      .map(node => node.type).toArray()[0]
    if (!anchorBlock) {
      return []
    }
    const marksField = this.groupedFields.slate.find(field => field.type === anchorBlock)
    if (!marksField || !marksField.marks) {
      return []
    }
    return marksField.marks.map(mark => {
      return {
        type: mark,
        active: this.hasMark(mark)
      }
    })
  }

  getListFormats() {
    if (!this.groupedFields.slate.filter(field => SLATE_LIST_BLOCKS.includes(field.type)).length) {
      return []
    }
    return this.groupedFields.slate
      .filter(field => SLATE_LIST_BLOCKS.includes(field.type))
      .map((field, index) => {
        return {
          type: field.listStyle,
          title: field.title,
          active: this.hasParentBlock(field)
        }
      })
  }

  getTextFormats() {
    if (!this.groupedFields.slate.length) {
      return []
    }
    const items = this.groupedFields.slate
      .filter(field => SLATE_TEXT_BLOCKS.includes(field.type))
      .map((field, index) => {
        return {
          key: `blockFormat-${index}`,
          preview: this.slateSchema.nodes[field.type](
            Object.assign(
              {isPreview: true},
              {children: {field.title}},
              pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS)
            )
          ),
          field: field,
          title: ` ${field.title}`,
          active: this.hasBlock(field)
        }
      })
    let value = items.filter(item => item.active)
    if (value.length === 0) {
      value = [{
        key: 'blockFormat-none',
        preview: null,
        field: null,
        title: 'No style',
        active: true
      }]
    }
    return {
      items: items,
      value: value
    }
  }

  handleToggleFullscreen = () => {
    this.setState({
      fullscreen: !this.state.fullscreen
    })
  }

  handleEditorChange = nextState => {
    this.props.onChange({patch: createLocalStatePatch(nextState)})
  }

  render() {
    const {validation, value} = this.props
    const hasError = validation && validation.messages && validation.messages.length > 0
    return (

        <Toolbar
          className={styles.toolbar}
          onInsertBlock={this.handleInsertBlock}
          insertBlocks={this.groupedFields.formBuilder || []}
          onFullscreenEnable={this.handleToggleFullscreen}
          fullscreen={this.state.fullscreen}
          onMarkButtonClick={this.handleOnClickMarkButton}
          onListButtonClick={this.handleOnClickListFormattingButton}
          onFormatSelectChange={this.handleSelectBlockFormatting}
          listFormats={this.getListFormats()}
          textFormats={this.getTextFormats()}
          marks={this.getActiveMarks()}
        />

          <Editor
            className={styles.input}
            onChange={this.handleEditorChange}
            placeholder=""
            state={value.state}
            plugins={this.slatePlugins}
            schema={this.slateSchema}
          />

    )
  }
}
<commit_msg>Add form field name for block editor/slate<commit_after>import React, {PropTypes} from 'react'
import {Editor} from 'slate'
import {pick, isEqual, uniqueId} from 'lodash'
import FormField from 'part:@sanity/components/formfields/default'
import InsertBlockOnEnter from 'slate-insert-block-on-enter'

import prepareSlateSchema from './util/prepareSlateSchema'
import createLocalStatePatch from './util/createLocalStatePatch'
import styles from './styles/BlockEditor.css'

import SlateValueContainer from './SlateValueContainer'

import FormBuilderNodeOnDrop from './plugins/FormBuilderNodeOnDrop'
import FormBuilderNodeOnPaste from './plugins/FormBuilderNodeOnPaste'
import TextFormattingOnKeyDown from './plugins/TextFormattingOnKeyDown'
import ListItemOnEnterKey from './plugins/ListItemOnEnterKey'
import TextBlockOnEnterKey from './plugins/TextBlockOnEnterKey'

import {
  SLATE_BLOCK_FORMATTING_OPTION_KEYS,
  SLATE_LIST_BLOCKS,
  SLATE_LIST_ITEM_TYPE,
  SLATE_DEFAULT_NODE,
  SLATE_TEXT_BLOCKS
} from './constants'

import Toolbar from './toolbar/Toolbar'

export default class BlockEditor extends React.Component {
  static valueContainer = SlateValueContainer

  static propTypes = {
    type: PropTypes.any,
    field: PropTypes.any,
    level: PropTypes.number,
    value: PropTypes.instanceOf(SlateValueContainer),
    validation: PropTypes.shape({
      errors: PropTypes.array
    }),
    onChange: PropTypes.func
  }

  static defaultProps = {
    onChange() {}
  }

  static contextTypes = {
    formBuilder: PropTypes.object
  }

  constructor(props, context) {
    super(props, context)

    const slateSchema = prepareSlateSchema(this.props.field)
    this.slateSchema = slateSchema.schema
    this.groupedFields = slateSchema.fields
    this.slatePlugins = [
      InsertBlockOnEnter({kind: 'block', type: 'paragraph', nodes: [{kind: 'text', text: '', ranges: []}]}),
      FormBuilderNodeOnDrop(),
      FormBuilderNodeOnPaste(this.context.formBuilder, this.props.field.of),
      TextFormattingOnKeyDown(),
      ListItemOnEnterKey(),
      TextBlockOnEnterKey()
    ]

    this.state = {
      fullscreen: false
    }
  }

  handleInsertBlock = item => {
    const {value, onChange, field} = this.props

    const type = item.type
    const ofField = field.of.find(it => it.type === type)
    const addItemValue = this.context.formBuilder.createFieldValue(undefined, ofField)

    const nextState = value.state
      .transform()
      .insertBlock({
        type: type,
        isVoid: true,
        data: {
          value: addItemValue
        }
      })
      .apply()

    onChange({patch: createLocalStatePatch(nextState)})
  }

  handleOnClickMarkButton = (event, type) => {
    event.preventDefault()
    const {value, onChange} = this.props
    const nextState = value.state
      .transform()
      .toggleMark(type)
      .apply()
    onChange({patch: createLocalStatePatch(nextState)})
  }

  handleOnClickListFormattingButton = (event, listStyle, active) => {
    const {value, onChange} = this.props
    const {state} = value
    const field = this.groupedFields.slate
      .find(sfield => SLATE_LIST_BLOCKS.includes(sfield.type) && sfield.listStyle === listStyle)
    const setBlock = {
      type: field.type,
      data: pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS)
    }
    let transform = state.transform()
    SLATE_LIST_BLOCKS.forEach(type => {
      transform = transform.unwrapBlock(type)
    })
    if (active) {
      if (setBlock.type === SLATE_DEFAULT_NODE) {
        transform.setBlock(setBlock)
      } else {
        transform = transform
          .setBlock(SLATE_LIST_ITEM_TYPE)
          .wrapBlock(setBlock)
      }
    } else {
      transform = transform
        .setBlock(SLATE_DEFAULT_NODE)
    }
    const nextState = transform.apply()
    onChange({patch: createLocalStatePatch(nextState)})
  }

  handleSelectBlockFormatting = selectedValue => {
    const {field} = selectedValue
    const {value, onChange} = this.props
    const {state} = value
    const {selection, startBlock, endBlock} = state
    const block = {
      type: field.type,
      data: pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS)
    }
    let transform = state.transform()

    if (this.isWithinList()) {
      SLATE_LIST_BLOCKS.forEach(type => {
        transform = transform.unwrapBlock(type)
      })
      transform = transform
        .setBlock(block)
      const nextState = transform.apply()
      onChange({patch: createLocalStatePatch(nextState)})
      return
    }

    // If a single block is selected partially, split block conditionally (selection in start, middle or end of text)
    if (startBlock === endBlock
      && selection.isExpanded
      && !(
        selection.hasStartAtStartOf(startBlock)
        && selection.hasEndAtEndOf(startBlock
      )
    )) {
      const hasTextBefore = !selection.hasStartAtStartOf(startBlock)
      const hasTextAfter = !selection.hasEndAtEndOf(startBlock)
      if (hasTextAfter) {
        const extendForward = selection.isForward
          ? (selection.focusOffset - selection.anchorOffset)
          : (selection.anchorOffset - selection.focusOffset)
        transform
          .collapseToStart()
          .splitBlock()
          .moveForward()
          .extendForward(extendForward)
          .collapseToEnd()
          .splitBlock()
          .collapseToStartOfPreviousText()
      } else {
        transform = hasTextBefore ? (
          transform
            .collapseToStart()
            .splitBlock()
            .moveForward()
        ) : (
          transform
            .collapseToEnd()
            .splitBlock()
            .moveTo(selection)
        )
      }
    }
    transform
      .setBlock(block)
    const nextState = transform.apply()
    onChange({patch: createLocalStatePatch(nextState)})
  }

  hasMark(type) {
    const {value} = this.props
    return value.state.marks.some(mark => mark.type == type)
  }

  hasBlock(field) {
    const {value} = this.props
    return value.state.blocks.some(node => node.type === field.type
        && isEqual(
          pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS),
          pick(node.data.toObject(), SLATE_BLOCK_FORMATTING_OPTION_KEYS)
        )
    )
  }

  isWithinList() {
    const {value} = this.props
    const {state} = value
    return state.blocks.some(block => block.type === SLATE_LIST_ITEM_TYPE)
  }

  hasParentBlock(field) {
    const {value} = this.props
    const {state} = value
    const {document} = state
    return state.blocks.some(node => {
      const parent = document.getParent(node)
      return parent && parent.data && parent.type === field.type
        && isEqual(
          pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS),
          pick(parent.data.toObject(), SLATE_BLOCK_FORMATTING_OPTION_KEYS)
        )
    })
  }

  getActiveMarks() {
    const {value} = this.props
    if (!value.state.blocks) {
      return []
    }
    const anchorBlock = value.state.blocks
      .filter(node => SLATE_TEXT_BLOCKS.concat(SLATE_LIST_ITEM_TYPE)
        .includes(node.type) && value.state.selection.hasAnchorIn(node)
      )
      .map(node => node.type).toArray()[0]
    if (!anchorBlock) {
      return []
    }
    const marksField = this.groupedFields.slate.find(field => field.type === anchorBlock)
    if (!marksField || !marksField.marks) {
      return []
    }
    return marksField.marks.map(mark => {
      return {
        type: mark,
        active: this.hasMark(mark)
      }
    })
  }

  getListFormats() {
    if (!this.groupedFields.slate.filter(field => SLATE_LIST_BLOCKS.includes(field.type)).length) {
      return []
    }
    return this.groupedFields.slate
      .filter(field => SLATE_LIST_BLOCKS.includes(field.type))
      .map((field, index) => {
        return {
          type: field.listStyle,
          title: field.title,
          active: this.hasParentBlock(field)
        }
      })
  }

  getTextFormats() {
    if (!this.groupedFields.slate.length) {
      return []
    }
    const items = this.groupedFields.slate
      .filter(field => SLATE_TEXT_BLOCKS.includes(field.type))
      .map((field, index) => {
        return {
          key: `blockFormat-${index}`,
          preview: this.slateSchema.nodes[field.type](
            Object.assign(
              {isPreview: true},
              {children: {field.title}},
              pick(field, SLATE_BLOCK_FORMATTING_OPTION_KEYS)
            )
          ),
          field: field,
          title: ` ${field.title}`,
          active: this.hasBlock(field)
        }
      })
    let value = items.filter(item => item.active)
    if (value.length === 0) {
      value = [{
        key: 'blockFormat-none',
        preview: null,
        field: null,
        title: 'No style',
        active: true
      }]
    }
    return {
      items: items,
      value: value
    }
  }

  handleToggleFullscreen = () => {
    this.setState({
      fullscreen: !this.state.fullscreen
    })
  }

  handleEditorChange = nextState => {
    this.props.onChange({patch: createLocalStatePatch(nextState)})
  }

  render() {
    const {validation, value, field, level} = this.props
    const hasError = validation && validation.messages && validation.messages.length > 0
    const inputId = uniqueId('FormBuilderText')
    return (
      <FormField label={field.title} labelHtmlFor={inputId} level={level}>

          <Toolbar
            className={styles.toolbar}
            onInsertBlock={this.handleInsertBlock}
            insertBlocks={this.groupedFields.formBuilder || []}
            onFullscreenEnable={this.handleToggleFullscreen}
            fullscreen={this.state.fullscreen}
            onMarkButtonClick={this.handleOnClickMarkButton}
            onListButtonClick={this.handleOnClickListFormattingButton}
            onFormatSelectChange={this.handleSelectBlockFormatting}
            listFormats={this.getListFormats()}
            textFormats={this.getTextFormats()}
            marks={this.getActiveMarks()}
          />

            <Editor
              className={styles.input}
              onChange={this.handleEditorChange}
              placeholder=""
              state={value.state}
              plugins={this.slatePlugins}
              schema={this.slateSchema}
            />

      </FormField>
    )
  }
}
<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return M<commit_msg>Correcting style<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return Ma<|endoftext|>