Use number generator with seed

Use number generator with seed

--- examples/instances.js
+++ examples/instances.js
@@ -1,9 +1,13 @@
 var instances = require('./../taillard');
 var NEH = require('./../neh');
+var seed = require('./../seed-random');

 // Iterate over filtered Taillard instances
 var filteredInstances = instances.filter(50, 20);
 for(var i = 0; i < filteredInstances.length; i++) {
+
+    // Overwrite Math.random by number generator with seed
+    seed(filteredInstances[i].initialSeed, true);

     console.log('               name:', filteredInstances[i].name);
     console.log('     number of jobs:', filteredInstances[i].numberOfJobs);

<|original_code|>
var instances = require('./../taillard');
var NEH = require('./../neh');

// Iterate over filtered Taillard instances
var filteredInstances = instances.filter(50, 20);
for(var i = 0; i < filteredInstances.length; i++) {

    console.log('               name:', filteredInstances[i].name);
    console.log('     number of jobs:', filteredInstances[i].numberOfJobs);
    console.log(' number of machines:', filteredInstances[i].numberOfMachines);
    console.log('       initial seed:', filteredInstances[i].initialSeed);
    console.log('        lower bound:', filteredInstances[i].lowerBound);
    console.log('        upper bound:', filteredInstances[i].upperBound);
    console.log('       NEH makespan:', NEH.makespan(filteredInstances[i].data));
    console.log('__________________________________________________');

}

<|edits_diff|>
--- examples/instances.js
+++ examples/instances.js
@@ -1,5 +1,6 @@
 var instances = require('./../taillard');
 var NEH = require('./../neh');
+var seed = require('./../seed-random');

 // Iterate over filtered Taillard instances
 var filteredInstances = instances.filter(50, 20);
<|current_version|>
var instances = require('./../taillard');
var NEH = require('./../neh');
var seed = require('./../seed-random');

// Iterate over filtered Taillard instances
var filteredInstances = instances.filter(50, 20);
for(var i = 0; i < filteredInstances.length; i++) {

    console.log('               name:', filteredInstances[i].name);
    console.log('     number of jobs:', filteredInstances[i].numberOfJobs);
    console.log(' number of machines:', filteredInstances[i].numberOfMachines);
    console.log('       initial seed:', filteredInstances[i].initialSeed);
    console.log('        lower bound:', filteredInstances[i].lowerBound);
    console.log('        upper bound:', filteredInstances[i].upperBound);
    console.log('       NEH makespan:', NEH.makespan(filteredInstances[i].data));
    console.log('__________________________________________________');

}

<|next_version|>
var instances = require('./../taillard');
var NEH = require('./../neh');
var seed = require('./../seed-random');

// Iterate over filtered Taillard instances
var filteredInstances = instances.filter(50, 20);
for(var i = 0; i < filteredInstances.length; i++) {

    // Overwrite Math.random by number generator with seed
    seed(filteredInstances[i].initialSeed, true);

    console.log('               name:', filteredInstances[i].name);
    console.log('     number of jobs:', filteredInstances[i].numberOfJobs);
    console.log(' number of machines:', filteredInstances[i].numberOfMachines);
    console.log('       initial seed:', filteredInstances[i].initialSeed);
    console.log('        lower bound:', filteredInstances[i].lowerBound);
    console.log('        upper bound:', filteredInstances[i].upperBound);
    console.log('       NEH makespan:', NEH.makespan(filteredInstances[i].data));
    console.log('__________________________________________________');

}


Define context for setupTips if undefined

--- src/sunstone/public/app/utils/tips.js
+++ src/sunstone/public/app/utils/tips.js
@@ -3,6 +3,10 @@
   //Replaces all class"tip" divs with an information icon that
   //displays the tip information on mouseover.
   var _setup = function(context, position) {
+    if (!context) {
+      context = $(document);
+    }
+
     //For each tip in this context
     $('.tip', context).each(function() {
       var obj = $(this);
@@ -16,6 +20,7 @@
       //replace the text with an icon and spans
       obj.html('');
     });
+
     context.foundation('reflow', 'tooltip');
   }

<|original_code|>
define(function(require) {
  require('foundation.tooltip');
  //Replaces all class"tip" divs with an information icon that
  //displays the tip information on mouseover.
  var _setup = function(context, position) {
    //For each tip in this context
    $('.tip', context).each(function() {
      var obj = $(this);
      obj.removeClass('tip');
      var tip = obj.html();

      var tip_classes = ['has-tip']
      if (position) {
        tip_classes.push(position)
      }
      //replace the text with an icon and spans
      obj.html('');
    });
    context.foundation('reflow', 'tooltip');
  }

  var _html = function(str) {
    return ''
  }

  return {
    'setup': _setup,
    'html': _html
  }
})

<|edits_diff|>
--- src/sunstone/public/app/utils/tips.js
+++ src/sunstone/public/app/utils/tips.js
@@ -3,6 +3,10 @@
   //Replaces all class"tip" divs with an information icon that
   //displays the tip information on mouseover.
   var _setup = function(context, position) {
+    if (!context) {
+      context = $(document);
+    }
+
     //For each tip in this context
     $('.tip', context).each(function() {
       var obj = $(this);
<|current_version|>
define(function(require) {
  require('foundation.tooltip');
  //Replaces all class"tip" divs with an information icon that
  //displays the tip information on mouseover.
  var _setup = function(context, position) {
    if (!context) {
      context = $(document);
    }

    //For each tip in this context
    $('.tip', context).each(function() {
      var obj = $(this);
      obj.removeClass('tip');
      var tip = obj.html();

      var tip_classes = ['has-tip']
      if (position) {
        tip_classes.push(position)
      }
      //replace the text with an icon and spans
      obj.html('');
    });
    context.foundation('reflow', 'tooltip');
  }

  var _html = function(str) {
    return ''
  }

  return {
    'setup': _setup,
    'html': _html
  }
})

<|next_version|>
define(function(require) {
  require('foundation.tooltip');
  //Replaces all class"tip" divs with an information icon that
  //displays the tip information on mouseover.
  var _setup = function(context, position) {
    if (!context) {
      context = $(document);
    }

    //For each tip in this context
    $('.tip', context).each(function() {
      var obj = $(this);
      obj.removeClass('tip');
      var tip = obj.html();

      var tip_classes = ['has-tip']
      if (position) {
        tip_classes.push(position)
      }
      //replace the text with an icon and spans
      obj.html('');
    });

    context.foundation('reflow', 'tooltip');
  }

  var _html = function(str) {
    return ''
  }

  return {
    'setup': _setup,
    'html': _html
  }
})


Add a notification zero state

Add a notification zero state

--- src/actions/notifications.js
+++ src/actions/notifications.js
@@ -1,8 +1,10 @@
+import React from 'react'
 import * as ACTION_TYPES from '../constants/action_types'
 import * as MAPPING_TYPES from '../constants/mapping_types'
 import * as api from '../networking/api'
 import * as StreamFilters from '../components/streams/StreamFilters'
 import * as StreamRenderables from '../components/streams/StreamRenderables'
+import { ZeroState } from '../components/zeros/Zeros'

 export function loadNotifications(params = {}) {
   return {
@@ -13,6 +15,7 @@
       renderStream: {
         asList: StreamRenderables.notificationList,
         asGrid: StreamRenderables.notificationList,
+        asZero: <ZeroState>Sorry, no notifications found.</ZeroState>,
       },
       resultFilter: StreamFilters.notificationsFromActivities,
     },

<|original_code|>
import * as ACTION_TYPES from '../constants/action_types'
import * as MAPPING_TYPES from '../constants/mapping_types'
import * as api from '../networking/api'
import * as StreamFilters from '../components/streams/StreamFilters'
import * as StreamRenderables from '../components/streams/StreamRenderables'

export function loadNotifications(params = {}) {
  return {
    type: ACTION_TYPES.LOAD_STREAM,
    payload: { endpoint: api.notifications(params), vo: {} },
    meta: {
      mappingType: MAPPING_TYPES.ACTIVITIES,
      renderStream: {
        asList: StreamRenderables.notificationList,
        asGrid: StreamRenderables.notificationList,
      },
      resultFilter: StreamFilters.notificationsFromActivities,
    },
  }
}

<|edits_diff|>
--- src/actions/notifications.js
+++ src/actions/notifications.js
@@ -1,8 +1,10 @@
+import React from 'react'
 import * as ACTION_TYPES from '../constants/action_types'
 import * as MAPPING_TYPES from '../constants/mapping_types'
 import * as api from '../networking/api'
 import * as StreamFilters from '../components/streams/StreamFilters'
 import * as StreamRenderables from '../components/streams/StreamRenderables'
+import { ZeroState } from '../components/zeros/Zeros'

 export function loadNotifications(params = {}) {
   return {
<|current_version|>
import React from 'react'
import * as ACTION_TYPES from '../constants/action_types'
import * as MAPPING_TYPES from '../constants/mapping_types'
import * as api from '../networking/api'
import * as StreamFilters from '../components/streams/StreamFilters'
import * as StreamRenderables from '../components/streams/StreamRenderables'
import { ZeroState } from '../components/zeros/Zeros'

export function loadNotifications(params = {}) {
  return {
    type: ACTION_TYPES.LOAD_STREAM,
    payload: { endpoint: api.notifications(params), vo: {} },
    meta: {
      mappingType: MAPPING_TYPES.ACTIVITIES,
      renderStream: {
        asList: StreamRenderables.notificationList,
        asGrid: StreamRenderables.notificationList,
      },
      resultFilter: StreamFilters.notificationsFromActivities,
    },
  }
}

<|next_version|>
import React from 'react'
import * as ACTION_TYPES from '../constants/action_types'
import * as MAPPING_TYPES from '../constants/mapping_types'
import * as api from '../networking/api'
import * as StreamFilters from '../components/streams/StreamFilters'
import * as StreamRenderables from '../components/streams/StreamRenderables'
import { ZeroState } from '../components/zeros/Zeros'

export function loadNotifications(params = {}) {
  return {
    type: ACTION_TYPES.LOAD_STREAM,
    payload: { endpoint: api.notifications(params), vo: {} },
    meta: {
      mappingType: MAPPING_TYPES.ACTIVITIES,
      renderStream: {
        asList: StreamRenderables.notificationList,
        asGrid: StreamRenderables.notificationList,
        asZero: <ZeroState>Sorry, no notifications found.</ZeroState>,
      },
      resultFilter: StreamFilters.notificationsFromActivities,
    },
  }
}


Set jsx curly spacing eslint rule

Set jsx curly spacing eslint rule

--- .eslintrc.js
+++ .eslintrc.js
@@ -10,6 +10,14 @@
 		"eslint:recommended",
 		"plugin:react/recommended"
 	],
+  "parserOptions": {
+    "ecmaFeatures": {
+      "jsx": true
+    }
+  },
 	"rules": {
+    "react/jsx-curly-spacing": [2, "always", { "spacing": {
+      "objectLiterals": "never"
+    }}]
 	}
 };

<|original_code|>
module.exports = {
	"parser": "babel-eslint",
	"env": {
		"browser": true
	},
	"plugins": [
		"react"
	],
	"extends": [
		"eslint:recommended",
		"plugin:react/recommended"
	],
	"rules": {
	}
};

<|edits_diff|>
--- .eslintrc.js
+++ .eslintrc.js
@@ -10,6 +10,11 @@
 		"eslint:recommended",
 		"plugin:react/recommended"
 	],
+  "parserOptions": {
+    "ecmaFeatures": {
+      "jsx": true
+    }
+  },
 	"rules": {
 	}
 };
<|current_version|>
module.exports = {
	"parser": "babel-eslint",
	"env": {
		"browser": true
	},
	"plugins": [
		"react"
	],
	"extends": [
		"eslint:recommended",
		"plugin:react/recommended"
	],
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    }
  },
	"rules": {
	}
};

<|next_version|>
module.exports = {
	"parser": "babel-eslint",
	"env": {
		"browser": true
	},
	"plugins": [
		"react"
	],
	"extends": [
		"eslint:recommended",
		"plugin:react/recommended"
	],
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    }
  },
	"rules": {
    "react/jsx-curly-spacing": [2, "always", { "spacing": {
      "objectLiterals": "never"
    }}]
	}
};


