<commit_before>'use strict';

var express = require('express')
  , router = express.Router()
  , twimlGenerator = require('../lib/twiml-generator')
  , Call = require('../models/call')
  , url = require('url')
  , twilioCaller = require('../lib/twilio-caller');

var AGENT_WAIT_URL = 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.classical';

var connectConferenceUrl = function(req, agentId, conferenceId) {
  var pathname = `/conference/${conferenceId}/connect/${agentId}`;
  return url.format({
    protocol: 'https',
    host: req.get('host'),
    pathname: pathname
  });
};

// POST /conference/wait
router.post('/wait/', function (req, res) {
  res.type('text/xml');
  res.send(twimlGenerator.waitResponseTwiml().toString());
});

// POST /conference/:conferenceId/connect/agent1/
router.post('/:conferenceId/connect/agent1/', function (req, res) {
  res.type('text/xml');
  res.send(twimlGenerator.connectConferenceTwiml({
    conferenceId:req.params.conferenceId,
    waitUrl: AGENT_WAIT_URL,
    startConferenceOnEnter: true,
    endConferenceOnExit: false
  })
  .toString());
});

// POST /conference/:conferenceId/connect/agent2/
router.post('/:conferenceId/connect/agent2/', function (req, res) {
  res.type('text/xml');
  res.send(twimlGenerator.connectConferenceTwiml({
    conferenceId: req.params.conferenceId,
    waitUrl: AGENT_WAIT_URL,
    startConferenceOnEnter: true,
    endConferenceOnExit: true
  })
  .toString());
});

// POST /conference/connect/client/
router.post('/connect/client/', function (req, res) {
  var conferenceId = req.body.CallSid
    , agentOne = 'agent1'
    , callbackUrl = connectConferenceUrl(req, agentOne, conferenceId);

  twilioCaller.call(agentOne, callbackUrl);

  Call.findOneAndUpdate(
    {
      agentId: agentOne
    },
    {
      agentId: agentOne,
      conferenceId: conferenceId
    },
    {
      upsert: true
    })
  .then(function(doc){
    res.type('text/xml');
    res.send(twimlGenerator.connectConferenceTwiml({
      conferenceId:conferenceId,
      waitUrl: AGENT_WAIT_URL,
      startConferenceOnEnter: false,
      endConferenceOnExit: true
    })
    .toString());
  });
});

// POST /conference/:agentId/call/
router.post('/:agentId/call/', function (req, res) {
  var agentTwo = 'agent2';
  Call.findOne({agentId: req.params.agentId}, function (err, call) {
    var callbackUrl = connectConferenceUrl(req, agentTwo, call.conferenceId);
    twilioCaller.call(agentTwo, callbackUrl);
    res.sendStatus(200);
  });
});

module.exports = router;
<commit_msg>Fix identation<commit_after>'use strict';

var express = require('express')
  , router = express.Router()
  , twimlGenerator = require('../lib/twiml-generator')
  , Call = require('../models/call')
  , url = require('url')
  , twilioCaller = require('../lib/twilio-caller');

var AGENT_WAIT_URL = 'http://twimlets.com/holdmusic?Bucket=com.twilio.music.classical';

var connectConferenceUrl = function(req, agentId, conferenceId) {
  var pathname = `/conference/${conferenceId}/connect/${agentId}`;
  return url.format({
    protocol: 'https',
    host: req.get('host'),
    pathname: pathname
  });
};

// POST /conference/wait
router.post('/wait/', function (req, res) {
  res.type('text/xml');
  res.send(twimlGenerator.waitResponseTwiml().toString());
});

// POST /conference/:conferenceId/connect/agent1/
router.post('/:conferenceId/connect/agent1/', function (req, res) {
  res.type('text/xml');
  res.send(twimlGenerator.connectConferenceTwiml({
    conferenceId: req.params.conferenceId,
    waitUrl: AGENT_WAIT_URL,
    startConferenceOnEnter: true,
    endConferenceOnExit: false
  })
  .toString());
});

// POST /conference/:conferenceId/connect/agent2/
router.post('/:conferenceId/connect/agent2/', function (req, res) {
  res.type('text/xml');
  res.send(twimlGenerator.connectConferenceTwiml({
    conferenceId: req.params.conferenceId,
    waitUrl: AGENT_WAIT_URL,
    startConferenceOnEnter: true,
    endConferenceOnExit: true
  })
  .toString());
});

// POST /conference/connect/client/
router.post('/connect/client/', function (req, res) {
  var conferenceId = req.body.CallSid
    , agentOne = 'agent1'
    , callbackUrl = connectConferenceUrl(req, agentOne, conferenceId);

  twilioCaller.call(agentOne, callbackUrl);

  Call.findOneAndUpdate(
    {
      agentId: agentOne
    },
    {
      agentId: agentOne,
      conferenceId: conferenceId
    },
    {
      upsert: true
    })
  .then(function(doc){
    res.type('text/xml');
    res.send(twimlGenerator.connectConferenceTwiml({
      conferenceId:conferenceId,
      waitUrl: AGENT_WAIT_URL,
      startConferenceOnEnter: false,
      endConferenceOnExit: true
    })
    .toString());
  });
});

// POST /conference/:agentId/call/
router.post('/:agentId/call/', function (req, res) {
  var agentTwo = 'agent2';
  Call.findOne({agentId: req.params.agentId}, function (err, call) {
    var callbackUrl = connectConferenceUrl(req, agentTwo, call.conferenceId);
    twilioCaller.call(agentTwo, callbackUrl);
    res.sendStatus(200);
  });
});

module.exports = router;
<|endoftext|>


<commit_before>import 'whatwg-fetch';
import codemirror from 'codemirror';
import 'codemirror/mode/javascript/javascript';
import analytics from './analytics';
import redirectTraffic from './redirect-traffic';
import layoutFunctions from './layoutFunctions';
import clickEvents from './clickEvents';
import drag from './drag';
import examples from './add-examples';
import libraries from './add-libraries';
import $ from './helpers';
import share from './share';
import snackbar from './snackbar';
import frameBridge from './frameBridge';
import MESSAGES from './sandbox/keys';

const codeWrapper = $.getElement('.code-wrapper'),
  fiddleWrapper = $.getElement('.fiddle-wrapper'),
  themeChanger = $.getElement('.change-theme'),
  savedTheme = localStorage.getItem('theme'),
  pathAr = location.pathname.split('/'),
  fiddleId = pathAr[pathAr.length - 2],
  embedded = pathAr[1] === 'embed',
  startFiddle = $.getElement('.star');

analytics.start();
redirectTraffic.register();

window.embedded = embedded;
window.exampleSelector = $.getElement('.examples');
examples.addExamples();

window.librariesSelector = $.getElement('.libraries');
libraries.addLibraries();

// check to see if the share button should be shown
if (fiddleId && !embedded) {
  const shareEl = $.getElement('.share');
  $.addStyleTo(startFiddle, 'display', 'block');
  if (shareEl) { share.shareFiddle(fiddleId); }
} else {
  $.addStyleTo(startFiddle, 'display', 'none');
}

// handle the embedded buttons
if (embedded) {
  const es6Btn = $.getElement('.es6-click-btn');
  const consoleBtn = $.getElement('.console-click-btn');
  $.getElement('.edit-at-es6').href = document.location.href.replace('/embed', '');

  es6Btn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'block');
    $.getElement('.result-wrapper').addStyle('display', 'none');
    $.addClass(es6Btn, 'selected');
    $.removeClass(consoleBtn, 'selected');
  };

  consoleBtn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'none');
    $.getElement('.result-wrapper').addStyle('display', 'block');
    $.removeClass(es6Btn, 'selected');
    $.addClass(consoleBtn, 'selected');
  };
}

// Change the layout of the page based on the type clicked.
// Save this layout choice in localStorage
// By default this will be vertical
$.getElement('.vertical').onclick = () => {
  layoutFunctions.setVerticalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('vertical');
};

// Onclick of the horizontal button then make the page visually horizontal
// And save the layout option clicked (in this case horizontal) to localstorage
$.getElement('.horizontal').onclick = () => {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('horizontal');
};

// add the fiddle area
const fiddle = codemirror($.getElement('.fiddle'), {
  lineNumbers: !embedded,
  readOnly: embedded ? 'nocursor' : false,
  theme: savedTheme || 'default',
});
fiddle.focus();

// If the user has previously selected to use the horizontal layout then load that
if (localStorage.getItem('es6fiddleLayout') === 'horizontal') {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  // Otherwise make the page the default vertical style
} else {
  layoutFunctions.setVerticalStyle(codeWrapper);
}

// If the user has previously enabled dark mode then open in dark mode
if (localStorage.getItem('es6fiddleDarkMode') === 'true') {
  clickEvents.enableDarkMode();
} else {
  clickEvents.disableDarkMode();
}

// When the dark mode button is clicked, toggle the dark mode setting
$.getElement('.dark-mode').onclick = () => {
  clickEvents.darkModeClick(clickEvents.disableDarkMode, clickEvents.enableDarkMode, fiddle);
};

// Set the saved theme in the theme changer dropdown
if (savedTheme) {
  themeChanger.value = savedTheme;
}

// Add line number to all console.log() statements
function calculateLineNumber(fiddleValue) {
  const lines = fiddleValue.split(/\n/);
  let newLines = '';
  newLines = lines.map((line, index) => {
    const consReg = /(console\.log\()(.*)/;
    //  separate console.log from original string and split it in to
    // "console.log(" and ")"
    const clgLines = line.match(consReg);
    if (clgLines) {
      // Add line no: to console.log and join it with rest of the original line.
      // return line.slice(0, clgLines.index) + clgLines[1] + `'${index+1}: ' , ` +clgLines[2];
      return `${line.slice(0, clgLines.index) + clgLines[1]}'${index + 1}: ' , ${clgLines[2]}`;
    }
    return line;
  });
  return newLines.join('\n');
}

/* eslint-disable */
const runFiddle = () => {
  frameBridge.send(MESSAGES.RUN_SCRIPT, calculateLineNumber(fiddle.getValue()));
};

/* eslint-enable */

const getFiddle = (data) => {
  if (data.fiddle) {
    if (data.value) {
      fiddle.setValue(data.value);
    } else {
      fiddle.setValue('* Sorry, but I could not load your code right now. *');
    }
    if (data.isPrivate) {
      const privateIcon = $.getElement('.fa-globe');
      privateIcon.classList.remove('fa-globe');
      privateIcon.classList.add('fa-lock');
      privateIcon.parentElement.setAttribute('data-balloon', 'Private Fiddle');
    }
  } else {
    $.addStyleTo(startFiddle, 'display', 'none');
    fiddle.setValue(data.message);
  }

  if (embedded) { // go ahead and run the code
    runFiddle();
  }
};

// if fiddleId is define then load up the saved code
if (fiddleId) {
  fetch(`/fiddles/${fiddleId}`, {
    credentials: 'same-origin',
  }).then(resp => resp.json()).then(data => getFiddle(data));
}

// if this is not an embedded fiddle than add extra elements to this
if (!embedded) {
  // run the input
  $.getElement('.run').onclick = runFiddle;

  // lint the result
  $.getElement('.lint').onclick = () => {
    const lint = JSHINT(fiddle.getValue(), {
      esnext: true,
      devel: true,
      browser: true,
    });

    // remove the line error class from all lines
    fiddle.eachLine((line) => {
      fiddle.removeLineClass(line, 'background', 'line-error');
    });

    const lints = [];
    if (!lint) {
      JSHINT.errors.forEach((err) => {
        fiddle.addLineClass(err.line - 1, 'background', 'line-error');
        lints.push(`console.log('Line ' + ${err.line} + ':', '${err.reason.replace(/'/g, '\\\'')}')\n`);
      });
    } else {
      lints.push('console.log(\'Awesome! Your code is lint free!\');');
    }

    frameBridge.send(MESSAGES.RUN_SCRIPT, lints.join('\n'));
  };

  // export to Github gist
  $.getElement('.gist').onclick = () => clickEvents.exportAsGist(fiddle);

  // save the code
  document.querySelector('.save').onclick = () => clickEvents.saveBtn(fiddle);

  // star the code
  $.getElement('.star').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/star/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
      .then(resp => resp.json())
      .then(data => clickEvents.starFiddle(data));
    }
  };

  // Make fiddle private
  $.getElement('.private').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/private/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
          .then(resp => resp.json())
          .then(data => clickEvents.privateFiddle(data));
    } else {
      snackbar.showSnackbar('You don\'t appear to have any code or its not saved.');
    }
  };

  themeChanger.onchange = () => {
    const theme = themeChanger.options[themeChanger.selectedIndex].textContent;
    fiddle.setOption('theme', theme);
    localStorage.setItem('theme', theme);
  };

  // load the selected code
  window.exampleSelector.onchange = () => {
    if (window.exampleSelector.value) {
      let code = 'Example Can Not Be Found';

      if (window.es6Example[window.exampleSelector.value]) {
        ({ code } = window.es6Example[window.exampleSelector.value]);
      } else if (window.es7Example[window.exampleSelector.value]) {
        ({ code } = window.es7Example[window.exampleSelector.value]);
      }

      fiddle.setValue(code);
    }
  };

  // load the selected javascript library
  window.librariesSelector.onchange = () => {
    if (window.librariesSelector.value) {
      const script = $.createElement('script');
      script.onload = function onScriptLoad() {
        console.log(`${window.librariesSelector.selectedOptions[0].text} Script loaded`);
      };
      script.src = window.librariesSelector.value;

      document.head.appendChild(script);
    }
  };
} // end not embedded