Handle errors when traversing the node_modules dir to stop EventEmitter throwing an exception

--- packages/navy-plugin-nodejs/src/hooks/rewrite-linked-node-modules.js
+++ packages/navy-plugin-nodejs/src/hooks/rewrite-linked-node-modules.js
@@ -1,9 +1,16 @@
 import findit from 'findit'
 import path from 'path'
 import fs from 'fs'
+import os from 'os'
+
+import {name as pluginName} from '../../package.json'

 export default () => {
   const finder = findit(path.join(process.cwd(), 'node_modules'))
+
+  finder.on('error', err => {
+    console.error(`${pluginName} failed to traverse your node_modules directory:`, os.EOL, err.toString())
+  })

   finder.on('link', link => {
     if (link.indexOf('.bin') !== -1) return

<|original_code|>
import findit from 'findit'
import path from 'path'
import fs from 'fs'

export default () => {
  const finder = findit(path.join(process.cwd(), 'node_modules'))

  finder.on('link', link => {
    if (link.indexOf('.bin') !== -1) return

    const absolutePath = fs.realpathSync(link)
    fs.unlinkSync(link)
    fs.symlinkSync(absolutePath, link)

    console.log('Linked', link, '->', absolutePath)
  })
}

<|edits_diff|>
--- packages/navy-plugin-nodejs/src/hooks/rewrite-linked-node-modules.js
+++ packages/navy-plugin-nodejs/src/hooks/rewrite-linked-node-modules.js
@@ -1,6 +1,9 @@
 import findit from 'findit'
 import path from 'path'
 import fs from 'fs'
+import os from 'os'
+
+import {name as pluginName} from '../../package.json'

 export default () => {
   const finder = findit(path.join(process.cwd(), 'node_modules'))
<|current_version|>
import findit from 'findit'
import path from 'path'
import fs from 'fs'
import os from 'os'

import {name as pluginName} from '../../package.json'

export default () => {
  const finder = findit(path.join(process.cwd(), 'node_modules'))

  finder.on('link', link => {
    if (link.indexOf('.bin') !== -1) return

    const absolutePath = fs.realpathSync(link)
    fs.unlinkSync(link)
    fs.symlinkSync(absolutePath, link)

    console.log('Linked', link, '->', absolutePath)
  })
}

<|next_version|>
import findit from 'findit'
import path from 'path'
import fs from 'fs'
import os from 'os'

import {name as pluginName} from '../../package.json'

export default () => {
  const finder = findit(path.join(process.cwd(), 'node_modules'))

  finder.on('error', err => {
    console.error(`${pluginName} failed to traverse your node_modules directory:`, os.EOL, err.toString())
  })

  finder.on('link', link => {
    if (link.indexOf('.bin') !== -1) return

    const absolutePath = fs.realpathSync(link)
    fs.unlinkSync(link)
    fs.symlinkSync(absolutePath, link)

    console.log('Linked', link, '->', absolutePath)
  })
}


Add touch input to puzzle rendering function

--- prelim/renderPuzzle.js
+++ prelim/renderPuzzle.js
@@ -18,5 +18,8 @@

     var inputController = new InputController( vc );
     var keyboardInput = new KeyboardInput(inputController);
+    var touchInput = new TouchInput(inputController, canvas);
+
     keyboardInput.listen();
+    touchInput.listen();
 }

<|original_code|>
function renderPuzzle( levelNumber, canvas, width, height ) {

    document.body.appendChild(canvas);

    canvas.width = width;
    canvas.height = height;

    canvas.style.backgroundColor = '#333333';

    canvas.id = 'gameView';

    var levels = new Levels( new XSPRNG(1), 70, new MonochromaticPaletteBuilder());
    var level = levels.get(levelNumber);

    var vc = new ViewController( level, canvas, 2, 'white' );

    vc.draw();

    var inputController = new InputController( vc );
    var keyboardInput = new KeyboardInput(inputController);
    keyboardInput.listen();
}

<|edits_diff|>
--- prelim/renderPuzzle.js
+++ prelim/renderPuzzle.js
@@ -18,5 +18,7 @@

     var inputController = new InputController( vc );
     var keyboardInput = new KeyboardInput(inputController);
+    var touchInput = new TouchInput(inputController, canvas);
+
     keyboardInput.listen();
 }
<|current_version|>
function renderPuzzle( levelNumber, canvas, width, height ) {

    document.body.appendChild(canvas);

    canvas.width = width;
    canvas.height = height;

    canvas.style.backgroundColor = '#333333';

    canvas.id = 'gameView';

    var levels = new Levels( new XSPRNG(1), 70, new MonochromaticPaletteBuilder());
    var level = levels.get(levelNumber);

    var vc = new ViewController( level, canvas, 2, 'white' );

    vc.draw();

    var inputController = new InputController( vc );
    var keyboardInput = new KeyboardInput(inputController);
    var touchInput = new TouchInput(inputController, canvas);

    keyboardInput.listen();
}

<|next_version|>
function renderPuzzle( levelNumber, canvas, width, height ) {

    document.body.appendChild(canvas);

    canvas.width = width;
    canvas.height = height;

    canvas.style.backgroundColor = '#333333';

    canvas.id = 'gameView';

    var levels = new Levels( new XSPRNG(1), 70, new MonochromaticPaletteBuilder());
    var level = levels.get(levelNumber);

    var vc = new ViewController( level, canvas, 2, 'white' );

    vc.draw();

    var inputController = new InputController( vc );
    var keyboardInput = new KeyboardInput(inputController);
    var touchInput = new TouchInput(inputController, canvas);

    keyboardInput.listen();
    touchInput.listen();
}


$().ready(function () {

  $("form.comment").on("submit", function (event) {
    event.preventDefault();
    var $form = $(this);
    var $comments = $(".comment-group");
    $.ajax({
      type: $form.attr("method"),
      url: $form.attr("action"),
      data: $form.serialize(),
      success: function (e, status) {
        $comments.prepend("<p>"+e.content+"</p>");
      },
      error: function (e, status) {
        var errors = e.responseJSON;
        $form.find(".content").addClass("has-error").find("span.tip").text(errors.content[0])
      }
    });
    return false;
  });

});

$().ready(function () {

  $("form.comment").on("submit", function (event) {
    event.preventDefault();
    var $form = $(this);
    var $comments = $(".comment-group");
    var $input = $("textarea.comment");
    $.ajax({
      type: $form.attr("method"),
      url: $form.attr("action"),
      data: $form.serialize(),
      success: function (e, status) {
        $comments.prepend("<p>"+e.content+"</p>");
        $input.val("");
      },
      error: function (e, status) {
        var errors = e.responseJSON;
        $form.find(".content").addClass("has-error").find("span.tip").text(errors.content[0])
      }
    });
    return false;
  });

});

Clear textarea after posting successfully

--- sigh/static/js/sigh.js
+++ sigh/static/js/sigh.js
@@ -4,12 +4,14 @@
     event.preventDefault();
     var $form = $(this);
     var $comments = $(".comment-group");
+    var $input = $("textarea.comment");
     $.ajax({
       type: $form.attr("method"),
       url: $form.attr("action"),
       data: $form.serialize(),
       success: function (e, status) {
         $comments.prepend("<p>"+e.content+"</p>");
+        $input.val("");
       },
       error: function (e, status) {
         var errors = e.responseJSON;

$().ready(function () {

  $("form.comment").on("submit", function (event) {
    event.preventDefault();
    var $form = $(this);
    var $comments = $(".comment-group");
    var $input = $("textarea.comment");
    $.ajax({
      type: $form.attr("method"),
      url: $form.attr("action"),
      data: $form.serialize(),
      success: function (e, status) {
        $comments.prepend("<p>"+e.content+"</p>");
      },
      error: function (e, status) {
        var errors = e.responseJSON;
        $form.find(".content").addClass("has-error").find("span.tip").text(errors.content[0])
      }
    });
    return false;
  });

});

<|original_code|>
$().ready(function () {

  $("form.comment").on("submit", function (event) {
    event.preventDefault();
    var $form = $(this);
    var $comments = $(".comment-group");
    $.ajax({
      type: $form.attr("method"),
      url: $form.attr("action"),
      data: $form.serialize(),
      success: function (e, status) {
        $comments.prepend("
"+e.content+"
");
      },
      error: function (e, status) {
        var errors = e.responseJSON;
        $form.find(".content").addClass("has-error").find("span.tip").text(errors.content[0])
      }
    });
    return false;
  });

});
<|edits_diff|>
--- sigh/static/js/sigh.js
+++ sigh/static/js/sigh.js
@@ -4,6 +4,7 @@
     event.preventDefault();
     var $form = $(this);
     var $comments = $(".comment-group");
+    var $input = $("textarea.comment");
     $.ajax({
       type: $form.attr("method"),
       url: $form.attr("action"),
<|current_version|>
$().ready(function () {

  $("form.comment").on("submit", function (event) {
    event.preventDefault();
    var $form = $(this);
    var $comments = $(".comment-group");
    var $input = $("textarea.comment");
    $.ajax({
      type: $form.attr("method"),
      url: $form.attr("action"),
      data: $form.serialize(),
      success: function (e, status) {
        $comments.prepend("
"+e.content+"
");
      },
      error: function (e, status) {
        var errors = e.responseJSON;
        $form.find(".content").addClass("has-error").find("span.tip").text(errors.content[0])
      }
    });
    return false;
  });

});

<|next_version|>
$().ready(function () {

  $("form.comment").on("submit", function (event) {
    event.preventDefault();
    var $form = $(this);
    var $comments = $(".comment-group");
    var $input = $("textarea.comment");
    $.ajax({
      type: $form.attr("method"),
      url: $form.attr("action"),
      data: $form.serialize(),
      success: function (e, status) {
        $comments.prepend("
"+e.content+"
");
        $input.val("");
      },
      error: function (e, status) {
        var errors = e.responseJSON;
        $form.find(".content").addClass("has-error").find("span.tip").text(errors.content[0])
      }
    });
    return false;
  });

});


Copy space separeted title and url to clipboard

--- popup.js
+++ popup.js
@@ -18,6 +18,7 @@
   var url = document.getElementById('page_url');
   var copyTitle = document.getElementById('copy_title');
   var copyUrl = document.getElementById('copy_url');
+  var copyAll = document.getElementById('copy_all');

   // Get tab info
   chrome.tabs.query({ active: true }, function(tabs){
@@ -40,5 +41,10 @@
       // Copy title to clipboard
       copyToClipboard(tabs[0].url);
     });
+    copyAll.addEventListener('click', function(){
+      'use strict';
+
+      copyToClipboard(tabs[0].title + ' ' + tabs[0].url);
+    });
   });
 });

<|original_code|>
function copyToClipboard(str){
  'use strict';

  // Copy str to clipboard
  var textArea = document.createElement('textarea');
  document.body.appendChild(textArea);
  textArea.value = str;
  textArea.select();
  document.execCommand('copy');
  document.body.removeChild(textArea);
}

window.addEventListener('load', function(){
  'use strict';

  // Get elements
  var title = document.getElementById('page_title');
  var url = document.getElementById('page_url');
  var copyTitle = document.getElementById('copy_title');
  var copyUrl = document.getElementById('copy_url');

  // Get tab info
  chrome.tabs.query({ active: true }, function(tabs){
    'use strict';

    // Show title and url
    title.innerHTML = tabs[0].title;
    url.innerHTML = tabs[0].url;

    // Add click listener to copy button
    copyTitle.addEventListener('click', function(){
      'use strict';

      // Copy title to clipboard
      copyToClipboard(tabs[0].title);
    });
    copyUrl.addEventListener('click', function(){
      'use strict';

      // Copy title to clipboard
      copyToClipboard(tabs[0].url);
    });
  });
});

<|edits_diff|>
--- popup.js
+++ popup.js
@@ -18,6 +18,7 @@
   var url = document.getElementById('page_url');
   var copyTitle = document.getElementById('copy_title');
   var copyUrl = document.getElementById('copy_url');
+  var copyAll = document.getElementById('copy_all');

   // Get tab info
   chrome.tabs.query({ active: true }, function(tabs){
<|current_version|>
function copyToClipboard(str){
  'use strict';

  // Copy str to clipboard
  var textArea = document.createElement('textarea');
  document.body.appendChild(textArea);
  textArea.value = str;
  textArea.select();
  document.execCommand('copy');
  document.body.removeChild(textArea);
}

window.addEventListener('load', function(){
  'use strict';

  // Get elements
  var title = document.getElementById('page_title');
  var url = document.getElementById('page_url');
  var copyTitle = document.getElementById('copy_title');
  var copyUrl = document.getElementById('copy_url');
  var copyAll = document.getElementById('copy_all');

  // Get tab info
  chrome.tabs.query({ active: true }, function(tabs){
    'use strict';

    // Show title and url
    title.innerHTML = tabs[0].title;
    url.innerHTML = tabs[0].url;

    // Add click listener to copy button
    copyTitle.addEventListener('click', function(){
      'use strict';

      // Copy title to clipboard
      copyToClipboard(tabs[0].title);
    });
    copyUrl.addEventListener('click', function(){
      'use strict';

      // Copy title to clipboard
      copyToClipboard(tabs[0].url);
    });
  });
});

<|next_version|>
function copyToClipboard(str){
  'use strict';

  // Copy str to clipboard
  var textArea = document.createElement('textarea');
  document.body.appendChild(textArea);
  textArea.value = str;
  textArea.select();
  document.execCommand('copy');
  document.body.removeChild(textArea);
}

window.addEventListener('load', function(){
  'use strict';

  // Get elements
  var title = document.getElementById('page_title');
  var url = document.getElementById('page_url');
  var copyTitle = document.getElementById('copy_title');
  var copyUrl = document.getElementById('copy_url');
  var copyAll = document.getElementById('copy_all');

  // Get tab info
  chrome.tabs.query({ active: true }, function(tabs){
    'use strict';

    // Show title and url
    title.innerHTML = tabs[0].title;
    url.innerHTML = tabs[0].url;

    // Add click listener to copy button
    copyTitle.addEventListener('click', function(){
      'use strict';

      // Copy title to clipboard
      copyToClipboard(tabs[0].title);
    });
    copyUrl.addEventListener('click', function(){
      'use strict';

      // Copy title to clipboard
      copyToClipboard(tabs[0].url);
    });
    copyAll.addEventListener('click', function(){
      'use strict';

      copyToClipboard(tabs[0].title + ' ' + tabs[0].url);
    });
  });
});


Set user's activity tracking on tab events

Update user's activity tracking on any tab opening or closing.

--- source/background/library/browserEvents.js
+++ source/background/library/browserEvents.js
@@ -1,12 +1,14 @@
 import log from "../../shared/library/log.js";
 import { dispatch } from "../redux/index.js";
 import { setAuthToken } from "../../shared/actions/dropbox.js";
+import { setUserActivity } from "../../shared/actions/app.js";

 const BUTTERCUP_DOMAIN_REXP = /^https:\/\/buttercup.pw\//;
 const DROPBOX_ACCESS_TOKEN_REXP = /access_token=([^&]+)/;

 export function attachBrowserStateListeners() {
     chrome.tabs.onUpdated.addListener(handleTabUpdatedEvent);
+    chrome.tabs.onRemoved.addListener(handleTabRemovedEvent);
 }

 function handleTabUpdatedEvent(tabID, changeInfo) {
@@ -21,4 +23,12 @@
             chrome.tabs.remove(tabID);
         }
     }
+
+    if (changeInfo.status === "loading") {
+        dispatch(setUserActivity());
+    }
 }
+
+function handleTabRemovedEvent(tabID, removeInfo) {
+    dispatch(setUserActivity());
+}

<|original_code|>
import log from "../../shared/library/log.js";
import { dispatch } from "../redux/index.js";
import { setAuthToken } from "../../shared/actions/dropbox.js";

const BUTTERCUP_DOMAIN_REXP = /^https:\/\/buttercup.pw\//;
const DROPBOX_ACCESS_TOKEN_REXP = /access_token=([^&]+)/;

export function attachBrowserStateListeners() {
    chrome.tabs.onUpdated.addListener(handleTabUpdatedEvent);
}

function handleTabUpdatedEvent(tabID, changeInfo) {
    // This event: https://developer.chrome.com/extensions/tabs#event-onUpdated
    const { url } = changeInfo;
    if (BUTTERCUP_DOMAIN_REXP.test(url)) {
        const accessTokenMatch = url.match(DROPBOX_ACCESS_TOKEN_REXP);
        if (accessTokenMatch) {
            const token = accessTokenMatch[1];
            log.info(`Retrieved Dropbox access token from tab: ${tabID}`);
            dispatch(setAuthToken(token));
            chrome.tabs.remove(tabID);
        }
    }
}

<|edits_diff|>
--- source/background/library/browserEvents.js
+++ source/background/library/browserEvents.js
@@ -1,12 +1,14 @@
 import log from "../../shared/library/log.js";
 import { dispatch } from "../redux/index.js";
 import { setAuthToken } from "../../shared/actions/dropbox.js";
+import { setUserActivity } from "../../shared/actions/app.js";

 const BUTTERCUP_DOMAIN_REXP = /^https:\/\/buttercup.pw\//;
 const DROPBOX_ACCESS_TOKEN_REXP = /access_token=([^&]+)/;

 export function attachBrowserStateListeners() {
     chrome.tabs.onUpdated.addListener(handleTabUpdatedEvent);
+    chrome.tabs.onRemoved.addListener(handleTabRemovedEvent);
 }

 function handleTabUpdatedEvent(tabID, changeInfo) {
@@ -21,4 +23,8 @@
             chrome.tabs.remove(tabID);
         }
     }
+
+    if (changeInfo.status === "loading") {
+        dispatch(setUserActivity());
+    }
 }
<|current_version|>
import log from "../../shared/library/log.js";
import { dispatch } from "../redux/index.js";
import { setAuthToken } from "../../shared/actions/dropbox.js";
import { setUserActivity } from "../../shared/actions/app.js";

const BUTTERCUP_DOMAIN_REXP = /^https:\/\/buttercup.pw\//;
const DROPBOX_ACCESS_TOKEN_REXP = /access_token=([^&]+)/;

export function attachBrowserStateListeners() {
    chrome.tabs.onUpdated.addListener(handleTabUpdatedEvent);
    chrome.tabs.onRemoved.addListener(handleTabRemovedEvent);
}

function handleTabUpdatedEvent(tabID, changeInfo) {
    // This event: https://developer.chrome.com/extensions/tabs#event-onUpdated
    const { url } = changeInfo;
    if (BUTTERCUP_DOMAIN_REXP.test(url)) {
        const accessTokenMatch = url.match(DROPBOX_ACCESS_TOKEN_REXP);
        if (accessTokenMatch) {
            const token = accessTokenMatch[1];
            log.info(`Retrieved Dropbox access token from tab: ${tabID}`);
            dispatch(setAuthToken(token));
            chrome.tabs.remove(tabID);
        }
    }

    if (changeInfo.status === "loading") {
        dispatch(setUserActivity());
    }
}

<|next_version|>
import log from "../../shared/library/log.js";
import { dispatch } from "../redux/index.js";
import { setAuthToken } from "../../shared/actions/dropbox.js";
import { setUserActivity } from "../../shared/actions/app.js";

const BUTTERCUP_DOMAIN_REXP = /^https:\/\/buttercup.pw\//;
const DROPBOX_ACCESS_TOKEN_REXP = /access_token=([^&]+)/;

export function attachBrowserStateListeners() {
    chrome.tabs.onUpdated.addListener(handleTabUpdatedEvent);
    chrome.tabs.onRemoved.addListener(handleTabRemovedEvent);
}

function handleTabUpdatedEvent(tabID, changeInfo) {
    // This event: https://developer.chrome.com/extensions/tabs#event-onUpdated
    const { url } = changeInfo;
    if (BUTTERCUP_DOMAIN_REXP.test(url)) {
        const accessTokenMatch = url.match(DROPBOX_ACCESS_TOKEN_REXP);
        if (accessTokenMatch) {
            const token = accessTokenMatch[1];
            log.info(`Retrieved Dropbox access token from tab: ${tabID}`);
            dispatch(setAuthToken(token));
            chrome.tabs.remove(tabID);
        }
    }

    if (changeInfo.status === "loading") {
        dispatch(setUserActivity());
    }
}

function handleTabRemovedEvent(tabID, removeInfo) {
    dispatch(setUserActivity());
}


Load Metadata and Utils in node

Load Metadata and Utils in node

--- src/peeracle.js
+++ src/peeracle.js
@@ -3,7 +3,9 @@
 (function () {
   var Peeracle = {};
   Peeracle.Media = require('./media');
+  Peeracle.Metadata = require('./metadata');
   Peeracle.Peer = require('./peer');
   Peeracle.Tracker = require('./tracker');
+  Peeracle.Utils = require('./utils');
   module.exports = Peeracle;
 })();

<|original_code|>
'use strict';

(function () {
  var Peeracle = {};
  Peeracle.Media = require('./media');
  Peeracle.Peer = require('./peer');
  Peeracle.Tracker = require('./tracker');
  module.exports = Peeracle;
})();

<|edits_diff|>
--- src/peeracle.js
+++ src/peeracle.js
@@ -3,6 +3,7 @@
 (function () {
   var Peeracle = {};
   Peeracle.Media = require('./media');
+  Peeracle.Metadata = require('./metadata');
   Peeracle.Peer = require('./peer');
   Peeracle.Tracker = require('./tracker');
   module.exports = Peeracle;
<|current_version|>
'use strict';

(function () {
  var Peeracle = {};
  Peeracle.Media = require('./media');
  Peeracle.Metadata = require('./metadata');
  Peeracle.Peer = require('./peer');
  Peeracle.Tracker = require('./tracker');
  module.exports = Peeracle;
})();

<|next_version|>
'use strict';

(function () {
  var Peeracle = {};
  Peeracle.Media = require('./media');
  Peeracle.Metadata = require('./metadata');
  Peeracle.Peer = require('./peer');
  Peeracle.Tracker = require('./tracker');
  Peeracle.Utils = require('./utils');
  module.exports = Peeracle;
})();


'use strict';

// Bot
const bot = require('../../bot');
const { replyOptions } = require('../../bot/options');

const { addGroup, managesGroup } = require('../../stores/group');
const { masterID } = require('../../config.json');

const addedToGroupHandler = async (ctx, next) => {
	const msg = ctx.message;

	const wasAdded = msg.new_chat_members.some(user =>
		user.username === ctx.me);
	if (wasAdded && ctx.from.id === masterID) {
		if (!await managesGroup(ctx.chat)) {
			const link = await bot.telegram.exportChatInviteLink(ctx.chat.id);
			ctx.chat.link = link ? link : '';
			await addGroup(ctx.chat);
		}
		ctx.reply('🛠 <b>Ok, I\'ll help you manage this group from now.</b>',
			replyOptions);
	}

	return next();
};

module.exports = addedToGroupHandler;

'use strict';

// Bot
const bot = require('../../bot');
const { replyOptions } = require('../../bot/options');

const { admin } = require('../../stores/user');
const { addGroup, managesGroup } = require('../../stores/group');
const { masterID } = require('../../config.json');

const addedToGroupHandler = async (ctx, next) => {
	const msg = ctx.message;

	const wasAdded = msg.new_chat_members.some(user =>
		user.username === ctx.me);
	if (wasAdded && ctx.from.id === masterID) {
		admin(ctx.from);
		if (!await managesGroup(ctx.chat)) {
			const link = await bot.telegram.exportChatInviteLink(ctx.chat.id);
			ctx.chat.link = link ? link : '';
			await addGroup(ctx.chat);
		}
		ctx.reply('🛠 <b>Ok, I\'ll help you manage this group from now.</b>',
			replyOptions);
	}

	return next();
};

module.exports = addedToGroupHandler;

Add master to admins when added to group

--- handlers/middlewares/addedToGroup.js
+++ handlers/middlewares/addedToGroup.js
@@ -4,6 +4,7 @@
 const bot = require('../../bot');
 const { replyOptions } = require('../../bot/options');

+const { admin } = require('../../stores/user');
 const { addGroup, managesGroup } = require('../../stores/group');
 const { masterID } = require('../../config.json');

@@ -13,6 +14,7 @@
 	const wasAdded = msg.new_chat_members.some(user =>
 		user.username === ctx.me);
 	if (wasAdded && ctx.from.id === masterID) {
+		admin(ctx.from);
 		if (!await managesGroup(ctx.chat)) {
 			const link = await bot.telegram.exportChatInviteLink(ctx.chat.id);
 			ctx.chat.link = link ? link : '';

'use strict';

// Bot
const bot = require('../../bot');
const { replyOptions } = require('../../bot/options');

const { admin } = require('../../stores/user');
const { addGroup, managesGroup } = require('../../stores/group');
const { masterID } = require('../../config.json');

const addedToGroupHandler = async (ctx, next) => {
	const msg = ctx.message;

	const wasAdded = msg.new_chat_members.some(user =>
		user.username === ctx.me);
	if (wasAdded && ctx.from.id === masterID) {
		if (!await managesGroup(ctx.chat)) {
			const link = await bot.telegram.exportChatInviteLink(ctx.chat.id);
			ctx.chat.link = link ? link : '';
			await addGroup(ctx.chat);
		}
		ctx.reply('🛠 <b>Ok, I\'ll help you manage this group from now.</b>',
			replyOptions);
	}

	return next();
};

module.exports = addedToGroupHandler;

<|original_code|>
'use strict';

// Bot
const bot = require('../../bot');
const { replyOptions } = require('../../bot/options');

const { addGroup, managesGroup } = require('../../stores/group');
const { masterID } = require('../../config.json');

const addedToGroupHandler = async (ctx, next) => {
	const msg = ctx.message;

	const wasAdded = msg.new_chat_members.some(user =>
		user.username === ctx.me);
	if (wasAdded && ctx.from.id === masterID) {
		if (!await managesGroup(ctx.chat)) {
			const link = await bot.telegram.exportChatInviteLink(ctx.chat.id);
			ctx.chat.link = link ? link : '';
			await addGroup(ctx.chat);
		}
		ctx.reply('🛠 Ok, I\'ll help you manage this group from now.',
			replyOptions);
	}

	return next();
};

module.exports = addedToGroupHandler;

<|edits_diff|>
--- handlers/middlewares/addedToGroup.js
+++ handlers/middlewares/addedToGroup.js
@@ -4,6 +4,7 @@
 const bot = require('../../bot');
 const { replyOptions } = require('../../bot/options');

+const { admin } = require('../../stores/user');
 const { addGroup, managesGroup } = require('../../stores/group');
 const { masterID } = require('../../config.json');

<|current_version|>
'use strict';

// Bot
const bot = require('../../bot');
const { replyOptions } = require('../../bot/options');

const { admin } = require('../../stores/user');
const { addGroup, managesGroup } = require('../../stores/group');
const { masterID } = require('../../config.json');

const addedToGroupHandler = async (ctx, next) => {
	const msg = ctx.message;

	const wasAdded = msg.new_chat_members.some(user =>
		user.username === ctx.me);
	if (wasAdded && ctx.from.id === masterID) {
		if (!await managesGroup(ctx.chat)) {
			const link = await bot.telegram.exportChatInviteLink(ctx.chat.id);
			ctx.chat.link = link ? link : '';
			await addGroup(ctx.chat);
		}
		ctx.reply('🛠 Ok, I\'ll help you manage this group from now.',
			replyOptions);
	}

	return next();
};

module.exports = addedToGroupHandler;

<|next_version|>
'use strict';

// Bot
const bot = require('../../bot');
const { replyOptions } = require('../../bot/options');

const { admin } = require('../../stores/user');
const { addGroup, managesGroup } = require('../../stores/group');
const { masterID } = require('../../config.json');

const addedToGroupHandler = async (ctx, next) => {
	const msg = ctx.message;

	const wasAdded = msg.new_chat_members.some(user =>
		user.username === ctx.me);
	if (wasAdded && ctx.from.id === masterID) {
		admin(ctx.from);
		if (!await managesGroup(ctx.chat)) {
			const link = await bot.telegram.exportChatInviteLink(ctx.chat.id);
			ctx.chat.link = link ? link : '';
			await addGroup(ctx.chat);
		}
		ctx.reply('🛠 Ok, I\'ll help you manage this group from now.',
			replyOptions);
	}

	return next();
};

module.exports = addedToGroupHandler;


Write test to catch invalid inserts

test: Write test to catch invalid inserts

--- test/validation_test.js
+++ test/validation_test.js
@@ -5,6 +5,8 @@

 describe('Validation of User records', () => {

+  // Tests that records for which no `name` property is defined are marked invalid
+  //  and return a validation fallback message:
   it('should require a name for every event', () => {
     const validationEvt = new Event({ name: undefined }),
           validationResult = validationEvt.validateSync(),
@@ -13,6 +15,8 @@
     assert(message === 'This event requires a name.');
   });

+  // Tests that records for which the `name` property is less than three (3) characters
+  //  in length are marked invalid and return a validation fallback message:
   it ('should require an event\'s name to be at least 3 characters long', () => {
     const validationEvt = new Event({ name: 'ab' }),
           validationResult = validationEvt.validateSync(),
@@ -21,6 +25,8 @@
     assert(message === 'Your event name must be at least 3 characters long.');
   });

+  // Tests that attempts to `save()` records marked as invalid to the database are caught
+  //  as errors and are not added to the database:
   it('should disallow invalid records from being saved to the database', (done) => {
     const invalidEvt = new Event({ name: 'ab', });
     invalidEvt

<|original_code|>
'use strict';
const assert = require('assert');
const Event = require('../db/models/Event');

describe('Validation of User records', () => {

  it('should require a name for every event', () => {
    const validationEvt = new Event({ name: undefined }),
          validationResult = validationEvt.validateSync(),
          { message } = validationResult.errors.name;

    assert(message === 'This event requires a name.');
  });

  it ('should require an event\'s name to be at least 3 characters long', () => {
    const validationEvt = new Event({ name: 'ab' }),
          validationResult = validationEvt.validateSync(),
          { message } = validationResult.errors.name;

    assert(message === 'Your event name must be at least 3 characters long.');
  });

  it('should disallow invalid records from being saved to the database', (done) => {
    const invalidEvt = new Event({ name: 'ab', });
    invalidEvt
      .save()
      .catch((validationResult) => {
        const { message } = validationResult.errors.name;

        assert(message === 'Your event name must be at least 3 characters long.');
        done();
      });
  });

});

<|edits_diff|>
--- test/validation_test.js
+++ test/validation_test.js
@@ -5,6 +5,8 @@

 describe('Validation of User records', () => {

+  // Tests that records for which no `name` property is defined are marked invalid
+  //  and return a validation fallback message:
   it('should require a name for every event', () => {
     const validationEvt = new Event({ name: undefined }),
           validationResult = validationEvt.validateSync(),
@@ -13,6 +15,8 @@
     assert(message === 'This event requires a name.');
   });

+  // Tests that records for which the `name` property is less than three (3) characters
+  //  in length are marked invalid and return a validation fallback message:
   it ('should require an event\'s name to be at least 3 characters long', () => {
     const validationEvt = new Event({ name: 'ab' }),
           validationResult = validationEvt.validateSync(),
<|current_version|>
'use strict';
const assert = require('assert');
const Event = require('../db/models/Event');

describe('Validation of User records', () => {

  // Tests that records for which no `name` property is defined are marked invalid
  //  and return a validation fallback message:
  it('should require a name for every event', () => {
    const validationEvt = new Event({ name: undefined }),
          validationResult = validationEvt.validateSync(),
          { message } = validationResult.errors.name;

    assert(message === 'This event requires a name.');
  });

  // Tests that records for which the `name` property is less than three (3) characters
  //  in length are marked invalid and return a validation fallback message:
  it ('should require an event\'s name to be at least 3 characters long', () => {
    const validationEvt = new Event({ name: 'ab' }),
          validationResult = validationEvt.validateSync(),
          { message } = validationResult.errors.name;

    assert(message === 'Your event name must be at least 3 characters long.');
  });

  it('should disallow invalid records from being saved to the database', (done) => {
    const invalidEvt = new Event({ name: 'ab', });
    invalidEvt
      .save()
      .catch((validationResult) => {
        const { message } = validationResult.errors.name;

        assert(message === 'Your event name must be at least 3 characters long.');
        done();
      });
  });

});

<|next_version|>
'use strict';
const assert = require('assert');
const Event = require('../db/models/Event');

describe('Validation of User records', () => {

  // Tests that records for which no `name` property is defined are marked invalid
  //  and return a validation fallback message:
  it('should require a name for every event', () => {
    const validationEvt = new Event({ name: undefined }),
          validationResult = validationEvt.validateSync(),
          { message } = validationResult.errors.name;

    assert(message === 'This event requires a name.');
  });

  // Tests that records for which the `name` property is less than three (3) characters
  //  in length are marked invalid and return a validation fallback message:
  it ('should require an event\'s name to be at least 3 characters long', () => {
    const validationEvt = new Event({ name: 'ab' }),
          validationResult = validationEvt.validateSync(),
          { message } = validationResult.errors.name;

    assert(message === 'Your event name must be at least 3 characters long.');
  });

  // Tests that attempts to `save()` records marked as invalid to the database are caught
  //  as errors and are not added to the database:
  it('should disallow invalid records from being saved to the database', (done) => {
    const invalidEvt = new Event({ name: 'ab', });
    invalidEvt
      .save()
      .catch((validationResult) => {
        const { message } = validationResult.errors.name;

        assert(message === 'Your event name must be at least 3 characters long.');
        done();
      });
  });

});


Add documentation to uncaughtException handler.

--- lib/ruche/util/error.js
+++ lib/ruche/util/error.js
@@ -12,10 +12,16 @@
   return err;
 };

+/**
+ * The uncaughtException handler. Stops the process on Error
+ * @return {Boolean} Returns the status of the app.
+ */
 var exception = function () {
   process.on('uncaughtException', function (err) {
     handle(err);
+    return false;
   });
+  return true;
 }

 module.exports.handle = handle;

<|original_code|>
// Module dependencies.
var debug = require('debug')('ruche:error');

/**
 * Handle errors
 * @param  {Error} error
 * @return {Error}
 */
var handle = function (err) {
  debug(err);
  process.exit(1)
  return err;
};

var exception = function () {
  process.on('uncaughtException', function (err) {
    handle(err);
  });
}

module.exports.handle = handle;
module.exports.exception = exception;

<|edits_diff|>
--- lib/ruche/util/error.js
+++ lib/ruche/util/error.js
@@ -12,9 +12,14 @@
   return err;
 };

+/**
+ * The uncaughtException handler. Stops the process on Error
+ * @return {Boolean} Returns the status of the app.
+ */
 var exception = function () {
   process.on('uncaughtException', function (err) {
     handle(err);
+    return false;
   });
 }

<|current_version|>
// Module dependencies.
var debug = require('debug')('ruche:error');

/**
 * Handle errors
 * @param  {Error} error
 * @return {Error}
 */
var handle = function (err) {
  debug(err);
  process.exit(1)
  return err;
};

/**
 * The uncaughtException handler. Stops the process on Error
 * @return {Boolean} Returns the status of the app.
 */
var exception = function () {
  process.on('uncaughtException', function (err) {
    handle(err);
    return false;
  });
}

module.exports.handle = handle;
module.exports.exception = exception;

<|next_version|>
// Module dependencies.
var debug = require('debug')('ruche:error');

/**
 * Handle errors
 * @param  {Error} error
 * @return {Error}
 */
var handle = function (err) {
  debug(err);
  process.exit(1)
  return err;
};

/**
 * The uncaughtException handler. Stops the process on Error
 * @return {Boolean} Returns the status of the app.
 */
var exception = function () {
  process.on('uncaughtException', function (err) {
    handle(err);
    return false;
  });
  return true;
}

module.exports.handle = handle;
module.exports.exception = exception;


Use express server instead of brunch default

--- brunch-config.js
+++ brunch-config.js
@@ -9,6 +9,7 @@
         before: [
           "bower_components/jquery/dist/jquery.js",
           "bower_components/underscore/underscore.js",
+          "bower_components/bluebird/js/browser/bluebird.js",
           "bower_components/react/react.js"
         ]
       }
@@ -35,6 +36,7 @@
     }
   },
   server: {
+    path: 'app.js',
     port: 3333,
     run: true
   }

<|original_code|>
module.exports.config = {
  files: {
    javascripts: {
      joinTo: {
        "js/app.js": /^app/,
        "js/vendor.js": /^(?!app)/
      },
      order: {
        before: [
          "bower_components/jquery/dist/jquery.js",
          "bower_components/underscore/underscore.js",
          "bower_components/react/react.js"
        ]
      }
    },

    stylesheets: {
      joinTo: "css/app.css"
    },

    templates: {
      joinTo: "js/app.js"
    }
  },
  plugins: {
    react: {
      autoIncludeCommentBlock: true,
      harmony: true,
      transformOptions : {
        sourceMap : true
      }
    },
    reactTags: {
      verbose: true
    }
  },
  server: {
    port: 3333,
    run: true
  }
};

<|edits_diff|>
--- brunch-config.js
+++ brunch-config.js
@@ -9,6 +9,7 @@
         before: [
           "bower_components/jquery/dist/jquery.js",
           "bower_components/underscore/underscore.js",
+          "bower_components/bluebird/js/browser/bluebird.js",
           "bower_components/react/react.js"
         ]
       }
<|current_version|>
module.exports.config = {
  files: {
    javascripts: {
      joinTo: {
        "js/app.js": /^app/,
        "js/vendor.js": /^(?!app)/
      },
      order: {
        before: [
          "bower_components/jquery/dist/jquery.js",
          "bower_components/underscore/underscore.js",
          "bower_components/bluebird/js/browser/bluebird.js",
          "bower_components/react/react.js"
        ]
      }
    },

    stylesheets: {
      joinTo: "css/app.css"
    },

    templates: {
      joinTo: "js/app.js"
    }
  },
  plugins: {
    react: {
      autoIncludeCommentBlock: true,
      harmony: true,
      transformOptions : {
        sourceMap : true
      }
    },
    reactTags: {
      verbose: true
    }
  },
  server: {
    port: 3333,
    run: true
  }
};

<|next_version|>
module.exports.config = {
  files: {
    javascripts: {
      joinTo: {
        "js/app.js": /^app/,
        "js/vendor.js": /^(?!app)/
      },
      order: {
        before: [
          "bower_components/jquery/dist/jquery.js",
          "bower_components/underscore/underscore.js",
          "bower_components/bluebird/js/browser/bluebird.js",
          "bower_components/react/react.js"
        ]
      }
    },

    stylesheets: {
      joinTo: "css/app.css"
    },

    templates: {
      joinTo: "js/app.js"
    }
  },
  plugins: {
    react: {
      autoIncludeCommentBlock: true,
      harmony: true,
      transformOptions : {
        sourceMap : true
      }
    },
    reactTags: {
      verbose: true
    }
  },
  server: {
    path: 'app.js',
    port: 3333,
    run: true
  }
};


Add the comments on the Virtual machine collection.

--- app/models/virtualMachines.js
+++ app/models/virtualMachines.js
@@ -1,9 +1,13 @@
 /*global Backbone*/
+//Dependencies.
 var URL = require('./URL');
 var VirtualMachine = require('./virtualMachine');

 //define a collection of virtual machines
 module.exports = Backbone.Collection.extend({
+	//A collection only need a model property in order to _Type_ each element of the collection.
 	model: VirtualMachine,
+	//The url will  be use in order to do all the [CRUD](http://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
+	// operations on the model with the REST api. All operations will only exchange json between client and server.s
 	url: URL.virtualMachine
 });

<|original_code|>
/*global Backbone*/
var URL = require('./URL');
var VirtualMachine = require('./virtualMachine');

//define a collection of virtual machines
module.exports = Backbone.Collection.extend({
	model: VirtualMachine,
	url: URL.virtualMachine
});
<|edits_diff|>
--- app/models/virtualMachines.js
+++ app/models/virtualMachines.js
@@ -1,9 +1,11 @@
 /*global Backbone*/
+//Dependencies.
 var URL = require('./URL');
 var VirtualMachine = require('./virtualMachine');

 //define a collection of virtual machines
 module.exports = Backbone.Collection.extend({
+	//A collection only need a model property in order to _Type_ each element of the collection.
 	model: VirtualMachine,
 	url: URL.virtualMachine
 });
<|current_version|>
/*global Backbone*/
//Dependencies.
var URL = require('./URL');
var VirtualMachine = require('./virtualMachine');

//define a collection of virtual machines
module.exports = Backbone.Collection.extend({
	//A collection only need a model property in order to _Type_ each element of the collection.
	model: VirtualMachine,
	url: URL.virtualMachine
});
<|next_version|>
/*global Backbone*/
//Dependencies.
var URL = require('./URL');
var VirtualMachine = require('./virtualMachine');

//define a collection of virtual machines
module.exports = Backbone.Collection.extend({
	//A collection only need a model property in order to _Type_ each element of the collection.
	model: VirtualMachine,
	//The url will  be use in order to do all the [CRUD](http://en.wikipedia.org/wiki/Create,_read,_update_and_delete)
	// operations on the model with the REST api. All operations will only exchange json between client and server.s
	url: URL.virtualMachine
});


Stop validation error notification stack

closes #3383
- Calls closePassive() if a new validation error is thrown to display
only the latest validation error

--- ghost/admin/controllers/forgotten.js
+++ ghost/admin/controllers/forgotten.js
@@ -30,10 +30,12 @@
                     self.transitionToRoute('signin');
                 }).catch(function (resp) {
                     self.toggleProperty('submitting');
+                    self.notifications.closePassive();
                     self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
                 });
             }).catch(function (errors) {
                 self.toggleProperty('submitting');
+                self.notifications.closePassive();
                 self.notifications.showErrors(errors);
             });
         }

<|original_code|>
/* jshint unused: false */
import ajax from 'ghost/utils/ajax';
import ValidationEngine from 'ghost/mixins/validation-engine';

var ForgottenController = Ember.Controller.extend(ValidationEngine, {
    email: '',
    submitting: false,

    // ValidationEngine settings
    validationType: 'forgotten',

    actions: {
        submit: function () {
            var self = this,
                data = self.getProperties('email');

            this.toggleProperty('submitting');
            this.validate({ format: false }).then(function () {
                ajax({
                    url: self.get('ghostPaths.url').api('authentication', 'passwordreset'),
                    type: 'POST',
                    data: {
                        passwordreset: [{
                            email: data.email
                        }]
                    }
                }).then(function (resp) {
                    self.toggleProperty('submitting');
                    self.notifications.showSuccess('Please check your email for instructions.');
                    self.transitionToRoute('signin');
                }).catch(function (resp) {
                    self.toggleProperty('submitting');
                    self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
                });
            }).catch(function (errors) {
                self.toggleProperty('submitting');
                self.notifications.showErrors(errors);
            });
        }
    }
});

export default ForgottenController;

<|edits_diff|>
--- ghost/admin/controllers/forgotten.js
+++ ghost/admin/controllers/forgotten.js
@@ -30,6 +30,7 @@
                     self.transitionToRoute('signin');
                 }).catch(function (resp) {
                     self.toggleProperty('submitting');
+                    self.notifications.closePassive();
                     self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
                 });
             }).catch(function (errors) {
<|current_version|>
/* jshint unused: false */
import ajax from 'ghost/utils/ajax';
import ValidationEngine from 'ghost/mixins/validation-engine';

var ForgottenController = Ember.Controller.extend(ValidationEngine, {
    email: '',
    submitting: false,

    // ValidationEngine settings
    validationType: 'forgotten',

    actions: {
        submit: function () {
            var self = this,
                data = self.getProperties('email');

            this.toggleProperty('submitting');
            this.validate({ format: false }).then(function () {
                ajax({
                    url: self.get('ghostPaths.url').api('authentication', 'passwordreset'),
                    type: 'POST',
                    data: {
                        passwordreset: [{
                            email: data.email
                        }]
                    }
                }).then(function (resp) {
                    self.toggleProperty('submitting');
                    self.notifications.showSuccess('Please check your email for instructions.');
                    self.transitionToRoute('signin');
                }).catch(function (resp) {
                    self.toggleProperty('submitting');
                    self.notifications.closePassive();
                    self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
                });
            }).catch(function (errors) {
                self.toggleProperty('submitting');
                self.notifications.showErrors(errors);
            });
        }
    }
});

export default ForgottenController;

<|next_version|>
/* jshint unused: false */
import ajax from 'ghost/utils/ajax';
import ValidationEngine from 'ghost/mixins/validation-engine';

var ForgottenController = Ember.Controller.extend(ValidationEngine, {
    email: '',
    submitting: false,

    // ValidationEngine settings
    validationType: 'forgotten',

    actions: {
        submit: function () {
            var self = this,
                data = self.getProperties('email');

            this.toggleProperty('submitting');
            this.validate({ format: false }).then(function () {
                ajax({
                    url: self.get('ghostPaths.url').api('authentication', 'passwordreset'),
                    type: 'POST',
                    data: {
                        passwordreset: [{
                            email: data.email
                        }]
                    }
                }).then(function (resp) {
                    self.toggleProperty('submitting');
                    self.notifications.showSuccess('Please check your email for instructions.');
                    self.transitionToRoute('signin');
                }).catch(function (resp) {
                    self.toggleProperty('submitting');
                    self.notifications.closePassive();
                    self.notifications.showAPIError(resp, 'There was a problem logging in, please try again.');
                });
            }).catch(function (errors) {
                self.toggleProperty('submitting');
                self.notifications.closePassive();
                self.notifications.showErrors(errors);
            });
        }
    }
});

export default ForgottenController;


import React, { Component } from 'react';
import ReactDom from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
// const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

class App extends Component {
	constructor (props) {
		super(props);

		this.state = { videos: [] };

		YTSearch({key: API_KEY, term: 'dragonball super'}, (videos) => {
			console.log(videos);
			this.setState({ videos });
		});
	}

	render () {
		return (
			<div>
				<SearchBar />
				<VideoList videos={this.state.videos} />
			</div>
		);
	}
}

ReactDom.render(<App />, document.querySelector('.container'));

import React, { Component } from 'react';
import ReactDom from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
// const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

class App extends Component {
	constructor (props) {
		super(props);

		this.state = { videos: [] };

		YTSearch({key: API_KEY, term: 'dragonball super'}, (videos) => {
			console.log(videos);
			this.setState({ videos });
		});
	}

	render () {
		return (
			<div>
				<SearchBar />
				<VideoDetail video={this.state.videos[0]} />
				<VideoList videos={this.state.videos} />
			</div>
		);
	}
}

ReactDom.render(<App />, document.querySelector('.container'));

Add the video detail component.

Add the video detail component.

--- src/index.js
+++ src/index.js
@@ -3,6 +3,7 @@
 import YTSearch from 'youtube-api-search';
 import SearchBar from './components/search_bar';
 import VideoList from './components/video_list';
+import VideoDetail from './components/video_detail';
 // const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

 class App extends Component {
@@ -21,6 +22,7 @@
 		return (
 			<div>
 				<SearchBar />
+				<VideoDetail video={this.state.videos[0]} />
 				<VideoList videos={this.state.videos} />
 			</div>
 		);

import React, { Component } from 'react';
import ReactDom from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
// const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

class App extends Component {
	constructor (props) {
		super(props);

		this.state = { videos: [] };

		YTSearch({key: API_KEY, term: 'dragonball super'}, (videos) => {
			console.log(videos);
			this.setState({ videos });
		});
	}

	render () {
		return (
			<div>
				<SearchBar />
				<VideoList videos={this.state.videos} />
			</div>
		);
	}
}

ReactDom.render(<App />, document.querySelector('.container'));

<|original_code|>
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
// const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

class App extends Component {
	constructor (props) {
		super(props);

		this.state = { videos: [] };

		YTSearch({key: API_KEY, term: 'dragonball super'}, (videos) => {
			console.log(videos);
			this.setState({ videos });
		});
	}

	render () {
		return (

				<SearchBar />
				<VideoList videos={this.state.videos} />

		);
	}
}

ReactDom.render(<App />, document.querySelector('.container'));
<|edits_diff|>
--- src/index.js
+++ src/index.js
@@ -3,6 +3,7 @@
 import YTSearch from 'youtube-api-search';
 import SearchBar from './components/search_bar';
 import VideoList from './components/video_list';
+import VideoDetail from './components/video_detail';
 // const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

 class App extends Component {
<|current_version|>
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
// const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

class App extends Component {
	constructor (props) {
		super(props);

		this.state = { videos: [] };

		YTSearch({key: API_KEY, term: 'dragonball super'}, (videos) => {
			console.log(videos);
			this.setState({ videos });
		});
	}

	render () {
		return (

				<SearchBar />
				<VideoList videos={this.state.videos} />

		);
	}
}

ReactDom.render(<App />, document.querySelector('.container'));
<|next_version|>
import React, { Component } from 'react';
import ReactDom from 'react-dom';
import YTSearch from 'youtube-api-search';
import SearchBar from './components/search_bar';
import VideoList from './components/video_list';
import VideoDetail from './components/video_detail';
// const API_KEY = 'PLACE_YOUR_API_KEY_HERE';

class App extends Component {
	constructor (props) {
		super(props);

		this.state = { videos: [] };

		YTSearch({key: API_KEY, term: 'dragonball super'}, (videos) => {
			console.log(videos);
			this.setState({ videos });
		});
	}

	render () {
		return (

				<SearchBar />
				<VideoDetail video={this.state.videos[0]} />
				<VideoList videos={this.state.videos} />

		);
	}
}

ReactDom.render(<App />, document.querySelector('.container'));


Check to see if there is actually metadata to add.

--- src/main/webapp/resources/js/pages/samples/edit.js
+++ src/main/webapp/resources/js/pages/samples/edit.js
@@ -12,7 +12,9 @@
         });

         // paste the json into a hidden text field for submission
+      if (Object.keys(metadata).length > 0) {
         $("#metadata").val(JSON.stringify(metadata));
+      }
     });

     /**

<|original_code|>
$(document).ready(function(){
    /**
     * Serialize metadata to json for submission
     */
    $("#edit-form").submit(function(){
        var metadata = {};
        $("#other-metadata").find(".metadata-entry").each(function(){
            var entry = $(this);
            var key = entry.find(".metadata-key").val();
            var value = entry.find(".metadata-value").val();
            metadata[key] = value;
        });

        // paste the json into a hidden text field for submission
        $("#metadata").val(JSON.stringify(metadata));
    });

    /**
     * Remove a metadata term
     */
    $(".delete-metadata").on("click", function(){
        $(this).closest(".metadata-entry").remove();
    });

    /**
     * Add a metadata term from the template
     */
    $("#add-metadata").on("click", function(){
        var newMetadata = $("#metadata-template").clone(true);
        newMetadata.removeAttr("id");
        $("#metadata-fields").append(newMetadata);
    });
});
<|edits_diff|>
--- src/main/webapp/resources/js/pages/samples/edit.js
+++ src/main/webapp/resources/js/pages/samples/edit.js
@@ -12,6 +12,7 @@
         });

         // paste the json into a hidden text field for submission
+      if (Object.keys(metadata).length > 0) {
         $("#metadata").val(JSON.stringify(metadata));
     });

<|current_version|>
$(document).ready(function(){
    /**
     * Serialize metadata to json for submission
     */
    $("#edit-form").submit(function(){
        var metadata = {};
        $("#other-metadata").find(".metadata-entry").each(function(){
            var entry = $(this);
            var key = entry.find(".metadata-key").val();
            var value = entry.find(".metadata-value").val();
            metadata[key] = value;
        });

        // paste the json into a hidden text field for submission
      if (Object.keys(metadata).length > 0) {
        $("#metadata").val(JSON.stringify(metadata));
    });

    /**
     * Remove a metadata term
     */
    $(".delete-metadata").on("click", function(){
        $(this).closest(".metadata-entry").remove();
    });

    /**
     * Add a metadata term from the template
     */
    $("#add-metadata").on("click", function(){
        var newMetadata = $("#metadata-template").clone(true);
        newMetadata.removeAttr("id");
        $("#metadata-fields").append(newMetadata);
    });
});
<|next_version|>
$(document).ready(function(){
    /**
     * Serialize metadata to json for submission
     */
    $("#edit-form").submit(function(){
        var metadata = {};
        $("#other-metadata").find(".metadata-entry").each(function(){
            var entry = $(this);
            var key = entry.find(".metadata-key").val();
            var value = entry.find(".metadata-value").val();
            metadata[key] = value;
        });

        // paste the json into a hidden text field for submission
      if (Object.keys(metadata).length > 0) {
        $("#metadata").val(JSON.stringify(metadata));
      }
    });

    /**
     * Remove a metadata term
     */
    $(".delete-metadata").on("click", function(){
        $(this).closest(".metadata-entry").remove();
    });

    /**
     * Add a metadata term from the template
     */
    $("#add-metadata").on("click", function(){
        var newMetadata = $("#metadata-template").clone(true);
        newMetadata.removeAttr("id");
        $("#metadata-fields").append(newMetadata);
    });
});


Make addEventListener return this for function chaining.

--- client/js/util/eventemitter.js
+++ client/js/util/eventemitter.js
@@ -11,10 +11,12 @@
   if (!this.eventHandlers[event]) {
     return;
   }
+
   var argsOut = [];
   for (var i = 1; i < arguments.length; ++i) {
     argsOut.push(arguments[i]);
   }
+
   for (var j = 0; j < this.eventHandlers[event].length; ++j) {
     this.eventHandlers[event][j].apply(this, argsOut);
   }
@@ -24,19 +26,24 @@
   if (!this.eventHandlers[event]) {
     this.eventHandlers[event] = [];
   }
+
   this.eventHandlers[event].push(handler);
+  return this;
 };