// Add dragging funcionality
fiddleWrapper.addEventListener('click', function init() {
  fiddleWrapper.removeEventListener('click', init, false);
  $.getElement('.resizer').addEventListener('mousedown', drag.initDrag, false);
}, false);
<commit_msg>Remove console<commit_after>import 'whatwg-fetch';
import codemirror from 'codemirror';
import 'codemirror/mode/javascript/javascript';
import analytics from './analytics';
import redirectTraffic from './redirect-traffic';
import layoutFunctions from './layoutFunctions';
import clickEvents from './clickEvents';
import drag from './drag';
import examples from './add-examples';
import libraries from './add-libraries';
import $ from './helpers';
import share from './share';
import snackbar from './snackbar';
import frameBridge from './frameBridge';
import MESSAGES from './sandbox/keys';

const codeWrapper = $.getElement('.code-wrapper'),
  fiddleWrapper = $.getElement('.fiddle-wrapper'),
  themeChanger = $.getElement('.change-theme'),
  savedTheme = localStorage.getItem('theme'),
  pathAr = location.pathname.split('/'),
  fiddleId = pathAr[pathAr.length - 2],
  embedded = pathAr[1] === 'embed',
  startFiddle = $.getElement('.star');

analytics.start();
redirectTraffic.register();

window.embedded = embedded;
window.exampleSelector = $.getElement('.examples');
examples.addExamples();

window.librariesSelector = $.getElement('.libraries');
libraries.addLibraries();

// check to see if the share button should be shown
if (fiddleId && !embedded) {
  const shareEl = $.getElement('.share');
  $.addStyleTo(startFiddle, 'display', 'block');
  if (shareEl) { share.shareFiddle(fiddleId); }
} else {
  $.addStyleTo(startFiddle, 'display', 'none');
}

// handle the embedded buttons
if (embedded) {
  const es6Btn = $.getElement('.es6-click-btn');
  const consoleBtn = $.getElement('.console-click-btn');
  $.getElement('.edit-at-es6').href = document.location.href.replace('/embed', '');

  es6Btn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'block');
    $.getElement('.result-wrapper').addStyle('display', 'none');
    $.addClass(es6Btn, 'selected');
    $.removeClass(consoleBtn, 'selected');
  };

  consoleBtn.onclick = () => {
    $.getElement('.fiddle').addStyle('display', 'none');
    $.getElement('.result-wrapper').addStyle('display', 'block');
    $.removeClass(es6Btn, 'selected');
    $.addClass(consoleBtn, 'selected');
  };
}

// Change the layout of the page based on the type clicked.
// Save this layout choice in localStorage
// By default this will be vertical
$.getElement('.vertical').onclick = () => {
  layoutFunctions.setVerticalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('vertical');
};

// Onclick of the horizontal button then make the page visually horizontal
// And save the layout option clicked (in this case horizontal) to localstorage
$.getElement('.horizontal').onclick = () => {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  layoutFunctions.saveLayoutOption('horizontal');
};

// add the fiddle area
const fiddle = codemirror($.getElement('.fiddle'), {
  lineNumbers: !embedded,
  readOnly: embedded ? 'nocursor' : false,
  theme: savedTheme || 'default',
});
fiddle.focus();

// If the user has previously selected to use the horizontal layout then load that
if (localStorage.getItem('es6fiddleLayout') === 'horizontal') {
  layoutFunctions.setHorizontalStyle(codeWrapper);
  // Otherwise make the page the default vertical style
} else {
  layoutFunctions.setVerticalStyle(codeWrapper);
}

// If the user has previously enabled dark mode then open in dark mode
if (localStorage.getItem('es6fiddleDarkMode') === 'true') {
  clickEvents.enableDarkMode();
} else {
  clickEvents.disableDarkMode();
}

// When the dark mode button is clicked, toggle the dark mode setting
$.getElement('.dark-mode').onclick = () => {
  clickEvents.darkModeClick(clickEvents.disableDarkMode, clickEvents.enableDarkMode, fiddle);
};

// Set the saved theme in the theme changer dropdown
if (savedTheme) {
  themeChanger.value = savedTheme;
}

// Add line number to all console.log() statements
function calculateLineNumber(fiddleValue) {
  const lines = fiddleValue.split(/\n/);
  let newLines = '';
  newLines = lines.map((line, index) => {
    const consReg = /(console\.log\()(.*)/;
    //  separate console.log from original string and split it in to
    // "console.log(" and ")"
    const clgLines = line.match(consReg);
    if (clgLines) {
      // Add line no: to console.log and join it with rest of the original line.
      // return line.slice(0, clgLines.index) + clgLines[1] + `'${index+1}: ' , ` +clgLines[2];
      return `${line.slice(0, clgLines.index) + clgLines[1]}'${index + 1}: ' , ${clgLines[2]}`;
    }
    return line;
  });
  return newLines.join('\n');
}

/* eslint-disable */
const runFiddle = () => {
  frameBridge.send(MESSAGES.RUN_SCRIPT, calculateLineNumber(fiddle.getValue()));
};

/* eslint-enable */

const getFiddle = (data) => {
  if (data.fiddle) {
    if (data.value) {
      fiddle.setValue(data.value);
    } else {
      fiddle.setValue('* Sorry, but I could not load your code right now. *');
    }
    if (data.isPrivate) {
      const privateIcon = $.getElement('.fa-globe');
      privateIcon.classList.remove('fa-globe');
      privateIcon.classList.add('fa-lock');
      privateIcon.parentElement.setAttribute('data-balloon', 'Private Fiddle');
    }
  } else {
    $.addStyleTo(startFiddle, 'display', 'none');
    fiddle.setValue(data.message);
  }

  if (embedded) { // go ahead and run the code
    runFiddle();
  }
};

// if fiddleId is define then load up the saved code
if (fiddleId) {
  fetch(`/fiddles/${fiddleId}`, {
    credentials: 'same-origin',
  }).then(resp => resp.json()).then(data => getFiddle(data));
}

// if this is not an embedded fiddle than add extra elements to this
if (!embedded) {
  // run the input
  $.getElement('.run').onclick = runFiddle;

  // lint the result
  $.getElement('.lint').onclick = () => {
    const lint = JSHINT(fiddle.getValue(), {
      esnext: true,
      devel: true,
      browser: true,
    });

    // remove the line error class from all lines
    fiddle.eachLine((line) => {
      fiddle.removeLineClass(line, 'background', 'line-error');
    });

    const lints = [];
    if (!lint) {
      JSHINT.errors.forEach((err) => {
        fiddle.addLineClass(err.line - 1, 'background', 'line-error');
        lints.push(`console.log('Line ' + ${err.line} + ':', '${err.reason.replace(/'/g, '\\\'')}')\n`);
      });
    } else {
      lints.push('console.log(\'Awesome! Your code is lint free!\');');
    }

    frameBridge.send(MESSAGES.RUN_SCRIPT, lints.join('\n'));
  };

  // export to Github gist
  $.getElement('.gist').onclick = () => clickEvents.exportAsGist(fiddle);

  // save the code
  document.querySelector('.save').onclick = () => clickEvents.saveBtn(fiddle);

  // star the code
  $.getElement('.star').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/star/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
      .then(resp => resp.json())
      .then(data => clickEvents.starFiddle(data));
    }
  };

  // Make fiddle private
  $.getElement('.private').onclick = () => {
    const pathArr = window.location.pathname.split('/'),
      fiddleID = pathArr[1].length > 1 ? pathArr[1] : -1;

    if (fiddleID !== -1) {
      fetch(`/private/${fiddleID}`, {
        method: 'POST',
        credentials: 'same-origin',
        headers: new Headers({
          'Content-Type': 'application/json',
        }),
      })
          .then(resp => resp.json())
          .then(data => clickEvents.privateFiddle(data));
    } else {
      snackbar.showSnackbar('You don\'t appear to have any code or its not saved.');
    }
  };

  themeChanger.onchange = () => {
    const theme = themeChanger.options[themeChanger.selectedIndex].textContent;
    fiddle.setOption('theme', theme);
    localStorage.setItem('theme', theme);
  };

  // load the selected code
  window.exampleSelector.onchange = () => {
    if (window.exampleSelector.value) {
      let code = 'Example Can Not Be Found';

      if (window.es6Example[window.exampleSelector.value]) {
        ({ code } = window.es6Example[window.exampleSelector.value]);
      } else if (window.es7Example[window.exampleSelector.value]) {
        ({ code } = window.es7Example[window.exampleSelector.value]);
      }

      fiddle.setValue(code);
    }
  };

  // load the selected javascript library
  window.librariesSelector.onchange = () => {
    if (window.librariesSelector.value) {
      const script = $.createElement('script');
      script.onload = function onScriptLoad() {
        // Library loaded
        // console.log(`${window.librariesSelector.selectedOptions[0].text} Script loaded`);
      };
      script.src = window.librariesSelector.value;

      document.head.appendChild(script);
    }
  };
} // end not embedded

// Add dragging funcionality
fiddleWrapper.addEventListener('click', function init() {
  fiddleWrapper.removeEventListener('click', init, false);
  $.getElement('.resizer').addEventListener('mousedown', drag.initDrag, false);
}, false);
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var uuid = require('node-uuid');
var express = require('express');
var Item = require(__dirname + '/../models/item');
var ItemDetail = require(__dirname + '/../models/itemDetail');
var User = require(__dirname + '/../models/user');

var itemRouter = module.exports = express.Router();

// This route gets the details on an item.
// Call this route with the detailId of any posted item.
// GET /item/{itemDetailId}
itemRouter.get('/:item_id', function(req, res)
{
	ItemDetail.findById(req.params.item_id, function(err, item) {
		if (!item) res.status(404).json({msg: 'Item doesn\'t exist.'});
		else res.json(item);
	});
});

// This is the update endpoint.
// PUT /item/{itemDetailId}
itemRouter.put('/:item_id', function(req, res)
{
	ItemDetail.findById(req.params.item_id, function(err, itemDetail) {
		if (err) res.send(err);
		else if (!itemDetail) res.status(404).json({ msg: 'Item doesn\'t exist.' });
		else
		{
			Item.findOne({'linkId': itemDetail.linkId}, function(err, item)
			{
				if (!item)
				{
					res.status(404).json({ msg: 'Item doesn\'t exist.' });
					return;
				}

				if (req.body.title)
				{
					itemDetail.title = req.body.title;
					item.title = req.body.title;
				}
				if (req.body.description) {
					item.description = req.body.description;
					itemDetail.description = req.body.description;
				}
				if (req.body.askingPrice)
				{
					itemDetail.askingPrice = req.body.askingPrice;
					item.askingPrice = req.body.askingPrice;
				}
				if (req.body.postDate) {
					  itemDetail.postDate = req.body.postDate;
					  item.postDate = req.body.postDate;
				}
				if (req.body.displayPhoto) item.displayPhoto = req.body.displayPhoto;
				if (req.body.morePhotos)  itemDetail.morePhotos = req.body.morePhotos;
				if (req.body.preferredMethodOfContact) itemDetail.preferredMethodOfContact = req.body.preferredMethodOfContact;

				itemDetail.save(function(err) {
					if (err) res.send(err);
					else
					{
						item.save(function(err)
						{
							if (err)
								res.send(err);

							else
								res.status(200).json({ msg: 'Item detail updated.'});

						})
					}
				});
			});
		}
	});
});