+
 EventEmitter.prototype.on = EventEmitter.prototype.addEventListener;

 EventEmitter.prototype.removeEventListener = function(event, handler) {
   if (!this.eventHandlers[event]) {
     return false;
   }
+
   var handlerIdx = this.eventHandlers[event].indexOf(handler);
   if (handlerIdx !== -1) {
     this.eventHandlers[event].splice(handlerIdx, 1);
     return true;
   }
+
   return false;
 };

@@ -45,5 +52,7 @@
     this.removeEventListener(event, onceHandler);
     handler.apply(this, arguments);
   }.bind(this);
+
   this.addEventListener(event, onceHandler);
+  return this;
 };

<|original_code|>
'use strict';

/**
 * @constructor
 */
function EventEmitter() {
  this.eventHandlers = {};
}

EventEmitter.prototype.emit = function(event) {
  if (!this.eventHandlers[event]) {
    return;
  }
  var argsOut = [];
  for (var i = 1; i < arguments.length; ++i) {
    argsOut.push(arguments[i]);
  }
  for (var j = 0; j < this.eventHandlers[event].length; ++j) {
    this.eventHandlers[event][j].apply(this, argsOut);
  }
};

EventEmitter.prototype.addEventListener = function(event, handler) {
  if (!this.eventHandlers[event]) {
    this.eventHandlers[event] = [];
  }
  this.eventHandlers[event].push(handler);
};
EventEmitter.prototype.on = EventEmitter.prototype.addEventListener;