// DELETE /item/{detailId}
itemRouter.delete('/:item_id', function(req, res) {
	ItemDetail.findById(req.params.item_id, function(err, itemDetail) {
		if (!itemDetail) res.status(404).json({msg: 'Item doesn\'t exist.'});
		else if (err) res.send(err);
		else {
			User.findOne({'username': itemDetail.sellerUserName}, function(err, foundUser) {
				if (!foundUser) res.status(404).json({ msg: 'The user is missing for this item.'});
				else if (err) res.send(err);
				else {
					foundUser.itemsForSale --;
					foundUser.save(function(err){
						if (err) {
							res.send(err);
							return;
						}
					});
				}

			});

			Item.findOne({'linkId': itemDetail.linkId }, function(err, item) {
				if (!item) res.status(404).json({ msg: 'Item not found.'});
				else if (err) res.send(err);
				else {
					Item.remove({ _id: item._id}, function(err, item) {
						if (err) res.send(err);
						else
						{
							ItemDetail.remove({ _id: req.params.item_id}, function(err, itemDetail){
								if (err) res.send(err);

								res.json({ msg: 'Item deleted.'});
							})
						}
					});
				}
			});
		}
	});
});

// This route gets all lightweight items.
// This would eventually be built out for searching.
itemRouter.get('/', function(req, res) {

	if (!req.query.q || req.query.q === "") {
		Item.find(function(err, items) {
			if (err) res.send(err);

			res.json(items);
		});
	}
	else {

		var searchterm = new RegExp(req.query.q, 'i');

		Item.find({$or:[
			{'title'		: searchterm},
			{'description'	: searchterm}]}, function(err, items) {
			if (err) res.send(err);

			res.json(items);
		});
	}
});

// Used to create an item advertisement.
// Successfully calling this route will create an object for an item's details as well as the item's posting.
itemRouter.post('/', function(req, res) {

	User.findOne({'username': req.body.sellerUserName}, function(err, foundUser) {
		if (!foundUser) res.status(404).json({ msg: 'User doesn\'t exist.' });
		else if (err) res.send(err);
		else
		{
			var dateOfPost = Date.now(); // Get the date at the time of post.

			var linkId = uuid.v4(); // Use this ID to link

			// Create the detailed post.
			var itemDetail = new ItemDetail();
			itemDetail.title = req.body.title;
			itemDetail.linkId = linkId;
			itemDetail.displayPhoto = req.body.displayPhoto;
			itemDetail.description = req.body.description;
			itemDetail.askingPrice = req.body.askingPrice;
			itemDetail.postDate = dateOfPost;
			itemDetail.sellerUserName = req.body.sellerUserName;
			itemDetail.sellerRating = foundUser.sellerRating;
			if (!foundUser.sellerTransHistory || foundUser.sellerTransHistory === "")
				itemDetail.sellerTransHistory = 0; // Was an empty string.
			else itemDetail.sellerTransHistory = foundUser.sellerHistory;
			itemDetail.sellerAverageResponse = foundUser.averageResponseInMinutes;
			itemDetail.sellerOtherItems = foundUser.itemsForSale + 1;
			itemDetail.latitude = foundUser.locationLng;
			itemDetail.longitude = foundUser.locationLat;
			itemDetail.morePhotos = req.body.morePhotos;
			itemDetail.noOfInquiries = 0; // Starts at zero at the time of posting.
			itemDetail.preferredMethodOfContact = req.body.preferredMethodOfContact;

			itemDetail.save(function(err)
			{
				if (err) res.send(err);

					res.status(201).json({ msg: 'Item created with ID ' + itemDetail._id });
			});

			// Create the light-weight version for searching that links to the details.
			var item = new Item();
			item.detailId = itemDetail._id; // Keeping detail ID for fast lookup.
			item.linkId = linkId; // We can index on the linkId once we create the index on the DB.
			item.title = req.body.title;
			item.description = req.body.description;
			item.displayPhoto = req.body.displayPhoto;
			item.askingPrice = req.body.askingPrice;
			item.postDate = dateOfPost;
			item.userName = req.body.userName;
			item.sellerRating = req.body.sellerRating;

			item.save(function(err)
			{
				if (err) res.send(err);
			});

			// Increment itemsForSale
			if (!foundUser.itemsForSale)
				foundUser.itemsForSale = 1;
			else
				foundUser.itemsForSale ++;

			foundUser.save(function(err){
				if (err) console.log(err);
			});
		}
	});
});
<commit_msg>items post now! hooray!<commit_after>var mongoose = require('mongoose');
var uuid = require('node-uuid');
var express = require('express');
var Item = require(__dirname + '/../models/item');
var ItemDetail = require(__dirname + '/../models/itemDetail');
var User = require(__dirname + '/../models/user');

var itemRouter = module.exports = express.Router();

// This route gets the details on an item.
// Call this route with the detailId of any posted item.
// GET /item/{itemDetailId}
itemRouter.get('/:item_id', function(req, res)
{
	ItemDetail.findById(req.params.item_id, function(err, item) {
		if (!item) res.status(404).json({msg: 'Item doesn\'t exist.'});
		else res.json(item);
	});
});

// This is the update endpoint.
// PUT /item/{itemDetailId}
itemRouter.put('/:item_id', function(req, res)
{
	ItemDetail.findById(req.params.item_id, function(err, itemDetail) {
		if (err) res.send(err);
		else if (!itemDetail) res.status(404).json({ msg: 'Item doesn\'t exist.' });
		else
		{
			Item.findOne({'linkId': itemDetail.linkId}, function(err, item)
			{
				if (!item)
				{
					res.status(404).json({ msg: 'Item doesn\'t exist.' });
					return;
				}

				if (req.body.title)
				{
					itemDetail.title = req.body.title;
					item.title = req.body.title;
				}
				if (req.body.description) {
					item.description = req.body.description;
					itemDetail.description = req.body.description;
				}
				if (req.body.askingPrice)
				{
					itemDetail.askingPrice = req.body.askingPrice;
					item.askingPrice = req.body.askingPrice;
				}
				if (req.body.postDate) {
					  itemDetail.postDate = req.body.postDate;
					  item.postDate = req.body.postDate;
				}
				if (req.body.displayPhoto) item.displayPhoto = req.body.displayPhoto;
				if (req.body.morePhotos)  itemDetail.morePhotos = req.body.morePhotos;
				if (req.body.preferredMethodOfContact) itemDetail.preferredMethodOfContact = req.body.preferredMethodOfContact;

				itemDetail.save(function(err) {
					if (err) res.send(err);
					else
					{
						item.save(function(err)
						{
							if (err)
								res.send(err);

							else
								res.status(200).json({ msg: 'Item detail updated.'});

						})
					}
				});
			});
		}
	});
});

// DELETE /item/{detailId}
itemRouter.delete('/:item_id', function(req, res) {
	ItemDetail.findById(req.params.item_id, function(err, itemDetail) {
		if (!itemDetail) res.status(404).json({msg: 'Item doesn\'t exist.'});
		else if (err) res.send(err);
		else {
			User.findOne({'username': itemDetail.sellerUserName}, function(err, foundUser) {
				if (!foundUser) res.status(404).json({ msg: 'The user is missing for this item.'});
				else if (err) res.send(err);
				else {
					foundUser.itemsForSale --;
					foundUser.save(function(err){
						if (err) {
							res.send(err);
							return;
						}
					});
				}

			});

			Item.findOne({'linkId': itemDetail.linkId }, function(err, item) {
				if (!item) res.status(404).json({ msg: 'Item not found.'});
				else if (err) res.send(err);
				else {
					Item.remove({ _id: item._id}, function(err, item) {
						if (err) res.send(err);
						else
						{
							ItemDetail.remove({ _id: req.params.item_id}, function(err, itemDetail){
								if (err) res.send(err);

								res.json({ msg: 'Item deleted.'});
							})
						}
					});
				}
			});
		}
	});
});

// This route gets all lightweight items.
// This would eventually be built out for searching.
itemRouter.get('/', function(req, res) {

	if (!req.query.q || req.query.q === "") {
		Item.find(function(err, items) {
			if (err) res.send(err);

			res.json(items);
		});
	}
	else {

		var searchterm = new RegExp(req.query.q, 'i');

		Item.find({$or:[
			{'title'		: searchterm},
			{'description'	: searchterm}]}, function(err, items) {
			if (err) res.send(err);

			res.json(items);
		});
	}
});

// Used to create an item advertisement.
// Successfully calling this route will create an object for an item's details as well as the item's posting.
itemRouter.post('/', function(req, res) {

	User.findOne({'username': req.body.sellerUserName}, function(err, foundUser) {
		if (!foundUser) res.status(404).json({ msg: 'User doesn\'t exist.' });
		else if (err) res.send(err);
		else
		{
			var dateOfPost = Date.now(); // Get the date at the time of post.

			var linkId = uuid.v4(); // Use this ID to link

			// Create the detailed post.
			var itemDetail = new ItemDetail();
			itemDetail.title = req.body.title;
			itemDetail.linkId = linkId;
			itemDetail.displayPhoto = req.body.displayPhoto;
			itemDetail.description = req.body.description;
			itemDetail.askingPrice = req.body.askingPrice;
			itemDetail.postDate = dateOfPost;
			itemDetail.sellerUserName = req.body.sellerUserName;
			itemDetail.sellerRating = foundUser.sellerRating;
			if (!foundUser.sellerTransHistory || foundUser.sellerTransHistory === "")
				itemDetail.sellerTransHistory = 0; // Was an empty string.
			else itemDetail.sellerTransHistory = foundUser.sellerHistory;
			itemDetail.sellerAverageResponse = foundUser.averageResponseInMinutes;
			itemDetail.sellerOtherItems = foundUser.itemsForSale + 1;
			itemDetail.latitude = foundUser.locationLng;
			itemDetail.longitude = foundUser.locationLat;
			itemDetail.morePhotos = req.body.morePhotos;
			itemDetail.noOfInquiries = 0; // Starts at zero at the time of posting.
			itemDetail.preferredMethodOfContact = req.body.preferredMethodOfContact;

			itemDetail.save(function(err, savedItemDetail)
			{
				if (err) res.send(err);
				else res.status(201).json({ msg: 'Item created with ID ' + savedItemDetail._id });
			});

			// Create the light-weight version for searching that links to the details.
			var item = new Item();
			item.detailId = itemDetail._id; // Keeping detail ID for fast lookup.
			item.linkId = linkId; // We can index on the linkId once we create the index on the DB.
			item.title = req.body.title;
			item.description = req.body.description;
			item.displayPhoto = req.body.displayPhoto;
			item.askingPrice = req.body.askingPrice;
			item.postDate = dateOfPost;
			item.userName = req.body.userName;
			item.sellerRating = req.body.sellerRating;

			item.save(function(err)
			{
				if (err) res.send(err);
			});

			// Increment itemsForSale
			if (!foundUser.itemsForSale)
				foundUser.itemsForSale = 1;
			else
				foundUser.itemsForSale ++;

			foundUser.save(function(err){
				if (err) console.log(err);
			});
		}
	});
});
<|endoftext|>


<commit_before>// Creates the main splash scene (if you can even call it a scene)
//
// times: [Array<SplashTime>] All of the timing objects of your splash
//
// If you assign an onEnd property to the object and it's a function, it'll fire
// once the splash is completed.

export class Splash {
	constructor(times) {
		this._times = times;
	}

	run() {
		this._previousTime = window.performance.now();

		for (let time of this._times) {
			time.start();
		}

		this._update();
	}