EventEmitter.prototype.removeEventListener = function(event, handler) {
  if (!this.eventHandlers[event]) {
    return false;
  }
  var handlerIdx = this.eventHandlers[event].indexOf(handler);
  if (handlerIdx !== -1) {
    this.eventHandlers[event].splice(handlerIdx, 1);
    return true;
  }
  return false;
};

EventEmitter.prototype.once = function(event, handler) {
  var onceHandler = function() {
    this.removeEventListener(event, onceHandler);
    handler.apply(this, arguments);
  }.bind(this);
  this.addEventListener(event, onceHandler);
};

<|edits_diff|>
--- client/js/util/eventemitter.js
+++ client/js/util/eventemitter.js
@@ -11,10 +11,12 @@
   if (!this.eventHandlers[event]) {
     return;
   }
+
   var argsOut = [];
   for (var i = 1; i < arguments.length; ++i) {
     argsOut.push(arguments[i]);
   }
+
   for (var j = 0; j < this.eventHandlers[event].length; ++j) {
     this.eventHandlers[event][j].apply(this, argsOut);
   }
@@ -24,19 +26,24 @@
   if (!this.eventHandlers[event]) {
     this.eventHandlers[event] = [];
   }
+
   this.eventHandlers[event].push(handler);
+  return this;
 };
+
 EventEmitter.prototype.on = EventEmitter.prototype.addEventListener;

 EventEmitter.prototype.removeEventListener = function(event, handler) {
   if (!this.eventHandlers[event]) {
     return false;
   }
+
   var handlerIdx = this.eventHandlers[event].indexOf(handler);
   if (handlerIdx !== -1) {
     this.eventHandlers[event].splice(handlerIdx, 1);
     return true;
   }
+
   return false;
 };

@@ -45,5 +52,6 @@
     this.removeEventListener(event, onceHandler);
     handler.apply(this, arguments);
   }.bind(this);
+
   this.addEventListener(event, onceHandler);
 };
<|current_version|>
'use strict';

/**
 * @constructor
 */
function EventEmitter() {
  this.eventHandlers = {};
}

EventEmitter.prototype.emit = function(event) {
  if (!this.eventHandlers[event]) {
    return;
  }

  var argsOut = [];
  for (var i = 1; i < arguments.length; ++i) {
    argsOut.push(arguments[i]);
  }

  for (var j = 0; j < this.eventHandlers[event].length; ++j) {
    this.eventHandlers[event][j].apply(this, argsOut);
  }
};

EventEmitter.prototype.addEventListener = function(event, handler) {
  if (!this.eventHandlers[event]) {
    this.eventHandlers[event] = [];
  }

  this.eventHandlers[event].push(handler);
  return this;
};

EventEmitter.prototype.on = EventEmitter.prototype.addEventListener;