	_update() {
		let now = window.performance.now(),
			delta = now - this._previousTime;
		this._previousTime = now;

		for (let time of this._times) {
			time.update(delta);
		}

		requestAnimationFrame(this._update.bind(this));
	}
}

// Creates a splash instace from an array of objects.
//
// Example:
// ```
// from([
//     {
//         delay: 1, in: 0.5, out: 0.5,
//         effects: [new GrowAndShrink(element)]
//     },
//     {
//         delay: 2, in: 1, stay: 0.2, out: 1
//         effects: [new FadeInAndOut(element)]
//     }
// ]);
// ```
// (Yes, I am aware that this would be pointless to do, but whatever)
export function splashFromArray(array) {
	let splashTimers = [];
	for (let time of array) {
		splashTimers.push(new SplashTimer(
			time.delay || 0,
			time.effects,
			{
				open: time.in || 0,
				stay: time.stay || 0,
				out: time.out || 0
			}
		));
	}
	return new Splash(splashTimers);
}

// Creates a splash timer object. Used for timing all the effects.
//
// delay: How much should this timer be delayed after the splash was started (seconds)
// effects: [Array<SplashEffect>] What effects to use
// parts: {
//     open: [Float] How long opening does this timer have (seconds)
//     stay: [Float] How long does it stay (the middle part) (seconds)
//     out: [Float] How long does it take it to end (seconds)
// }
//
// If one of the parts isn't present, a value of 0 seconds will be assumed.

export class SplashTimer {
	constructor(delay, effects, parts) {
		this.delay = delay;
		this.effects = effects;
		this.parts = {
			open: parts.open || 0,
			stay: parts.stay || 0,
			out: parts.out || 0
		}
	}

	update(delta) {
		this.seconds += delta / 1000;

		if (this.started) {
			if (this.seconds <= this._times[0]) {
				let value = this.seconds / this.parts.open;
				this._runEffect("in", value);
			} else if (this.seconds <= this._times[1]) {
				if (this._count == 0) {
					this._runEffect("in", 1);
					this._count = 1;
				}

				let value = (this.seconds - this._times[0]) / this.parts.stay;
				this._runEffect("stay", value);
			} else if (this.seconds <= this._times[2]) {
				if (this._count == 1) {
					this._runEffect("stay", 1);
					this._count = 2;
				}

				let value = (this.seconds - this._times[1]) / this.parts.out;
				this._runEffect("out", value);
			} else if (this._count == 2) {
				this._runEffect("out", 1);
				this._count = 3;
			}
		} else {
			this._runEffect("in", 0);

			if (this.seconds >= this.delay) {
				this.seconds = 0;
				this.started = true;
			}
		}
	}

	_runEffect(stage, value) {
		for (let effect of this.effects) {
			if (typeof effect[stage] == "function") effect[stage](value);
		}
	}

	start() {
		this.seconds = 0;
		this._times = [
			this.parts.open,
			this.parts.open + this.parts.stay,
			this.parts.open + this.parts.stay + this.parts.out
		];
		this._count = 0;
	}
}

import * as effects from "./effects";
import * as interpolation from "./interpolation.js";

export { effects };
export { interpolation };
<commit_msg>Fix last frame not getting run in certain conditions<commit_after>// Creates the main splash scene (if you can even call it a scene)
//
// times: [Array<SplashTime>] All of the timing objects of your splash
//
// If you assign an onEnd property to the object and it's a function, it'll fire
// once the splash is completed.

export class Splash {
	constructor(times) {
		this._times = times;
	}

	run() {
		this._previousTime = window.performance.now();

		for (let time of this._times) {
			time.start();
		}

		this._update();
	}

	_update() {
		let now = window.performance.now(),
			delta = now - this._previousTime;
		this._previousTime = now;

		for (let time of this._times) {
			time.update(delta);
		}

		requestAnimationFrame(this._update.bind(this));
	}
}

// Creates a splash instace from an array of objects.
//
// Example:
// ```
// from([
//     {
//         delay: 1, in: 0.5, out: 0.5,
//         effects: [new GrowAndShrink(element)]
//     },
//     {
//         delay: 2, in: 1, stay: 0.2, out: 1
//         effects: [new FadeInAndOut(element)]
//     }
// ]);
// ```
// (Yes, I am aware that this would be pointless to do, but whatever)
export function splashFromArray(array) {
	let splashTimers = [];
	for (let time of array) {
		splashTimers.push(new SplashTimer(
			time.delay || 0,
			time.effects,
			{
				open: time.in || 0,
				stay: time.stay || 0,
				out: time.out || 0
			}
		));
	}
	return new Splash(splashTimers);
}

// Creates a splash timer object. Used for timing all the effects.
//
// delay: How much should this timer be delayed after the splash was started (seconds)
// effects: [Array<SplashEffect>] What effects to use
// parts: {
//     open: [Float] How long opening does this timer have (seconds)
//     stay: [Float] How long does it stay (the middle part) (seconds)
//     out: [Float] How long does it take it to end (seconds)
// }
//
// If one of the parts isn't present, a value of 0 seconds will be assumed.

export class SplashTimer {
	constructor(delay, effects, parts) {
		this.delay = delay;
		this.effects = effects;
		this.parts = {
			open: parts.open || 0,
			stay: parts.stay || 0,
			out: parts.out || 0
		}
	}

	update(delta) {
		this.seconds += delta / 1000;

		if (this.started) {
			if (this.seconds <= this._times[0]) {
				let value = this.seconds / this.parts.open;
				this._runEffect("in", value);
			} else if (this.seconds <= this._times[1]) {
				if (this._count == 0) {
					this._runEffect("in", 1);
					this._count = 1;
				}

				let value = (this.seconds - this._times[0]) / this.parts.stay;
				this._runEffect("stay", value);
			} else if (this.seconds <= this._times[2]) {
				if (this._count == 1) {
					this._runEffect("stay", 1);
					this._count = 2;
				}

				let value = (this.seconds - this._times[1]) / this.parts.out;
				this._runEffect("out", value);
			} else if (this._count < 3) {
				switch (this._count) {
					case 0: this._runEffect("in", 1); break;
					case 1: this._runEffect("stay", 1); break;
					case 2: this._runEffect("out", 1); break;
				}
				this._count = 3;
			}
		} else {
			this._runEffect("in", 0);

			if (this.seconds >= this.delay) {
				this.seconds = 0;
				this.started = true;
			}
		}
	}

	_runEffect(stage, value) {
		for (let effect of this.effects) {
			if (typeof effect[stage] == "function") effect[stage](value);
		}
	}

	start() {
		this.seconds = 0;
		this._times = [
			this.parts.open,
			this.parts.open + this.parts.stay,
			this.parts.open + this.parts.stay + this.parts.out
		];
		this._count = 0;
	}
}

import * as effects from "./effects";
import * as interpolation from "./interpolation.js";

export { effects };
export { interpolation };
<|endoftext|>


<commit_before>var keystone = require('../../'),
	_ = require('underscore'),
	async = require('async');

exports = module.exports = function(req, res) {

	var itemQuery = req.list.model.findById(req.params.item).select();

	itemQuery.exec(function(err, item) {

		if (!item) {
			req.flash('error', 'Item ' + req.params.item + ' could not be found.');
			return res.redirect('/keystone/' + req.list.path);
		}

		var viewLocals = {
			validationErrors: {}
		};

		var renderView = function() {

			var relationships = _.values(_.compact(_.map(req.list.relationships, function(i) {
				if (i.isValid) {
					return _.clone(i);
				} else {
					keystone.console.err('Relationship Configuration Error', 'Relationship: ' + i.path + ' on list: ' + req.list.key + ' links to an invalid list: ' + i.ref);
					return null;
				}
			})));

			var drilldown = {
				def: req.list.get('drilldown'),
				// data: {},
				items: []
			};

			var loadDrilldown = function(cb) {

				if (!drilldown.def) {
					return cb();
				}

				// step back through the drilldown list and load in reverse order to support nested relationships
				// TODO: proper support for nested relationships in drilldown
				drilldown.def = drilldown.def.split(' ').reverse();

				async.eachSeries(drilldown.def, function(path, done) {

					var field = req.list.fields[path];

					if (!field || field.type !== 'relationship') {
						throw new Error('Drilldown for ' + req.list.key + ' is invalid: field at path ' + path + ' is not a relationship.');
					}

					var refList = field.refList;

					if (field.many) {
						if (!item.get(field.path).length) {
							return done();
						}
						refList.model.find().where('_id').in(item.get(field.path)).limit(4).exec(function(err, results) {
							if (err || !results) {
								done(err);
							}
							var more = (results.length === 4) ? results.pop() : false;
							if (results.length) {
								// drilldown.data[path] = results;
								drilldown.items.push({
									list: refList.getOptions(),
									items: _.map(results, function(i) { return {
										label: refList.getDocumentName(i),
										href: '/keystone/' + refList.path + '/' + i.id
									};}),
									more: (more) ? true : false
								});
							}
							done();
						});
					} else {
						if (!item.get(field.path)) {
							return done();
						}
						refList.model.findById(item.get(field.path)).exec(function(err, result) {
							if (result) {
								// drilldown.data[path] = result;
								drilldown.items.push({
									list: refList.getOptions(),
									items: [{
										label: refList.getDocumentName(result),
										href: '/keystone/' + refList.path + '/' + result.id
									}]
								});
							}
							done();
						});
					}

				}, function(err) {
					// put the drilldown list back in the right order
					drilldown.def.reverse();
					drilldown.items.reverse();
					cb(err);
				});
			};

			var loadRelationships = function(cb) {

				async.each(relationships, function(rel, done) {

					// TODO: Handle invalid relationship config
					rel.list = keystone.list(rel.ref);
					rel.sortable = (rel.list.get('sortable') && rel.list.get('sortContext') === req.list.key + ':' + rel.path);

					// TODO: Handle relationships with more than 1 page of results
					var q = rel.list.paginate({ page: 1, perPage: 100 })
						.where(rel.refPath).equals(item.id)
						.sort(rel.list.defaultSort);

					// rel.columns = _.reject(rel.list.defaultColumns, function(col) { return (col.type == 'relationship' && col.refList == req.list) });
					rel.columns = rel.list.defaultColumns;
					rel.list.selectColumns(q, rel.columns);

					q.exec(function(err, results) {
						rel.items = results;
						done(err);
					});

				}, cb);
			};

			/** Render View */

			async.parallel([
				loadDrilldown,
				loadRelationships
			], function(err) {

				// TODO: Handle err

				var showRelationships = _.some(relationships, function(rel) {
					return rel.items.results.length;
				});

				var appName = keystone.get('name') || 'Keystone';

				keystone.render(req, res, 'item', _.extend(viewLocals, {
					section: keystone.nav.by.list[req.list.key] || {},
					title: appName + ': ' + req.list.singular + ': ' + req.list.getDocumentName(item),
					page: 'item',
					list: req.list,
					item: item,
					drilldown: drilldown,
					relationships: relationships,
					showRelationships: showRelationships
				}));

			});

		};

		if (req.method === 'POST' && req.body.action === 'updateItem' && !req.list.get('noedit')) {

			if (!keystone.security.csrf.validate(req)) {
				console.error('CSRF failure', req.method, req.body);
				req.flash('error', 'There was a problem with your request, please try again.');
				return renderView();
			}

			item.getUpdateHandler(req).process(req.body, { flashErrors: true, logErrors: true }, function(err) {
				if (err) {
					return renderView();
				}
				req.flash('success', 'Your changes have been saved.');
				return res.redirect('/keystone/' + req.list.path + '/' + item.id);
			});

		} else {
			renderView();
		}

	});

};
<commit_msg>Cleaning up functionality now handled by the API<commit_after>var keystone = require('../../'),
	_ = require('underscore'),
	async = require('async');

exports = module.exports = function(req, res) {

	var itemQuery = req.list.model.findById(req.params.item).select();

	itemQuery.exec(function(err, item) {

		if (!item) {
			req.flash('error', 'Item ' + req.params.item + ' could not be found.');
			return res.redirect('/keystone/' + req.list.path);
		}

		var renderView = function() {

			var relationships = _.values(_.compact(_.map(req.list.relationships, function(i) {
				if (i.isValid) {
					return _.clone(i);
				} else {
					keystone.console.err('Relationship Configuration Error', 'Relationship: ' + i.path + ' on list: ' + req.list.key + ' links to an invalid list: ' + i.ref);
					return null;
				}
			})));

			async.each(relationships, function(rel, done) {

				// TODO: Handle invalid relationship config
				rel.list = keystone.list(rel.ref);
				rel.sortable = (rel.list.get('sortable') && rel.list.get('sortContext') === req.list.key + ':' + rel.path);

				// TODO: Handle relationships with more than 1 page of results
				var q = rel.list.paginate({ page: 1, perPage: 100 })
					.where(rel.refPath).equals(item.id)
					.sort(rel.list.defaultSort);

				// rel.columns = _.reject(rel.list.defaultColumns, function(col) { return (col.type == 'relationship' && col.refList == req.list) });
				rel.columns = rel.list.defaultColumns;
				rel.list.selectColumns(q, rel.columns);

				q.exec(function(err, results) {
					rel.items = results;
					done(err);
				});

			}, function(err) {

				// TODO: Handle err

				var showRelationships = _.some(relationships, function(rel) {
					return rel.items.results.length;
				});

				var appName = keystone.get('name') || 'Keystone';

				keystone.render(req, res, 'item', {
					section: keystone.nav.by.list[req.list.key] || {},
					title: appName + ': ' + req.list.singular + ': ' + req.list.getDocumentName(item),
					page: 'item',
					list: req.list,
					item: item,
					relationships: relationships,
					showRelationships: showRelationships
				});

			});

		};

		if (req.method === 'POST' && req.body.action === 'updateItem' && !req.list.get('noedit')) {

			if (!keystone.security.csrf.validate(req)) {
				console.error('CSRF failure', req.method, req.body);
				req.flash('error', 'There was a problem with your request, please try again.');
				return renderView();
			}

			item.getUpdateHandler(req).process(req.body, { flashErrors: true, logErrors: true }, function(err) {
				if (err) {
					return renderView();
				}
				req.flash('success', 'Your changes have been saved.');
				return res.redirect('/keystone/' + req.list.path + '/' + item.id);
			});

		} else {
			renderView();
		}

	});

};
<|endoftext|>


<commit_before>var keystone = require('keystone'),
    async = require('async');

exports = module.exports = function(req, res) {

    var view = new keystone.View(req, res);
    var locals = res.locals;

    locals.filters = {
        post: req.params.post
    };
    locals.data = {
        categories: res.locals.categories,
        env: keystone.get('env'),
        isBlogType: true
    };

    // Load the current post
    view.on('init', function(next) {

        keystone.list('Post').model
            .findOne({
                state: 'published',
                slug: locals.filters.post
            })
            .populate('author categories')
            .exec(function(mainPostErr, mainPost) {

                if (mainPostErr) {
                    return next(mainPostErr);
                }

                if (! "key" in mainPost) {
                    return next(new Error("Post not found"));
                }

                locals.data.mainPost = mainPost;
                locals.section = (mainPost.isSoftwareRelated) ? 'code' : 'cogito';

                async.parallel(
                    [
                        //Get previous post
                        function(callback){
                            "use strict";

                            keystone.list('Post').model
                                .findOne({
                                    state: 'published',
                                    publishedDate: { $lt: mainPost.publishedDate }
                                })
                                .sort('-publishedDate')
                                .populate('author categories')
                                .exec(function(previousPostErr, previousPost) {
                                    if (previousPostErr) {
                                        return callback(previousPostErr);
                                    }
                                    callback(null, previousPost);
                                });
                        },
                        //Get next post
                        function(callback){
                            "use strict";

                            keystone.list('Post').model
                                .findOne({
                                    state: 'published',
                                    publishedDate: { $gt: mainPost.publishedDate }
                                })
                                .sort('-publishedDate')
                                .populate('author categories')
                                .exec(function(nextPostErr, nextPost) {
                                    if (nextPostErr) {
                                        return callback(nextPostErr);
                                    }
                                    callback(null, nextPost);
                                });
                        },
                        //Get related post
                        function(callback){
                            "use strict";

                            keystone.list('Post').model
                                .find(
                                    { $text : { $search : mainPost.searchRelated } },
                                    { score : { $meta : "textScore" } }
                                )
                                .sort({ score : { $meta : 'textScore' } })
                                .populate('author categories')
                                .limit(5)
                                .exec(function(relatedPostErr, relatedPosts) {

                                    if (relatedPostErr) {
                                        return callback(relatedPostErr);
                                    }

                                    //The first el is often the same as searched
                                    relatedPosts.shift();
                                    callback(null, relatedPosts);
                                });
                        },
                    ],
                    function(parallelError, results) {

                        if (parallelError) {
                            return next(parallelError);
                        }

                        locals.data.previousPost = results[0];
                        locals.data.nextPost     = results[1];
                        locals.data.relatedposts = results[2];
                        next();
                    }
                );
            });
    });

    view.render('post');
};
<commit_msg>[master] Naive bug fix for related post with less or more than 3 items<commit_after>var keystone = require('keystone'),
    async = require('async');

exports = module.exports = function(req, res) {

    var view = new keystone.View(req, res);
    var locals = res.locals;

    locals.filters = {
        post: req.params.post
    };
    locals.data = {
        categories: res.locals.categories,
        env: keystone.get('env'),
        isBlogType: true
    };

    // Load the current post
    view.on('init', function(next) {

        keystone.list('Post').model
            .findOne({
                state: 'published',
                slug: locals.filters.post
            })
            .populate('author categories')
            .exec(function(mainPostErr, mainPost) {

                if (mainPostErr) {
                    return next(mainPostErr);
                }

                if (! "key" in mainPost) {
                    return next(new Error("Post not found"));
                }

                locals.data.mainPost = mainPost;
                locals.section = (mainPost.isSoftwareRelated) ? 'code' : 'cogito';

                async.parallel(
                    [
                        //Get previous post
                        function(callback){
                            "use strict";

                            keystone.list('Post').model
                                .findOne({
                                    state: 'published',
                                    publishedDate: { $lt: mainPost.publishedDate }
                                })
                                .sort('-publishedDate')
                                .populate('author categories')
                                .exec(function(previousPostErr, previousPost) {
                                    if (previousPostErr) {
                                        return callback(previousPostErr);
                                    }
                                    callback(null, previousPost);
                                });
                        },
                        //Get next post
                        function(callback){
                            "use strict";

                            keystone.list('Post').model
                                .findOne({
                                    state: 'published',
                                    publishedDate: { $gt: mainPost.publishedDate }
                                })
                                .sort('-publishedDate')
                                .populate('author categories')
                                .exec(function(nextPostErr, nextPost) {
                                    if (nextPostErr) {
                                        return callback(nextPostErr);
                                    }
                                    callback(null, nextPost);
                                });
                        },
                        //Get related post
                        function(callback){
                            "use strict";

                            keystone.list('Post').model
                                .find(
                                    { $text : { $search : mainPost.searchRelated } },
                                    { score : { $meta : "textScore" } }
                                )
                                .sort({ score : { $meta : 'textScore' } })
                                .populate('author categories')
                                .limit(5)
                                .exec(function(relatedPostErr, relatedPosts) {

                                    if (relatedPostErr) {
                                        return callback(relatedPostErr);
                                    }

                                    //The first el is often the same as searched
                                    var firstRelated = relatedPosts.shift();

                                    //Too much result
                                    if (relatedPosts.length > 3) {
                                        relatedPosts = relatedPosts.slice(0, 3);
                                    } else if (relatedPosts.length >= 2) {
                                        relatedPosts.push(firstRelated);
                                    }

                                    callback(null, relatedPosts);
                                });
                        },
                    ],
                    function(parallelError, results) {

                        if (parallelError) {
                            return next(parallelError);
                        }

                        locals.data.previousPost = results[0];
                        locals.data.nextPost     = results[1];
                        locals.data.relatedposts = results[2];
                        next();
                    }
                );
            });
    });

    view.render('post');
};
<|endoftext|>


<commit_before>var storageKeys = [
	"server",
	"type",
	"username",
	"password"
];
var app = angular.module("BugApp", []);

app.controller("SetupController", SetupController);

app.controller("BugController", BugController);

app.run(onModuleRun);

app.factory("storage", function(){
	var cache;
	return {
		get: getStorage,
		set: setStorage,
		clear: clearStorage
	};

	function getStorage(keys){
		if(cache) {
			return Promise.resolve(cache);
		}
		return new Promise(function(resolve, reject){
			chrome.storage.local.get(keys || storageKeys, function(data){
				cache = data;
				data ? resolve(data) : reject();
			});
		});
	}

	function setStorage(data){
		return new Promise(function(resolve, reject){
			cache = null;
			chrome.storage.local.set(data, function(e){
				e ? reject(e) : resolve();
			});
		});
	}

	function clearStorage(){
		return new Promise(function(resolve, reject){
			chrome.storage.local.clear(function(err){
				err ? reject(err) : resolve();
			});
		});
	}
});

app.factory("isSetuped", function(){
	return function(data){
		var valid = true;
		angular.forEach(storageKeys, function(key){
			if(!data.hasOwnProperty(key)) {
				valid = false;
			}
		});
		return valid;
	};
});

function SetupController($scope, storage, $rootScope){
	var defaults = {
		server: "172.16.203.11:8011",
		type: "bugfree"
	};

	// 异步操作，完成后手动 .$digest()
	storage.get().then(function(data){
		if(data) {
			angular.extend($scope, defaults, data);
		}
		$scope.$digest();
	}, function(e){
		$scope.error = e.message;
		$scope.$digest();
	});

	$scope.saveSetup = function(){
		var form = $scope.setupForm;
		var values = {};
		if(form.$invalid) {
			angular.forEach(form.$error, function(ctrl){
				ctrl.$setViewValue("");
			});
			return;
		}
		angular.forEach(storageKeys, function(key){
			values[key] = $scope[key];
		});
		values.server = "http://" + values.server;

		storage.set(values).then(function(){
			chrome.runtime.sendMessage({cmd: "test-ready"}, function(){
				$scope.loading = false;
				$rootScope.$apply(function(scope){
					scope.page = "buglist";
				});
			});
		}).catch(function(e){
			$scope.$apply(function(scope){
				scope.error = e.message;
			});
		});
		$scope.loading = true;
	};

	$scope.onKeydown = function(e){
		if(e.keyCode === 13 && $scope.setupForm.$valid) {
			this.saveSetup();
		}
	};

	$scope.$on("error", function(e_, e){
		$scope.error = e.message
	});
}

SetupController.$inject = ["$scope", "storage", "$rootScope"];