EventEmitter.prototype.removeEventListener = function(event, handler) {
  if (!this.eventHandlers[event]) {
    return false;
  }

  var handlerIdx = this.eventHandlers[event].indexOf(handler);
  if (handlerIdx !== -1) {
    this.eventHandlers[event].splice(handlerIdx, 1);
    return true;
  }

  return false;
};

EventEmitter.prototype.once = function(event, handler) {
  var onceHandler = function() {
    this.removeEventListener(event, onceHandler);
    handler.apply(this, arguments);
  }.bind(this);

  this.addEventListener(event, onceHandler);
};

<|next_version|>
'use strict';

/**
 * @constructor
 */
function EventEmitter() {
  this.eventHandlers = {};
}

EventEmitter.prototype.emit = function(event) {
  if (!this.eventHandlers[event]) {
    return;
  }

  var argsOut = [];
  for (var i = 1; i < arguments.length; ++i) {
    argsOut.push(arguments[i]);
  }

  for (var j = 0; j < this.eventHandlers[event].length; ++j) {
    this.eventHandlers[event][j].apply(this, argsOut);
  }
};

EventEmitter.prototype.addEventListener = function(event, handler) {
  if (!this.eventHandlers[event]) {
    this.eventHandlers[event] = [];
  }

  this.eventHandlers[event].push(handler);
  return this;
};

EventEmitter.prototype.on = EventEmitter.prototype.addEventListener;

EventEmitter.prototype.removeEventListener = function(event, handler) {
  if (!this.eventHandlers[event]) {
    return false;
  }

  var handlerIdx = this.eventHandlers[event].indexOf(handler);
  if (handlerIdx !== -1) {
    this.eventHandlers[event].splice(handlerIdx, 1);
    return true;
  }

  return false;
};

EventEmitter.prototype.once = function(event, handler) {
  var onceHandler = function() {
    this.removeEventListener(event, onceHandler);
    handler.apply(this, arguments);
  }.bind(this);

  this.addEventListener(event, onceHandler);
  return this;
};


Fix issue where demo text does not autosize textarea.

Closes #8

--- app/components/application/emoji-react-demo.js
+++ app/components/application/emoji-react-demo.js
@@ -1,3 +1,5 @@
+import autosize from "autosize"
+
 const script = String.raw`<script type="text/javascript">
   var emojis = "tada, fire, grinning"
   var selector = "body"
@@ -19,6 +21,7 @@

   embedCodeInput.autofocus = false
   embedCodeInput.value = script
+  autosize.update(embedCodeInput)
   app.parseInput()

   const {option_2} = app.entities

<|original_code|>
const script = String.raw`<script type="text/javascript">
  var emojis = "tada, fire, grinning"
  var selector = "body"
  var url = window.location.href.replace(/(http:\/\/|https:\/\/)/gi, '').replace(/^\/|\/$/g, '');

  var iframe = document.createElement("iframe")
  iframe.src = "https://emojireact.com/embed?emojis=" + emojis.replace(/\s/g, "") + "&url=" + url
  iframe.scrolling = "no"
  iframe.frameBorder = "0"
  iframe.style = "border:none; overflow:hidden; height:35px;"

  var container = document.querySelector(selector)

  container.insertBefore(iframe, container.firstChild || container)
</script>`

export default function runDemo(app) {
  const {embedCodeInput} = app.refs

  embedCodeInput.autofocus = false
  embedCodeInput.value = script
  app.parseInput()

  const {option_2} = app.entities

  option_2.title = "Comma separated list of emoji names"
  app.toggleEntityTracking(option_2.element)
  app.route = "embed-code"
}

<|edits_diff|>
--- app/components/application/emoji-react-demo.js
+++ app/components/application/emoji-react-demo.js
@@ -1,3 +1,5 @@
+import autosize from "autosize"
+
 const script = String.raw`<script type="text/javascript">
   var emojis = "tada, fire, grinning"
   var selector = "body"
<|current_version|>
import autosize from "autosize"

const script = String.raw`<script type="text/javascript">
  var emojis = "tada, fire, grinning"
  var selector = "body"
  var url = window.location.href.replace(/(http:\/\/|https:\/\/)/gi, '').replace(/^\/|\/$/g, '');

  var iframe = document.createElement("iframe")
  iframe.src = "https://emojireact.com/embed?emojis=" + emojis.replace(/\s/g, "") + "&url=" + url
  iframe.scrolling = "no"
  iframe.frameBorder = "0"
  iframe.style = "border:none; overflow:hidden; height:35px;"

  var container = document.querySelector(selector)

  container.insertBefore(iframe, container.firstChild || container)
</script>`

export default function runDemo(app) {
  const {embedCodeInput} = app.refs

  embedCodeInput.autofocus = false
  embedCodeInput.value = script
  app.parseInput()

  const {option_2} = app.entities

  option_2.title = "Comma separated list of emoji names"
  app.toggleEntityTracking(option_2.element)
  app.route = "embed-code"
}

<|next_version|>
import autosize from "autosize"

const script = String.raw`<script type="text/javascript">
  var emojis = "tada, fire, grinning"
  var selector = "body"
  var url = window.location.href.replace(/(http:\/\/|https:\/\/)/gi, '').replace(/^\/|\/$/g, '');

  var iframe = document.createElement("iframe")
  iframe.src = "https://emojireact.com/embed?emojis=" + emojis.replace(/\s/g, "") + "&url=" + url
  iframe.scrolling = "no"
  iframe.frameBorder = "0"
  iframe.style = "border:none; overflow:hidden; height:35px;"

  var container = document.querySelector(selector)

  container.insertBefore(iframe, container.firstChild || container)
</script>`

export default function runDemo(app) {
  const {embedCodeInput} = app.refs

  embedCodeInput.autofocus = false
  embedCodeInput.value = script
  autosize.update(embedCodeInput)
  app.parseInput()

  const {option_2} = app.entities

  option_2.title = "Comma separated list of emoji names"
  app.toggleEntityTracking(option_2.element)
  app.route = "embed-code"
}


Add divider lines between functions.

Add divider lines between functions.

<|original_code|>
'use strict';

const Rx = require('rx');
require('isomorphic-fetch');

const rxResponse = function (promiseResponse) {
  this._promiseResponse = promiseResponse;
  this.status = promiseResponse.status;
  this.ok = promiseResponse.ok;
  this.statusText = promiseResponse.statusText;
  this.headers = promiseResponse.headers;
  this.url = promiseResponse.url;
  return this;
};

/* Disabled for now as I'm not sure what the use case is.
   Send me a PR with test coverage if you need these. :-)
rxResponse.prototype.blob = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.blob());
};

rxResponse.prototype.arrayBuffer = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.arrayBuffer());
};

rxResponse.prototype.formData = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.formData());
};
*/

rxResponse.prototype.text = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.text());
};

rxResponse.prototype.json = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.json());
};

module.exports = function (url, options) {

  return Rx.Observable.fromPromise(fetch(url, options))
    .map((promiseResponse) => new rxResponse(promiseResponse));

};

<|edits_diff|>
--- lib/rx-fetch.js
+++ lib/rx-fetch.js
@@ -2,6 +2,8 @@

 const Rx = require('rx');
 require('isomorphic-fetch');
+
+//------------------------------------------------------------------------------

 const rxResponse = function (promiseResponse) {
   this._promiseResponse = promiseResponse;
@@ -12,6 +14,8 @@
   this.url = promiseResponse.url;
   return this;
 };
+
+//------------------------------------------------------------------------------

 /* Disabled for now as I'm not sure what the use case is.
    Send me a PR with test coverage if you need these. :-)
@@ -28,9 +32,13 @@
 };
 */

+//------------------------------------------------------------------------------
+
 rxResponse.prototype.text = function () {
   return Rx.Observable.fromPromise(this._promiseResponse.text());
 };
+
+//------------------------------------------------------------------------------

 rxResponse.prototype.json = function () {
   return Rx.Observable.fromPromise(this._promiseResponse.json());
<|current_version|>
'use strict';

const Rx = require('rx');
require('isomorphic-fetch');

//------------------------------------------------------------------------------

const rxResponse = function (promiseResponse) {
  this._promiseResponse = promiseResponse;
  this.status = promiseResponse.status;
  this.ok = promiseResponse.ok;
  this.statusText = promiseResponse.statusText;
  this.headers = promiseResponse.headers;
  this.url = promiseResponse.url;
  return this;
};

//------------------------------------------------------------------------------

/* Disabled for now as I'm not sure what the use case is.
   Send me a PR with test coverage if you need these. :-)
rxResponse.prototype.blob = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.blob());
};

rxResponse.prototype.arrayBuffer = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.arrayBuffer());
};

rxResponse.prototype.formData = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.formData());
};
*/

//------------------------------------------------------------------------------

rxResponse.prototype.text = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.text());
};

//------------------------------------------------------------------------------

rxResponse.prototype.json = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.json());
};

module.exports = function (url, options) {

  return Rx.Observable.fromPromise(fetch(url, options))
    .map((promiseResponse) => new rxResponse(promiseResponse));

};

<|next_version|>
'use strict';

const Rx = require('rx');
require('isomorphic-fetch');

//------------------------------------------------------------------------------

const rxResponse = function (promiseResponse) {
  this._promiseResponse = promiseResponse;
  this.status = promiseResponse.status;
  this.ok = promiseResponse.ok;
  this.statusText = promiseResponse.statusText;
  this.headers = promiseResponse.headers;
  this.url = promiseResponse.url;
  return this;
};

//------------------------------------------------------------------------------

/* Disabled for now as I'm not sure what the use case is.
   Send me a PR with test coverage if you need these. :-)
rxResponse.prototype.blob = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.blob());
};

rxResponse.prototype.arrayBuffer = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.arrayBuffer());
};

rxResponse.prototype.formData = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.formData());
};
*/

//------------------------------------------------------------------------------

rxResponse.prototype.text = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.text());
};

//------------------------------------------------------------------------------

rxResponse.prototype.json = function () {
  return Rx.Observable.fromPromise(this._promiseResponse.json());
};

//------------------------------------------------------------------------------

module.exports = function (url, options) {

  return Rx.Observable.fromPromise(fetch(url, options))
    .map((promiseResponse) => new rxResponse(promiseResponse));

};


Add specs for latest exit event

:new: Add specs for latest exit event

--- spec/main-spec.js
+++ spec/main-spec.js
@@ -11,14 +11,20 @@
     it('works as expected', function() {
       const child = fork(WORKER_PATH)
       const communication = Communication.createFromProcess(child)
+      let exitTriggered = 0

       waitsForPromise(function() {
+        communication.onDidExit(function() {
+          ++exitTriggered
+        })
         return communication.request('ping', 'ping').then(function(response) {
           expect(response).toBe('pong')
           return communication.request('ping', 'ping')
         }).then(function(response) {
           expect(response).toBe('pong')
           communication.kill()
+        }).then(function() {
+          expect(exitTriggered).toBe(1)
         })
       })
     })

<|original_code|>
'use babel'

import {fork} from 'child_process'
import * as Communication from '../src/main'

const WORKER_PATH = __dirname + '/fixtures/worker.js'

describe('Process-Communication', function() {

  describe('createFromProcess', function() {
    it('works as expected', function() {
      const child = fork(WORKER_PATH)
      const communication = Communication.createFromProcess(child)

      waitsForPromise(function() {
        return communication.request('ping', 'ping').then(function(response) {
          expect(response).toBe('pong')
          return communication.request('ping', 'ping')
        }).then(function(response) {
          expect(response).toBe('pong')
          communication.kill()
        })
      })
    })
  })

  describe('forkFile', function() {
    it('works as expected', function() {
      const communication = Communication.forkFile(WORKER_PATH)

      waitsForPromise(function(){
        return communication.request('error', {error: true}).then(function() {
          expect(false).toBe(true)
        }, function(error) {
          expect(error.message).toBe('Yes! It works too!')
          communication.kill()
        })
      })
    })
  })

})