function BugController($scope, $interval, storage){
	$scope.ignoreLocalFix = false;
	$scope.bugs = [];
	$scope.columns = [
		"ID", "Bug标题", "修改日期", "模块路径", "严重程度", "优先级",
		"创建者", "指派者", "解决者", "解决方案", "处理状态", "附件", "复现步骤"
	];

	getBugList();
	getBugError();

	$scope.openBug = function(id){
		chrome.runtime.sendMessage({cmd: "open-bug", id: id});
	};

	$scope.openBugfree = function(){
		chrome.runtime.sendMessage({cmd: "open-bugfree"});
	};

	$scope.reloadExtension = function(){
		chrome.runtime.sendMessage({cmd: "reload"});
	};

	$scope.setBugIndex = function(index){
		var bug;
		$scope.bugIndex = index;
		$scope.bugs.forEach(function(b){
			if(b.ID === index) {
				bug = b;
			}
		});
		// 已经获取过详细信息了
		if(bug.hasOwnProperty("模块路径")) {
			return;
		}
		chrome.runtime.sendMessage({
			cmd: "bug-detail",
			id: index
		}, function(data){
			if(!data || data instanceof Error) {
				return;
			}
			angular.extend(bug, data);
		});
	};

	$scope.isSpectialColumn = function(name){
		return ["ID", "附件", "复现步骤"].indexOf(name) > -1;
	};

	$scope.toggleLocalFix = function(v){
		var bugs = $scope.originalBugs || $scope.bugs;
		var filteredBugs = bugs.filter(function(bug){
			var isfix = bug["处理状态"] === "Local Fix";
			return isfix !== v;
		});
		$scope.originalBugs = bugs;
		$scope.bugs = filteredBugs;
		if($scope.originalBugs.length === $scope.bugs.length) {
			delete $scope.originalBugs;
		}
	};

	$scope.isLocalFix = function(bug) {
		return bug["处理状态"] === "Local Fix";
	};

	$scope.resetStorage = function(){
		storage.clear().then(function(){
			chrome.runtime.sendMessage({cmd: "reload"});
		});
	};

	function getBugList(){
		chrome.runtime.sendMessage({cmd: "get-bug-list"}, function(bugs){
			$scope.bugs = bugs;
			if($scope.hasOwnProperty("bugIndex")) {
				var exsits = false;
				bugs.forEach(function(bug){
					if(bug.ID === $scope.bugIndex) {
						exsits = true;
					}
				});
				if(!exsits && bugs.length > 0) {
					$scope.setBugIndex(bugs[0].ID);
				}
			} else {
				if(bugs.length > 0) {
					$scope.setBugIndex(bugs[0].ID);
				}
			}
			$scope.$digest();
		});
	}
	function getBugError(){
		chrome.runtime.sendMessage({cmd: "get-bug-error"}, function(err){
			$scope.bugError = err;
			$scope.$digest();
		});
	}
}

BugController.$inject = ["$scope", "$interval", "storage"];

function onModuleRun($rootScope, storage, isSetuped){
	// 根据是否有存储的数据来判断显示哪个界面
	storage.get().then(function(data){
		$rootScope.$apply(function(scope){
			scope.page = isSetuped(data) ? "buglist" : "setup";
		});
	}).catch(function(err){
		console.error("unexpected error", err);
	});
	// 汇报页面报错信息
	window.addEventListener("error", function(e){
		$rootScope.$broadcast("error", e);
	});
}

onModuleRun.$inject = ["$rootScope", "storage", "isSetuped"];<commit_msg>popup 交互逻辑优化<commit_after>var storageKeys = [
	"server",
	"type",
	"username",
	"password"
];
var app = angular.module("BugApp", []);

app.controller("SetupController", SetupController);

app.controller("BugController", BugController);

app.run(onModuleRun);

app.factory("storage", function(){
	var cache;
	return {
		get: getStorage,
		set: setStorage,
		clear: clearStorage
	};

	function getStorage(keys){
		if(cache) {
			return Promise.resolve(cache);
		}
		return new Promise(function(resolve, reject){
			chrome.storage.local.get(keys || storageKeys, function(data){
				cache = data;
				data ? resolve(data) : reject();
			});
		});
	}

	function setStorage(data){
		return new Promise(function(resolve, reject){
			cache = null;
			chrome.storage.local.set(data, function(e){
				e ? reject(e) : resolve();
			});
		});
	}

	function clearStorage(){
		return new Promise(function(resolve, reject){
			chrome.storage.local.clear(function(err){
				err ? reject(err) : resolve();
			});
		});
	}
});

app.factory("isSetuped", function(){
	return function(data){
		var valid = true;
		angular.forEach(storageKeys, function(key){
			if(!data.hasOwnProperty(key)) {
				valid = false;
			}
		});
		return valid;
	};
});

function SetupController($scope, storage, $rootScope){
	var defaults = {
		server: "172.16.203.11:8011",
		type: "bugfree"
	};

	// 异步操作，完成后刷新 scope
	storage.get().then(function(data){
		if(data) {
			angular.extend($scope, defaults, data);
		}
		$scope.$apply();
	}, function(e){
		$scope.error = e.message;
		$scope.$apply();
	});

	$scope.saveSetup = function(){
		var form = $scope.setupForm;
		var values = {};
		if(form.$invalid) {
			angular.forEach(form.$error, function(ctrl){
				ctrl.$setViewValue("");
			});
			return;
		}
		angular.forEach(storageKeys, function(key){
			values[key] = $scope[key];
		});
		values.server = "http://" + values.server;

		storage.set(values).then(function(){
			chrome.runtime.sendMessage({cmd: "test-ready"}, function(){
				$scope.loading = false;
				$rootScope.$apply(function(scope){
					scope.page = "buglist";
				});
			});
		}).catch(function(e){
			$scope.$apply(function(scope){
				scope.error = e.message;
			});
		});
		$scope.loading = true;
	};

	$scope.onKeydown = function(e){
		if(e.keyCode === 13 && $scope.setupForm.$valid) {
			this.saveSetup();
		}
	};

	$scope.$on("error", function(e_, e){
		$scope.error = e.message
	});
}

SetupController.$inject = ["$scope", "storage", "$rootScope"];

function BugController($scope, $timeout, storage){
	$scope.ignoreLocalFix = false;
	$scope.bugs = [];
	$scope.columns = [
		"ID", "Bug标题", "修改日期", "模块路径", "严重程度", "优先级",
		"创建者", "指派者", "解决者", "解决方案", "处理状态", "附件", "复现步骤"
	];

	$scope.openBug = function(id){
		chrome.runtime.sendMessage({cmd: "open-bug", id: id});
	};

	$scope.openBugfree = function(){
		chrome.runtime.sendMessage({cmd: "open-bugfree"});
	};

	$scope.reloadExtension = function(){
		chrome.runtime.sendMessage({cmd: "reload"});
	};

	$scope.setBugIndex = function(index){
		var bug;
		$scope.bugIndex = index;
		$scope.bugs.forEach(function(b){
			if(b.ID === index) {
				bug = b;
			}
		});
		// 已经获取过详细信息了
		if(bug.hasOwnProperty("模块路径")) {
			return;
		}
		chrome.runtime.sendMessage({
			cmd: "bug-detail",
			id: index
		}, function(data){
			if(!data || data instanceof Error) {
				return;
			}
			angular.extend(bug, data);
			$scope.$apply();
		});
	};

	$scope.isSpectialColumn = function(name){
		return ["ID", "附件", "复现步骤"].indexOf(name) > -1;
	};

	$scope.toggleLocalFix = function(v){
		var bugs = $scope.originalBugs || $scope.bugs;
		var filteredBugs = bugs.filter(function(bug){
			var isfix = bug["处理状态"] === "Local Fix";
			return isfix !== v;
		});
		$scope.originalBugs = bugs;
		$scope.bugs = filteredBugs;
		if($scope.originalBugs.length === $scope.bugs.length) {
			delete $scope.originalBugs;
		}
	};

	$scope.isLocalFix = function(bug) {
		return bug["处理状态"] === "Local Fix";
	};

	$scope.resetStorage = function(){
		storage.clear().then(function(){
			chrome.runtime.sendMessage({cmd: "reload"});
		});
	};

	loop();

	function loop() {
		getBugList();
		getBugError();
		$timeout(loop, 2000);
	}

	function getBugList(){
		chrome.runtime.sendMessage({cmd: "get-bug-list"}, function(bugs){
			var bugMap = {};
			var newBugs = [];
			angular.forEach($scope.bugs, function(bug){
				// 标记 bug 为不存在，合并新 bug 数据后删除此标记
				bug.exsits = false;
				bugMap[bug.ID] = bug;
			});
			angular.forEach(bugs, function(bug){
				if(bugMap.hasOwnProperty(bug.ID)) {
					bug.exsits = true;
					angular.extend(bugMap[bug.ID], bug);
				} else {
					newBugs.push(bug);
				}
			});
			$scope.bugs = $scope.bugs.filter(function(bug){
				var exsits = bug.exsits;
				delete bug.exsits;
				return exsits;
			}).concat(newBugs);
			// 自动显示第一个 bug
			if(!$scope.hasOwnProperty("bugIndex") && $scope.bugs.length > 0) {
				$scope.setBugIndex($scope.bugs[0].ID);
			}
			$scope.$apply();
		});
	}
	function getBugError(){
		chrome.runtime.sendMessage({cmd: "get-bug-error"}, function(err){
			$scope.bugError = err;
			$scope.$apply();
		});
	}
}

BugController.$inject = ["$scope", "$timeout", "storage"];

function onModuleRun($rootScope, storage, isSetuped){
	// 根据是否有存储的数据来判断显示哪个界面
	storage.get().then(function(data){
		$rootScope.$apply(function(scope){
			scope.page = isSetuped(data) ? "buglist" : "setup";
		});
	}).catch(function(err){
		console.error("unexpected error", err);
	});
	// 汇报页面报错信息
	window.addEventListener("error", function(e){
		$rootScope.$broadcast("error", e);
	});
}

onModuleRun.$inject = ["$rootScope", "storage", "isSetuped"];<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
'use strict';

var logDisabled_ = false;

// Utility methods.
var utils = {
  disableLog: function(bool) {
    if (typeof bool !== 'boolean') {
      return new Error('Argument type: ' + typeof bool +
          '. Please use a boolean.');
    }
    logDisabled_ = bool;
    return (bool) ? 'adapter.js logging disabled' :
        'adapter.js logging enabled';
  },

  log: function() {
    if (typeof window === 'object') {
      if (logDisabled_) {
        return;
      }
      console.log.apply(console, arguments);
    }
  },

  /**
   * Extract browser version out of the provided user agent string.
   *
   * @param {!string} uastring userAgent string.
   * @param {!string} expr Regular expression used as match criteria.
   * @param {!number} pos position in the version string to be returned.
   * @return {!number} browser version.
   */
  extractVersion: function(uastring, expr, pos) {
    var match = uastring.match(expr);
    return match && match.length >= pos && parseInt(match[pos], 10);
  },

  /**
   * Browser detector.
   *
   * @return {object} result containing browser, version and minVersion
   *     properties.
   */
  detectBrowser: function() {
    // Returned result object.
    var result = {};
    result.browser = null;
    result.version = null;
    result.minVersion = null;

    // Fail early if it's not a browser
    if (typeof window === 'undefined' || !window.navigator) {
      result.browser = 'Not a browser.';
      return result;
    }

    // Firefox.
    if (navigator.mozGetUserMedia) {
      result.browser = 'firefox';
      result.version = this.extractVersion(navigator.userAgent,
          /Firefox\/([0-9]+)\./, 1);
      result.minVersion = 31;

    // all webkit-based browsers
    } else if (navigator.webkitGetUserMedia && window.webkitRTCPeerConnection) {

      // Chrome, Chromium, Webview, Opera, all use the chrome shim for nowa
      if (navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)) {
        result.browser = 'chrome';
        result.version = this.extractVersion(navigator.userAgent,
          /Chrom(e|ium)\/([0-9]+)\./, 2);
        result.minVersion = 38;

      // Safari uses its own shim.
      //
      // Safari UA substrings of interesti for reference:
      // - webkit version:            AppleWebKit/602.1.25 (also used in Cr)
      // - safari commercial version: Version/9.0.3
      // - safari webkit version:     Safari/601.4.4 (also used in Cr)
      // if the safari webkit version and webkit versions are different,
      // ... this is a nightly version.
      } else if (navigator.userAgent.match(/Safari\//) {
        result.browser = 'safari';
        result.version = this.extractVersion(navigator.userAgent,
          /AppleWebKit\/([0-9]+)\./, 1);
        result.minVersion = 602;

      // unknown webkit-based browser
      } else {
        result.browser = 'Unsupported webkit-based browser.';
        return result;
      }

      // Edge.
    } else if (navigator.mediaDevices &&
        navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
      result.browser = 'edge';
      result.version = this.extractVersion(navigator.userAgent,
          /Edge\/(\d+).(\d+)$/, 2);
      result.minVersion = 10547;

    } else {
      // Default fallthrough: not supported.
      result.browser = 'Not a supported browser.';
      return result;
    }

    // Warn if version is less than minVersion.
    if (result.version < result.minVersion) {
      utils.log('Browser: ' + result.browser + ' Version: ' + result.version +
          ' < minimum supported version: ' + result.minVersion +
          '\n some things might not work!');
    }

    return result;
  }
};

// Export.
module.exports = {
  log: utils.log,
  disableLog: utils.disableLog,
  browserDetails: utils.detectBrowser(),
  extractVersion: utils.extractVersion
};
<commit_msg>BUG: missing ending parenthesis.<commit_after>/*
 *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */
'use strict';

var logDisabled_ = false;

// Utility methods.
var utils = {
  disableLog: function(bool) {
    if (typeof bool !== 'boolean') {
      return new Error('Argument type: ' + typeof bool +
          '. Please use a boolean.');
    }
    logDisabled_ = bool;
    return (bool) ? 'adapter.js logging disabled' :
        'adapter.js logging enabled';
  },

  log: function() {
    if (typeof window === 'object') {
      if (logDisabled_) {
        return;
      }
      console.log.apply(console, arguments);
    }
  },

  /**
   * Extract browser version out of the provided user agent string.
   *
   * @param {!string} uastring userAgent string.
   * @param {!string} expr Regular expression used as match criteria.
   * @param {!number} pos position in the version string to be returned.
   * @return {!number} browser version.
   */
  extractVersion: function(uastring, expr, pos) {
    var match = uastring.match(expr);
    return match && match.length >= pos && parseInt(match[pos], 10);
  },

  /**
   * Browser detector.
   *
   * @return {object} result containing browser, version and minVersion
   *     properties.
   */
  detectBrowser: function() {
    // Returned result object.
    var result = {};
    result.browser = null;
    result.version = null;
    result.minVersion = null;

    // Fail early if it's not a browser
    if (typeof window === 'undefined' || !window.navigator) {
      result.browser = 'Not a browser.';
      return result;
    }

    // Firefox.
    if (navigator.mozGetUserMedia) {
      result.browser = 'firefox';
      result.version = this.extractVersion(navigator.userAgent,
          /Firefox\/([0-9]+)\./, 1);
      result.minVersion = 31;

    // all webkit-based browsers
    } else if (navigator.webkitGetUserMedia && window.webkitRTCPeerConnection) {

      // Chrome, Chromium, Webview, Opera, all use the chrome shim for nowa
      if (navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)) {
        result.browser = 'chrome';
        result.version = this.extractVersion(navigator.userAgent,
          /Chrom(e|ium)\/([0-9]+)\./, 2);
        result.minVersion = 38;

      // Safari uses its own shim.
      //
      // Safari UA substrings of interesti for reference:
      // - webkit version:            AppleWebKit/602.1.25 (also used in Cr)
      // - safari commercial version: Version/9.0.3
      // - safari webkit version:     Safari/601.4.4 (also used in Cr)
      // if the safari webkit version and webkit versions are different,
      // ... this is a nightly version.
      } else if (navigator.userAgent.match(/Safari\//)) {
        result.browser = 'safari';
        result.version = this.extractVersion(navigator.userAgent,
          /AppleWebKit\/([0-9]+)\./, 1);
        result.minVersion = 602;

      // unknown webkit-based browser
      } else {
        result.browser = 'Unsupported webkit-based browser.';
        return result;
      }

      // Edge.
    } else if (navigator.mediaDevices &&
        navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
      result.browser = 'edge';
      result.version = this.extractVersion(navigator.userAgent,
          /Edge\/(\d+).(\d+)$/, 2);
      result.minVersion = 10547;

    } else {
      // Default fallthrough: not supported.
      result.browser = 'Not a supported browser.';
      return result;
    }

    // Warn if version is less than minVersion.
    if (result.version < result.minVersion) {
      utils.log('Browser: ' + result.browser + ' Version: ' + result.version +
          ' < minimum supported version: ' + result.minVersion +
          '\n some things might not work!');
    }

    return result;
  }
};

// Export.
module.exports = {
  log: utils.log,
  disableLog: utils.disableLog,
  browserDetails: utils.detectBrowser(),
  extractVersion: utils.extractVersion
};
<|endoftext|>


<commit_before>module.exports = {
    'jsx-a11y/accessible-emoji': 'error',
    'jsx-a11y/alt-text': 'error',
    'jsx-a11y/anchor-has-content': 'error',
    'jsx-a11y/anchor-is-valid': 'error',
    'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
    'jsx-a11y/aria-props': 'error',
    'jsx-a11y/aria-proptypes': 'error',
    'jsx-a11y/aria-role': 'error',
    'jsx-a11y/aria-unsupported-elements': 'error',
    'jsx-a11y/click-events-have-key-events': 'error',
    'jsx-a11y/control-has-associated-label': 'error',
    'jsx-a11y/heading-has-content': 'error',
    'jsx-a11y/html-has-lang': 'error',
    'jsx-a11y/iframe-has-title': 'error',
    'jsx-a11y/img-redundant-alt': 'error',
    'jsx-a11y/interactive-supports-focus': 'error',
    'jsx-a11y/lang': 'error',
    'jsx-a11y/media-has-caption': 'error',
    'jsx-a11y/mouse-events-have-key-events': 'error',
    'jsx-a11y/no-access-key': 'error',
    'jsx-a11y/no-distracting-elements': 'error',
    'jsx-a11y/no-interactive-element-to-noninteractive-role': 'error',
    'jsx-a11y/no-noninteractive-element-to-interactive-role': 'error',
    'jsx-a11y/no-noninteractive-tabindex': 'error',
    'jsx-a11y/no-redundant-roles': 'error',
    'jsx-a11y/no-static-element-interactions': 'error',
    'jsx-a11y/role-has-required-aria-props': 'error',
    'jsx-a11y/role-supports-aria-props': 'error',
    'jsx-a11y/scope': 'error',
    'jsx-a11y/tabindex-no-positive': 'error'
};
<commit_msg>Removes `jsx-a11y/control-has-associated-label`.<commit_after>module.exports = {
    'jsx-a11y/accessible-emoji': 'error',
    'jsx-a11y/alt-text': 'error',
    'jsx-a11y/anchor-has-content': 'error',
    'jsx-a11y/anchor-is-valid': 'error',
    'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
    'jsx-a11y/aria-props': 'error',
    'jsx-a11y/aria-proptypes': 'error',
    'jsx-a11y/aria-role': 'error',
    'jsx-a11y/aria-unsupported-elements': 'error',
    'jsx-a11y/click-events-have-key-events': 'error',
    'jsx-a11y/heading-has-content': 'error',
    'jsx-a11y/html-has-lang': 'error',
    'jsx-a11y/iframe-has-title': 'error',
    'jsx-a11y/img-redundant-alt': 'error',
    'jsx-a11y/interactive-supports-focus': 'error',
    'jsx-a11y/lang': 'error',
    'jsx-a11y/media-has-caption': 'error',
    'jsx-a11y/mouse-events-have-key-events': 'error',
    'jsx-a11y/no-access-key': 'error',
    'jsx-a11y/no-distracting-elements': 'error',
    'jsx-a11y/no-interactive-element-to-noninteractive-role': 'error',
    'jsx-a11y/no-noninteractive-element-to-interactive-role': 'error',
    'jsx-a11y/no-noninteractive-tabindex': 'error',
    'jsx-a11y/no-redundant-roles': 'error',
    'jsx-a11y/no-static-element-interactions': 'error',
    'jsx-a11y/role-has-required-aria-props': 'error',
    'jsx-a11y/role-supports-aria-props': 'error',
    'jsx-a11y/scope': 'error',
    'jsx-a11y/tabindex-no-positive': 'error'
};
<|endoftext|>


<commit_before>import * as actions from './actions'
import React, { Component } from 'react';
import { connect } from 'react-redux'
import Mousetrap from 'mousetrap'

@connect(state => ({
  query: state.get('query'),
}))
class Keyboard extends Component {
  componentDidMount() {
    Mousetrap.bind('s', this.showQueryBox)
    Mousetrap.bind('n', this.nextPage)
    Mousetrap.bind('p', this.prevPage)
  }

  componentWillUnmount() {
    Mousetrap.unbind(['s', 'n', 'p'])
  }

  showQueryBox = (e) => {
    e.preventDefault()
    this.props.store.dispatch(actions.showQueryBox())
  };

  nextPage = (e) => {
    e.preventDefault()
    this.props.store.dispatch(actions.nextPage())
  };

  prevPage = (e) => {
    e.preventDefault()
    this.props.store.dispatch(actions.prevPage())
  };

  render() {
    return this.props.children
  }
}

export default Keyboard
<commit_msg>do not capture keys when in the popup<commit_after>import * as actions from './actions'
import React, { Component } from 'react';
import { connect } from 'react-redux'
import Mousetrap from 'mousetrap'

@connect(state => ({
  query: state.get('query'),
  showingQueryBox: state.get('showingQueryBox'),
}))
class Keyboard extends Component {
  componentDidMount() {
    Mousetrap.bind('s', this.showQueryBox)
    Mousetrap.bind('n', this.nextPage)
    Mousetrap.bind('p', this.prevPage)
  }

  componentWillUnmount() {
    Mousetrap.unbind(['s', 'n', 'p'])
  }

  showQueryBox = (e) => {
    if (!this.props.showingQueryBox) {
      e.preventDefault()
      this.props.store.dispatch(actions.showQueryBox())
    }
  };

  nextPage = (e) => {
    if (!this.props.showingQueryBox) {
      e.preventDefault()
      this.props.store.dispatch(actions.nextPage())
    }
  };

  prevPage = (e) => {
    if (!this.props.showingQueryBox) {
      e.preventDefault()
      this.props.store.dispatch(actions.prevPage())
    }
  };

  render() {
    return this.props.children
  }
}

export default Keyboard
<|endoftext|>