<|edits_diff|>
--- spec/main-spec.js
+++ spec/main-spec.js
@@ -11,8 +11,12 @@
     it('works as expected', function() {
       const child = fork(WORKER_PATH)
       const communication = Communication.createFromProcess(child)
+      let exitTriggered = 0

       waitsForPromise(function() {
+        communication.onDidExit(function() {
+          ++exitTriggered
+        })
         return communication.request('ping', 'ping').then(function(response) {
           expect(response).toBe('pong')
           return communication.request('ping', 'ping')
<|current_version|>
'use babel'

import {fork} from 'child_process'
import * as Communication from '../src/main'

const WORKER_PATH = __dirname + '/fixtures/worker.js'

describe('Process-Communication', function() {

  describe('createFromProcess', function() {
    it('works as expected', function() {
      const child = fork(WORKER_PATH)
      const communication = Communication.createFromProcess(child)
      let exitTriggered = 0

      waitsForPromise(function() {
        communication.onDidExit(function() {
          ++exitTriggered
        })
        return communication.request('ping', 'ping').then(function(response) {
          expect(response).toBe('pong')
          return communication.request('ping', 'ping')
        }).then(function(response) {
          expect(response).toBe('pong')
          communication.kill()
        })
      })
    })
  })

  describe('forkFile', function() {
    it('works as expected', function() {
      const communication = Communication.forkFile(WORKER_PATH)

      waitsForPromise(function(){
        return communication.request('error', {error: true}).then(function() {
          expect(false).toBe(true)
        }, function(error) {
          expect(error.message).toBe('Yes! It works too!')
          communication.kill()
        })
      })
    })
  })

})

<|next_version|>
'use babel'

import {fork} from 'child_process'
import * as Communication from '../src/main'

const WORKER_PATH = __dirname + '/fixtures/worker.js'

describe('Process-Communication', function() {

  describe('createFromProcess', function() {
    it('works as expected', function() {
      const child = fork(WORKER_PATH)
      const communication = Communication.createFromProcess(child)
      let exitTriggered = 0

      waitsForPromise(function() {
        communication.onDidExit(function() {
          ++exitTriggered
        })
        return communication.request('ping', 'ping').then(function(response) {
          expect(response).toBe('pong')
          return communication.request('ping', 'ping')
        }).then(function(response) {
          expect(response).toBe('pong')
          communication.kill()
        }).then(function() {
          expect(exitTriggered).toBe(1)
        })
      })
    })
  })

  describe('forkFile', function() {
    it('works as expected', function() {
      const communication = Communication.forkFile(WORKER_PATH)

      waitsForPromise(function(){
        return communication.request('error', {error: true}).then(function() {
          expect(false).toBe(true)
        }, function(error) {
          expect(error.message).toBe('Yes! It works too!')
          communication.kill()
        })
      })
    })
  })

})


Add classes to identify Upload Field interface actions.

--- extensions/field_upload/assets/publish.js
+++ extensions/field_upload/assets/publish.js
@@ -8,8 +8,10 @@
 		if (file.length) {
 			var clear = jQuery('<a />')
 				.text('Change')
+				.addClass('action-change')
 				.prependTo(field.find('.label'));
 			var keep = jQuery('<a />')
+				.addClass('action-keep')
 				.text('Keep')
 				.prependTo(field.find('.label'))
 				.hide();

<|original_code|>
jQuery(document).ready(function() {
	jQuery('.field-upload').each(function() {
		var field = jQuery(this);
		var file = field.find('.file');
		var upload = field.find('.upload');
		var hidden = upload.find('input[type = "hidden"]');

		if (file.length) {
			var clear = jQuery('<a />')
				.text('Change')
				.prependTo(field.find('.label'));
			var keep = jQuery('<a />')
				.text('Keep')
				.prependTo(field.find('.label'))
				.hide();

			clear.bind('click', function() {
				var file = jQuery('<input type="file" />');

				file.attr('name', hidden.attr('name'));

				clear.hide();
				keep.show();
				upload.show();
				hidden.remove();
				file.appendTo(upload);
			});

			keep.bind('click', function() {
				var file = upload.find('input[type = "file"]');

				clear.show();
				keep.hide();
				upload.hide();
				file.remove();
				hidden.appendTo(upload);
			});

			upload.hide();
		}
	});
});
<|edits_diff|>
--- extensions/field_upload/assets/publish.js
+++ extensions/field_upload/assets/publish.js
@@ -8,6 +8,7 @@
 		if (file.length) {
 			var clear = jQuery('<a />')
 				.text('Change')
+				.addClass('action-change')
 				.prependTo(field.find('.label'));
 			var keep = jQuery('<a />')
 				.text('Keep')
<|current_version|>
jQuery(document).ready(function() {
	jQuery('.field-upload').each(function() {
		var field = jQuery(this);
		var file = field.find('.file');
		var upload = field.find('.upload');
		var hidden = upload.find('input[type = "hidden"]');

		if (file.length) {
			var clear = jQuery('<a />')
				.text('Change')
				.addClass('action-change')
				.prependTo(field.find('.label'));
			var keep = jQuery('<a />')
				.text('Keep')
				.prependTo(field.find('.label'))
				.hide();

			clear.bind('click', function() {
				var file = jQuery('<input type="file" />');

				file.attr('name', hidden.attr('name'));

				clear.hide();
				keep.show();
				upload.show();
				hidden.remove();
				file.appendTo(upload);
			});

			keep.bind('click', function() {
				var file = upload.find('input[type = "file"]');

				clear.show();
				keep.hide();
				upload.hide();
				file.remove();
				hidden.appendTo(upload);
			});

			upload.hide();
		}
	});
});
<|next_version|>
jQuery(document).ready(function() {
	jQuery('.field-upload').each(function() {
		var field = jQuery(this);
		var file = field.find('.file');
		var upload = field.find('.upload');
		var hidden = upload.find('input[type = "hidden"]');

		if (file.length) {
			var clear = jQuery('<a />')
				.text('Change')
				.addClass('action-change')
				.prependTo(field.find('.label'));
			var keep = jQuery('<a />')
				.addClass('action-keep')
				.text('Keep')
				.prependTo(field.find('.label'))
				.hide();

			clear.bind('click', function() {
				var file = jQuery('<input type="file" />');

				file.attr('name', hidden.attr('name'));

				clear.hide();
				keep.show();
				upload.show();
				hidden.remove();
				file.appendTo(upload);
			});

			keep.bind('click', function() {
				var file = upload.find('input[type = "file"]');

				clear.show();
				keep.hide();
				upload.hide();
				file.remove();
				hidden.appendTo(upload);
			});

			upload.hide();
		}
	});
});


Fix card image/links that have Æ in the name

--- app/card/card_service.js
+++ app/card/card_service.js
@@ -1,9 +1,15 @@
 app.service("cardService", function() {
   this.getCardUrl = function(name) {
+    name = this.sanitizeName_(name);
     return "http://gatherer.wizards.com/Pages/Card/Details.aspx?name=" + name;
   };

   this.getCardImage = function(name) {
+    name = this.sanitizeName_(name);
     return "http://gatherer.wizards.com/Handlers/Image.ashx?name=" + name + "&type=card&.jpg";
   };
+
+  this.sanitizeName_ = function(name) {
+    return name.replace("\u00C6", "Ae");
+  }
 });

<|original_code|>
app.service("cardService", function() {
  this.getCardUrl = function(name) {
    return "http://gatherer.wizards.com/Pages/Card/Details.aspx?name=" + name;
  };

  this.getCardImage = function(name) {
    return "http://gatherer.wizards.com/Handlers/Image.ashx?name=" + name + "&type=card&.jpg";
  };
});
<|edits_diff|>
--- app/card/card_service.js
+++ app/card/card_service.js
@@ -1,9 +1,11 @@
 app.service("cardService", function() {
   this.getCardUrl = function(name) {
+    name = this.sanitizeName_(name);
     return "http://gatherer.wizards.com/Pages/Card/Details.aspx?name=" + name;
   };

   this.getCardImage = function(name) {
+    name = this.sanitizeName_(name);
     return "http://gatherer.wizards.com/Handlers/Image.ashx?name=" + name + "&type=card&.jpg";
   };
 });
<|current_version|>
app.service("cardService", function() {
  this.getCardUrl = function(name) {
    name = this.sanitizeName_(name);
    return "http://gatherer.wizards.com/Pages/Card/Details.aspx?name=" + name;
  };

  this.getCardImage = function(name) {
    name = this.sanitizeName_(name);
    return "http://gatherer.wizards.com/Handlers/Image.ashx?name=" + name + "&type=card&.jpg";
  };
});
<|next_version|>
app.service("cardService", function() {
  this.getCardUrl = function(name) {
    name = this.sanitizeName_(name);
    return "http://gatherer.wizards.com/Pages/Card/Details.aspx?name=" + name;
  };

  this.getCardImage = function(name) {
    name = this.sanitizeName_(name);
    return "http://gatherer.wizards.com/Handlers/Image.ashx?name=" + name + "&type=card&.jpg";
  };

  this.sanitizeName_ = function(name) {
    return name.replace("\u00C6", "Ae");
  }
});


Add getPassword to Contractor class for hashing temp password

--- model/contractor.js
+++ model/contractor.js
@@ -1,3 +1,5 @@
+var crypto = require('crypto');
+
 module.exports =
   class Contractor {
   constructor(firstName, lastName, isResident, privateEmail) {
@@ -18,4 +20,8 @@

     return sanitizedFirst + '.' + sanitizedLast + '@7hci.com';
   }
+
+  getPassword() {
+    return crypto.createHash('md5').update(this.getFullName()).digest('hex');
+  }
 };

<|original_code|>
module.exports =
  class Contractor {
  constructor(firstName, lastName, isResident, privateEmail) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.isResident = isResident;
    this.privateEmail = privateEmail;
  }

  getFullName() {
    return this.firstName + ' ' + this.lastName;
  }

  getEmail() {
    var pattern = /[^a-zA-Z]/g;
    var sanitizedFirst = this.firstName.replace(pattern, '').toLowerCase();
    var sanitizedLast = this.lastName.replace(pattern, '').toLowerCase();

    return sanitizedFirst + '.' + sanitizedLast + '@7hci.com';
  }
};
<|edits_diff|>
--- model/contractor.js
+++ model/contractor.js
@@ -1,3 +1,5 @@
+var crypto = require('crypto');
+
 module.exports =
   class Contractor {
   constructor(firstName, lastName, isResident, privateEmail) {
<|current_version|>
var crypto = require('crypto');

module.exports =
  class Contractor {
  constructor(firstName, lastName, isResident, privateEmail) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.isResident = isResident;
    this.privateEmail = privateEmail;
  }

  getFullName() {
    return this.firstName + ' ' + this.lastName;
  }

  getEmail() {
    var pattern = /[^a-zA-Z]/g;
    var sanitizedFirst = this.firstName.replace(pattern, '').toLowerCase();
    var sanitizedLast = this.lastName.replace(pattern, '').toLowerCase();

    return sanitizedFirst + '.' + sanitizedLast + '@7hci.com';
  }
};
<|next_version|>
var crypto = require('crypto');

module.exports =
  class Contractor {
  constructor(firstName, lastName, isResident, privateEmail) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.isResident = isResident;
    this.privateEmail = privateEmail;
  }

  getFullName() {
    return this.firstName + ' ' + this.lastName;
  }

  getEmail() {
    var pattern = /[^a-zA-Z]/g;
    var sanitizedFirst = this.firstName.replace(pattern, '').toLowerCase();
    var sanitizedLast = this.lastName.replace(pattern, '').toLowerCase();

    return sanitizedFirst + '.' + sanitizedLast + '@7hci.com';
  }

  getPassword() {
    return crypto.createHash('md5').update(this.getFullName()).digest('hex');
  }
};