<commit_before>module.exports = {
  'clear-filter': 'Clear filter',
  'matched-message': '{count} results for entries matching {keyword}',
  'search-entries': 'Search entries...',
  'about': 'About',
  'add-a-folder': 'Add a folder',
  'add-entry': 'Add Entry',
  'add-folder': 'Add Folder',
  'app-language': 'App Language',
  'back': 'Back',
  'bo': 'Tibetan',
  'cancel': 'Cancel',
  'category': 'Category',
  'category-1': 'People',
  'category-2': 'Repect',
  'category-3': 'Temple',
  'category-4': 'Ground',
  'category-5': 'Sutra',
  'category-6': 'Thing',
  'category-7': 'Amount',
  'category-8': 'Sentence',
  'choose-at-least-one-content-field': 'Please choose at least one content field.',
  'choose-at-least-one-target-language': 'Please choose at least one target language.',
  'choose-csv-file': 'Choose CSV file',
  'completed-csv-line': 'Completed {completedLine} lines',
  'confirm': 'Confirm',
  'content-fields': 'Content Fields',
  'csv-imported-done': '{filename} has been imported',
  'delete': 'delete',
  'delete-folder-instruction': 'Input {folderName} to delete this folder, once you delete a repository, there is no going back. Please be certain.',
  'done': 'Done',
  'edit': 'Edit',
  'edit-folder': 'Edit Folder',
  'edit-folder-entry': 'Edit {sourceEntry}',
  'en': 'English',
  'explaination': 'Explaintion',
  'explaination-category-1': 'Character',
  'explaination-category-10': 'Term',
  'explaination-category-11': 'Sanskrit',
  'explaination-category-12': 'Chinese',
  'explaination-category-13': 'Mongolian',
  'explaination-category-2': 'Gods',
  'explaination-category-3': 'Temple',
  'explaination-category-4': 'Location',
  'explaination-category-5': 'Classic',
  'explaination-category-6': 'Item',
  'explaination-category-7': 'Law',
  'explaination-category-8': 'Sentence',
  'explaination-category-9': 'Language',
  'explaination-category-num': 'Explaination Category {num}',
  'explaination-lang': 'Explaination - {lang}',
  'explaination-note': 'Explaination Note',
  'explaination-note-num': 'Explaination Note {num}',
  'explaination-num-lang': 'Explaination {num} - {lang}',
  'explaination-source-num': 'Explaination Source {num}',
  'export': 'Export',
  'field-source-language-required': 'Field source language is required.',
  'folder-entries': '{folderName} 的詞條',
  'folder-entries-has-been-deleted': 'Deleted {count} entries.',
  'folder-entry-has-been-created': 'Entry {sourceEntry} has been created.',
  'folder-entry-has-been-updated': 'Entry {sourceEntry} has been updated.',
  'folder-entry-name-required': 'Entry field is required.',
  'folder-entry-name-taken': 'Entry already existed in this folder.',
  'folder-has-been-created': 'Folder {folderName} has been created.',
  'folder-has-been-deleted': 'Folder {folderName} has been deleted.',
  'folder-has-been-updated': 'Folder {folderName} has been updated.',
  'folder-name': 'Folder Name',
  'folder-name-required': 'Field folder name is required.',
  'folder-name-taken': 'Folder name {folderName} exists',
  'folders': 'Folders',
  'garchen': 'Garchen',
  'home': 'Home',
  'import-csv-file': 'Import CSV file',
  'import-csv-rule-1': '1. Supported language codes are {supportedLangs} in this version, also known as {langExpression}',
  'import-csv-rule-2': '2. {langExpression} means the language code that supposed to be matched. For example, the column name of Source Entry is `source-entry-{langExpression}`.  It becomes source-entry-bo when Tibetan language code is applied.',
  'import-csv-rule-3': '3. Supported column names are {supportedColumnNames}.',
  'import-csv-rule-4': '4. First row should have column definition and MUST have source-entry-[lang], Please refer to our example file ',
  'import-csv-rule-5': '5. Please increase the write delay in settings page if you experience any slow responses while importing.',
  'login': 'Login',
  'next-page': 'Next',
  'no-column-row-detected': '在 {errorFilename} 偵測不到欄位資訊',
  'original-lang': 'Original - {lang}',
  'page-num': 'Page Number',
  'please-input-exact-the-same-folder-name': 'Please input {folderName}',
  'prev-page': 'Prev',
  'sect': 'Sect',
  'sect-1': 'Old',
  'sect-2': 'When',
  'sect-3': 'Sa',
  'sect-4': 'Karma',
  'sect-5': 'Fragant',
  'sect-6': 'Time',
  'sect-7': 'Off',
  'sect-8': 'According',
  'see-imported-folder': 'See imported folder',
  'settings': 'Settings',
  'source': 'Source',
  'source-entry': 'Source Entry',
  'source-entry-lang': 'Source Entry - {lang}',
  'source-lang': 'Source - {lang}',
  'source-language': 'Source Language',
  'submit': 'Submit',
  'target-entry-lang': 'Entry - {lang}',
  'target-language': 'Target Language',
  'update': 'Update',
  'write-delay-with-num': 'Write delay {writeDelay}ms',
  'zh-CN': 'Simplified Chinese',
  'zh-TW': 'Traditial Chinese'
};
<commit_msg>fix typo - completedLines<commit_after>module.exports = {
  'clear-filter': 'Clear filter',
  'matched-message': '{count} results for entries matching {keyword}',
  'search-entries': 'Search entries...',
  'about': 'About',
  'add-a-folder': 'Add a folder',
  'add-entry': 'Add Entry',
  'add-folder': 'Add Folder',
  'app-language': 'App Language',
  'back': 'Back',
  'bo': 'Tibetan',
  'cancel': 'Cancel',
  'category': 'Category',
  'category-1': 'People',
  'category-2': 'Repect',
  'category-3': 'Temple',
  'category-4': 'Ground',
  'category-5': 'Sutra',
  'category-6': 'Thing',
  'category-7': 'Amount',
  'category-8': 'Sentence',
  'choose-at-least-one-content-field': 'Please choose at least one content field.',
  'choose-at-least-one-target-language': 'Please choose at least one target language.',
  'choose-csv-file': 'Choose CSV file',
  'completed-csv-line': 'Completed {completedLines} lines',
  'confirm': 'Confirm',
  'content-fields': 'Content Fields',
  'csv-imported-done': '{filename} has been imported',
  'delete': 'delete',
  'delete-folder-instruction': 'Input {folderName} to delete this folder, once you delete a repository, there is no going back. Please be certain.',
  'done': 'Done',
  'edit': 'Edit',
  'edit-folder': 'Edit Folder',
  'edit-folder-entry': 'Edit {sourceEntry}',
  'en': 'English',
  'explaination': 'Explaintion',
  'explaination-category-1': 'Character',
  'explaination-category-10': 'Term',
  'explaination-category-11': 'Sanskrit',
  'explaination-category-12': 'Chinese',
  'explaination-category-13': 'Mongolian',
  'explaination-category-2': 'Gods',
  'explaination-category-3': 'Temple',
  'explaination-category-4': 'Location',
  'explaination-category-5': 'Classic',
  'explaination-category-6': 'Item',
  'explaination-category-7': 'Law',
  'explaination-category-8': 'Sentence',
  'explaination-category-9': 'Language',
  'explaination-category-num': 'Explaination Category {num}',
  'explaination-lang': 'Explaination - {lang}',
  'explaination-note': 'Explaination Note',
  'explaination-note-num': 'Explaination Note {num}',
  'explaination-num-lang': 'Explaination {num} - {lang}',
  'explaination-source-num': 'Explaination Source {num}',
  'export': 'Export',
  'field-source-language-required': 'Field source language is required.',
  'folder-entries': '{folderName} 的詞條',
  'folder-entries-has-been-deleted': 'Deleted {count} entries.',
  'folder-entry-has-been-created': 'Entry {sourceEntry} has been created.',
  'folder-entry-has-been-updated': 'Entry {sourceEntry} has been updated.',
  'folder-entry-name-required': 'Entry field is required.',
  'folder-entry-name-taken': 'Entry already existed in this folder.',
  'folder-has-been-created': 'Folder {folderName} has been created.',
  'folder-has-been-deleted': 'Folder {folderName} has been deleted.',
  'folder-has-been-updated': 'Folder {folderName} has been updated.',
  'folder-name': 'Folder Name',
  'folder-name-required': 'Field folder name is required.',
  'folder-name-taken': 'Folder name {folderName} exists',
  'folders': 'Folders',
  'garchen': 'Garchen',
  'home': 'Home',
  'import-csv-file': 'Import CSV file',
  'import-csv-rule-1': '1. Supported language codes are {supportedLangs} in this version, also known as {langExpression}',
  'import-csv-rule-2': '2. {langExpression} means the language code that supposed to be matched. For example, the column name of Source Entry is `source-entry-{langExpression}`.  It becomes source-entry-bo when Tibetan language code is applied.',
  'import-csv-rule-3': '3. Supported column names are {supportedColumnNames}.',
  'import-csv-rule-4': '4. First row should have column definition and MUST have source-entry-[lang], Please refer to our example file ',
  'import-csv-rule-5': '5. Please increase the write delay in settings page if you experience any slow responses while importing.',
  'login': 'Login',
  'next-page': 'Next',
  'no-column-row-detected': '在 {errorFilename} 偵測不到欄位資訊',
  'original-lang': 'Original - {lang}',
  'page-num': 'Page Number',
  'please-input-exact-the-same-folder-name': 'Please input {folderName}',
  'prev-page': 'Prev',
  'sect': 'Sect',
  'sect-1': 'Old',
  'sect-2': 'When',
  'sect-3': 'Sa',
  'sect-4': 'Karma',
  'sect-5': 'Fragant',
  'sect-6': 'Time',
  'sect-7': 'Off',
  'sect-8': 'According',
  'see-imported-folder': 'See imported folder',
  'settings': 'Settings',
  'source': 'Source',
  'source-entry': 'Source Entry',
  'source-entry-lang': 'Source Entry - {lang}',
  'source-lang': 'Source - {lang}',
  'source-language': 'Source Language',
  'submit': 'Submit',
  'target-entry-lang': 'Entry - {lang}',
  'target-language': 'Target Language',
  'update': 'Update',
  'write-delay-with-num': 'Write delay {writeDelay}ms',
  'zh-CN': 'Simplified Chinese',
  'zh-TW': 'Traditial Chinese'
};
<|endoftext|>


<commit_before>import getDefaultSettings from "./lazyload.defaults";
import purgeElements from "./lazyload.purge";
import autoInitialize from "./lazyload.autoInitialize";
import revealElement from "./lazyload.reveal";

const LazyLoad = function (instanceSettings, elements) {
    this._settings = Object.assign({}, getDefaultSettings(), instanceSettings);
    this._setObserver();
    this.update(elements);
};

LazyLoad.prototype = {
    _setObserver: function () {
        if (!("IntersectionObserver" in window)) {
            return;
        }

        const settings = this._settings;
        const onIntersection = (entries) => {
            entries.forEach((entry) => {
                // entry.isIntersecting is null on some versions of MS Edge
                // entry.intersectionRatio can be 0 on some intersecting elements
                if (entry.isIntersecting || entry.intersectionRatio > 0) {
                    let element = entry.target;
                    revealElement(element, settings);
                    this._observer.unobserve(element);
                }
            });
            this._elements = purgeElements(this._elements);
        };
        this._observer = new IntersectionObserver(onIntersection, {
            root: settings.container === document ? null : settings.container,
            rootMargin: settings.threshold + "px"
        });
    },

    update: function (elements) {
        const settings = this._settings;
        const nodeSet = elements || settings.container.querySelectorAll(settings.elements_selector);

        this._elements = purgeElements(Array.prototype.slice.call(nodeSet)); // nodeset to array for IE compatibility
        if (this._observer) {
            this._elements.forEach(element => {
                this._observer.observe(element);
            });
            return;
        }
        // Fallback: load all elements at once
        this._elements.forEach(element => {
            revealElement(element, settings);
        });
        this._elements = purgeElements(this._elements);
    },

    destroy: function () {
        if (this._observer) {
            purgeElements(this._elements).forEach(element => {
                this._observer.unobserve(element);
            });
            this._observer = null;
        }
        this._elements = null;
        this._settings = null;
    }
}

/* Automatic instances creation if required (useful for async script loading!) */
let autoInitOptions = window.lazyLoadOptions;
if (autoInitOptions) {
    autoInitialize(LazyLoad, autoInitOptions);
}

export default LazyLoad;<commit_msg>check for window before accessing it in the top level<commit_after>import getDefaultSettings from "./lazyload.defaults";
import purgeElements from "./lazyload.purge";
import autoInitialize from "./lazyload.autoInitialize";
import revealElement from "./lazyload.reveal";

const LazyLoad = function (instanceSettings, elements) {
    this._settings = Object.assign({}, getDefaultSettings(), instanceSettings);
    this._setObserver();
    this.update(elements);
};

LazyLoad.prototype = {
    _setObserver: function () {
        if (!("IntersectionObserver" in window)) {
            return;
        }

        const settings = this._settings;
        const onIntersection = (entries) => {
            entries.forEach((entry) => {
                // entry.isIntersecting is null on some versions of MS Edge
                // entry.intersectionRatio can be 0 on some intersecting elements
                if (entry.isIntersecting || entry.intersectionRatio > 0) {
                    let element = entry.target;
                    revealElement(element, settings);
                    this._observer.unobserve(element);
                }
            });
            this._elements = purgeElements(this._elements);
        };
        this._observer = new IntersectionObserver(onIntersection, {
            root: settings.container === document ? null : settings.container,
            rootMargin: settings.threshold + "px"
        });
    },

    update: function (elements) {
        const settings = this._settings;
        const nodeSet = elements || settings.container.querySelectorAll(settings.elements_selector);

        this._elements = purgeElements(Array.prototype.slice.call(nodeSet)); // nodeset to array for IE compatibility
        if (this._observer) {
            this._elements.forEach(element => {
                this._observer.observe(element);
            });
            return;
        }
        // Fallback: load all elements at once
        this._elements.forEach(element => {
            revealElement(element, settings);
        });
        this._elements = purgeElements(this._elements);
    },

    destroy: function () {
        if (this._observer) {
            purgeElements(this._elements).forEach(element => {
                this._observer.unobserve(element);
            });
            this._observer = null;
        }
        this._elements = null;
        this._settings = null;
    }
}

if (typeof window !== "undefined") {
    /* Automatic instances creation if required (useful for async script loading!) */
    let autoInitOptions = window.lazyLoadOptions;
    if (autoInitOptions) {
        autoInitialize(LazyLoad, autoInitOptions);
    }
}

export default LazyLoad;<|endoftext|>