<commit_before>var homepageScripts = function() {
  var adjustParentHeight = function($elements, $parent) {
    var maxElementHeight = 0;
    var currentElementHeight;

    $elements.each(function() {
      currentElementHeight = $(this).outerHeight(true);

      if (currentElementHeight > maxElementHeight) {
        maxElementHeight = currentElementHeight;

        $parent.css("height", maxElementHeight);
      }
    });
  };

  // Testimonials slider
  const $testimonials = $(".testimonial");
  const testimonialsSlider = ".testimonials-slider";
  const $testimonialText = $(".testimonial--blurb");
  var $currentSlide, testimonialHeight, currentTestimonialHeight;

  adjustParentHeight($testimonials, $(testimonialsSlider));

  $(window).resize(function() {
    adjustParentHeight($testimonials, $(testimonialsSlider));
  });

  $('.testimonials--nav--dot').click(function() {
    var posClass = $(this).attr("class").split(' ')[1];

    $('.testimonial, .testimonials--nav--dot').removeClass('is-active');
    $('.' + posClass).addClass('is-active');
  })

  setInterval(function() {
    $currentSlide = $(".testimonial.is-active");

    $(testimonialsSlider + " .is-active").removeClass("is-active");

    if ($currentSlide.hasClass("first")) {
      $(testimonialsSlider + " .second").addClass("is-active");
    } else if ($currentSlide.hasClass("second")) {
      $(testimonialsSlider + " .third").addClass("is-active");
    } else if ($currentSlide.hasClass("third")) {
      $(testimonialsSlider + " .fourth").addClass("is-active");
    } else if ($currentSlide.hasClass("fourth")) {
      $(testimonialsSlider + " .fifth").addClass("is-active");
    } else if ($currentSlide.hasClass("fifth")) {
      $(testimonialsSlider + " .sixth").addClass("is-active");
    } else if ($currentSlide.hasClass("sixth")) {
      $(testimonialsSlider + " .first").addClass("is-active");
    }

  }, 15000);

  // Sub-hero logo sliders
  var lastScrollPosition = 0;

  var hasScrollBar = function($element, $parent) {
    return $element.width() > $parent.width();
  };

  var elementIsVisible = function($element) {
    var windowScrollBottom = $(window).scrollTop() + $(window).height();
    var elementBottomPosition = $element.offset().top + $element.outerHeight();

    return windowScrollBottom > elementBottomPosition;
  };

  var canScrollLeft = function($element, $parent) {
    return $parent.scrollLeft() < $element.width();
  };

  var animateScroll = function($element) {
    var $image = $element.children(".home--sub-hero--logo");
    var currentScrollPosition = $(window).scrollTop();
    var elementScrollShift = currentScrollPosition < lastScrollPosition ? 0 : 1;

    lastScrollPosition = currentScrollPosition;

    if (hasScrollBar($image, $element) && elementIsVisible($element) && canScrollLeft($image, $element)) {
      $element.scrollLeft($element.scrollLeft() + elementScrollShift);
    }
  };

  $(window).scroll(function() {
    animateScroll($(".home--sub-hero--logos.containers"));
    animateScroll($(".home--sub-hero--logos.applications"));
  });

  $(function() {
    var htmlDecode = function(input) {
      var doc = new DOMParser().parseFromString(input, "text/html");
      return doc.documentElement.textContent;
    }
    var makeCommunityEvent = function(e) {
      if (e === undefined) {
        return e;
      }

      var eventType;

      if (e["event_category"]) {
        var parts = e["event_category"].split(",");
        var index = parts.indexOf("Habitat");

        if (index >= 0) {
          parts.splice(index, 1);
        }

      }

      var eventLink = htmlDecode(e["guid"]);
      var eventName = e["event_name"];
      var eventDateUrl = "https://events.chef.io/events/s/category/habitat/?scope[0]=" + e["start_date"] + "&scope[1]=" + e["start_date"];
      var eventDateEncoded = encodeURI(eventDateUrl);
      var eventDate = e["start_date"];
      var eventLocation = "";

      if (e.event_location && e.event_location.city && e.event_location.country) {
        eventLocation = e.event_location.city + ", " + e.event_location.country;
      }
      var weekdayNames = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday", "Sunday"]
      var monthNames = [ "January", "February", "March", "April", "May", "June",
          "July", "August", "September", "October", "November", "December" ];
      var newDate = new Date(e["start_date"]);
      var formattedDate = weekdayNames[newDate.getDay()] + ', '  + monthNames[newDate.getMonth()] + ' ' + newDate.getDate();
      var month = monthNames[newDate.getMonth()];

      var t = $("#homepage-event-template").clone().show().html();
      var template = t.replace("{{ event_link }}", eventLink)
                      .replace("{{ event_name }}", eventName)
                      .replace("{{ day_of_month }}", newDate.getDate())
                      .replace("{{ month_name }}", month)
                      .replace("{{ event_date_url }}", eventDateEncoded)
                      .replace("{{ event_date }}", formattedDate)
                      .replace("{{ event_location }}", eventLocation);

      return template;
    }

    if ($(".homepage--events--content").length) {
      $.getJSON("https://events.chef.io/wp-json/events/category/habitat", function(data) {
        if (Array.isArray(data)) {
          for (var i=0; i < 1; i+=1) {
            var row = $("<div>", {
              class: "home--hero--highlight--wrap"
            });

            var eventHome = makeCommunityEvent(data[i]);

            row.append(eventHome);

            $("div.homepage--events--content").append(row);
          }
        }
      });
    }
  });
};
<commit_msg>Use event timestamps for date computations<commit_after>var homepageScripts = function() {
  var adjustParentHeight = function($elements, $parent) {
    var maxElementHeight = 0;
    var currentElementHeight;

    $elements.each(function() {
      currentElementHeight = $(this).outerHeight(true);

      if (currentElementHeight > maxElementHeight) {
        maxElementHeight = currentElementHeight;

        $parent.css("height", maxElementHeight);
      }
    });
  };

  // Testimonials slider
  const $testimonials = $(".testimonial");
  const testimonialsSlider = ".testimonials-slider";
  const $testimonialText = $(".testimonial--blurb");
  var $currentSlide, testimonialHeight, currentTestimonialHeight;

  adjustParentHeight($testimonials, $(testimonialsSlider));

  $(window).resize(function() {
    adjustParentHeight($testimonials, $(testimonialsSlider));
  });

  $('.testimonials--nav--dot').click(function() {
    var posClass = $(this).attr("class").split(' ')[1];

    $('.testimonial, .testimonials--nav--dot').removeClass('is-active');
    $('.' + posClass).addClass('is-active');
  })

  setInterval(function() {
    $currentSlide = $(".testimonial.is-active");

    $(testimonialsSlider + " .is-active").removeClass("is-active");

    if ($currentSlide.hasClass("first")) {
      $(testimonialsSlider + " .second").addClass("is-active");
    } else if ($currentSlide.hasClass("second")) {
      $(testimonialsSlider + " .third").addClass("is-active");
    } else if ($currentSlide.hasClass("third")) {
      $(testimonialsSlider + " .fourth").addClass("is-active");
    } else if ($currentSlide.hasClass("fourth")) {
      $(testimonialsSlider + " .fifth").addClass("is-active");
    } else if ($currentSlide.hasClass("fifth")) {
      $(testimonialsSlider + " .sixth").addClass("is-active");
    } else if ($currentSlide.hasClass("sixth")) {
      $(testimonialsSlider + " .first").addClass("is-active");
    }

  }, 15000);

  // Sub-hero logo sliders
  var lastScrollPosition = 0;

  var hasScrollBar = function($element, $parent) {
    return $element.width() > $parent.width();
  };

  var elementIsVisible = function($element) {
    var windowScrollBottom = $(window).scrollTop() + $(window).height();
    var elementBottomPosition = $element.offset().top + $element.outerHeight();

    return windowScrollBottom > elementBottomPosition;
  };

  var canScrollLeft = function($element, $parent) {
    return $parent.scrollLeft() < $element.width();
  };

  var animateScroll = function($element) {
    var $image = $element.children(".home--sub-hero--logo");
    var currentScrollPosition = $(window).scrollTop();
    var elementScrollShift = currentScrollPosition < lastScrollPosition ? 0 : 1;

    lastScrollPosition = currentScrollPosition;

    if (hasScrollBar($image, $element) && elementIsVisible($element) && canScrollLeft($image, $element)) {
      $element.scrollLeft($element.scrollLeft() + elementScrollShift);
    }
  };

  $(window).scroll(function() {
    animateScroll($(".home--sub-hero--logos.containers"));
    animateScroll($(".home--sub-hero--logos.applications"));
  });

  $(function() {
    var htmlDecode = function(input) {
      var doc = new DOMParser().parseFromString(input, "text/html");
      return doc.documentElement.textContent;
    }
    var makeCommunityEvent = function(e) {
      if (e === undefined) {
        return e;
      }

      var eventType;

      if (e["event_category"]) {
        var parts = e["event_category"].split(",");
        var index = parts.indexOf("Habitat");

        if (index >= 0) {
          parts.splice(index, 1);
        }

      }

      var eventLink = htmlDecode(e["guid"]);
      var eventName = e["event_name"];
      var eventDateUrl = "https://events.chef.io/events/s/category/habitat/?scope[0]=" + e["start_date"] + "&scope[1]=" + e["start_date"];
      var eventDateEncoded = encodeURI(eventDateUrl);
      var eventDate = e["start_date"];
      var eventLocation = "";

      if (e.event_location && e.event_location.city && e.event_location.country) {
        eventLocation = e.event_location.city + ", " + e.event_location.country;
      }
      var weekdayNames = ["Monday", "Tuesday", "Thursday", "Friday", "Saturday", "Sunday"]
      var monthNames = [ "January", "February", "March", "April", "May", "June",
          "July", "August", "September", "October", "November", "December" ];
      var newDate = new Date(e["start"] * 1000);
      var formattedDate = weekdayNames[newDate.getDay()] + ', '  + monthNames[newDate.getMonth()] + ' ' + newDate.getDate();
      var month = monthNames[newDate.getMonth()];

      var t = $("#homepage-event-template").clone().show().html();
      var template = t.replace("{{ event_link }}", eventLink)
                      .replace("{{ event_name }}", eventName)
                      .replace("{{ day_of_month }}", newDate.getDate())
                      .replace("{{ month_name }}", month)
                      .replace("{{ event_date_url }}", eventDateEncoded)
                      .replace("{{ event_date }}", formattedDate)
                      .replace("{{ event_location }}", eventLocation);

      return template;
    }

    if ($(".homepage--events--content").length) {
      $.getJSON("https://events.chef.io/wp-json/events/category/habitat", function(data) {
        if (Array.isArray(data)) {
          for (var i=0; i < 1; i+=1) {
            var row = $("<div>", {
              class: "home--hero--highlight--wrap"
            });

            var eventHome = makeCommunityEvent(data[i]);

            row.append(eventHome);

            $("div.homepage--events--content").append(row);
          }
        }
      });
    }
  });
};
<|endoftext|>


<commit_before>import 'phantomjs-polyfill-object-assign';
import raf from 'raf';
raf.polyfill();
import {assert} from 'chai';
import ol from 'openlayers';

import ReactTestUtils from 'react-addons-test-utils';

import GeoNodeViewer from '../geonode.jsx';
import rendererWithIntl from '../helper/renderWithIntl.js';

describe('GeoNodeViewer', () => {
	let config;
	beforeEach(() => {
		config = { map: { layers: [] }};
	});
	it('exists', () => {
		const geonodeviewer = rendererWithIntl( <GeoNodeViewer config={config}/> );
		assert.isDefined(ReactTestUtils.isCompositeComponent(geonodeviewer));
	});
});
<commit_msg>Add test for rendering<commit_after>import 'phantomjs-polyfill-object-assign';
import raf from 'raf';
raf.polyfill();
import {assert} from 'chai';
import ol from 'openlayers';

import ReactTestUtils from 'react-addons-test-utils';

import GeoNodeViewer from '../geonode.jsx';
import rendererWithIntl from '../helper/renderWithIntl.js';

describe('GeoNodeViewer', () => {
	let config;
	beforeEach(() => {
		config = { map: { layers: [] }};
	});
	it('exists', () => {
		const geonodeviewer = rendererWithIntl( <GeoNodeViewer config={config}/> );
		assert.isDefined(ReactTestUtils.isCompositeComponent(geonodeviewer));
	});
	it('has a root div', () => {
		const renderer = ReactTestUtils.createRenderer();
		renderer.render(<GeoNodeViewer config={config} />);
		let result = renderer.getRenderOutput();
		assert.equal(result.type, 'div')
	});
  describe('one layer', () => {
    beforeEach(() => {
      config = { map: {
        layers: [{"opacity": 1.0, "group": "background", "name": "mapnik", "visibility": true, "source": "0", "fixed": true, "type": "OpenLayers.Layer.OSM"}]
      },
      sources: { "0": {"ptype": "gxp_osmsource"} }
      };
    });
    it('the layer list includes one layer', () => {
			const geonodeviewer = ReactTestUtils.renderIntoDocument(<IntlProvider locale="en"><GeoNodeViewer config={config}/></IntlProvider>);
      var contents = ReactTestUtils.scryRenderedDOMComponentsWithClass(geonodeviewer, 'layer-list');
			assert.equal(contents[0].textContent,'Base Mapsmapnik');
    });
	});
});
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import { isBlocked, block } from './clock';
import { addListener, removeListener } from './listener';
import {
  BACK,
  DOWN,
  UP,
  MENU,
  NEXTPROG,
  PREVPROG,
  NUM0,
  NUM1,
  NUM2,
  NUM3,
  NUM4,
  NUM5,
  NUM6,
  NUM7,
  NUM8,
  NUM9,
} from './keys';
import { execCb } from './funcHandler';

const Keys = React.createClass({

  propTypes: {
    children: React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array,
    ]),
    onBack: PropTypes.func,
    onDown: PropTypes.func,
    onUp: PropTypes.func,
    onDigit: PropTypes.func,
    onMenu: PropTypes.func,
    onNextProg: PropTypes.func,
    onPrevProg: PropTypes.func,
    active: PropTypes.bool,
  },

  getDefaultProps() {
    return {
      active: true,
    };
  },

  componentDidMount() {
    this.listenerId = addListener(this.keysHandler, this);
  },

  componentWillUnmount() {
    removeListener(this.listenerId);
  },

  keysHandler(keyCode) {
    if (this.props.active && !isBlocked()) {
      switch (keyCode) {
        case BACK:
          this.performAction(this.props.onBack);
          break;
        case UP:
          this.performAction(this.props.onUp);
          break;
        case DOWN:
          this.performAction(this.props.onDown);
          break;
        case MENU:
          this.performAction(this.props.onMenu);
          break;
        case NEXTPROG:
          this.performAction(this.props.onNextProg);
          break;
        case PREVPROG:
          this.performAction(this.props.onPrevProg);
          break;
        case NUM0:
        case NUM1:
        case NUM2:
        case NUM3:
        case NUM4:
        case NUM5:
        case NUM6:
        case NUM7:
        case NUM8:
        case NUM9:
          this.performAction(this.props.onDigit, keyCode);
          break;
        default:
      }
    }
  },

  performAction(callback, keyCode) {
    if (callback) {
      block();
      execCb(callback, keyCode, this, this.props);
    }
  },

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

});

export default Keys;
<commit_msg>onEnter property is now available on "KEYS"<commit_after>import React, { PropTypes } from 'react';
import { isBlocked, block } from './clock';
import { addListener, removeListener } from './listener';
import {
  BACK,
  DOWN,
  ENTER,
  UP,
  MENU,
  NEXTPROG,
  PREVPROG,
  NUM0,
  NUM1,
  NUM2,
  NUM3,
  NUM4,
  NUM5,
  NUM6,
  NUM7,
  NUM8,
  NUM9,
} from './keys';
import { execCb } from './funcHandler';

const Keys = React.createClass({

  propTypes: {
    children: React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array,
    ]),
    onBack: PropTypes.func,
    onEnter: PropTypes.func,
    onDown: PropTypes.func,
    onUp: PropTypes.func,
    onDigit: PropTypes.func,
    onMenu: PropTypes.func,
    onNextProg: PropTypes.func,
    onPrevProg: PropTypes.func,
    active: PropTypes.bool,
  },

  getDefaultProps() {
    return {
      active: true,
    };
  },

  componentDidMount() {
    this.listenerId = addListener(this.keysHandler, this);
  },

  componentWillUnmount() {
    removeListener(this.listenerId);
  },

  keysHandler(keyCode) {
    if (this.props.active && !isBlocked()) {
      switch (keyCode) {
        case BACK:
          this.performAction(this.props.onBack);
          break;
        case ENTER:
          this.performAction(this.props.onEnter);
          break;
        case UP:
          this.performAction(this.props.onUp);
          break;
        case DOWN:
          this.performAction(this.props.onDown);
          break;
        case MENU:
          this.performAction(this.props.onMenu);
          break;
        case NEXTPROG:
          this.performAction(this.props.onNextProg);
          break;
        case PREVPROG:
          this.performAction(this.props.onPrevProg);
          break;
        case NUM0:
        case NUM1:
        case NUM2:
        case NUM3:
        case NUM4:
        case NUM5:
        case NUM6:
        case NUM7:
        case NUM8:
        case NUM9:
          this.performAction(this.props.onDigit, keyCode);
          break;
        default:
      }
    }
  },

  performAction(callback, keyCode) {
    if (callback) {
      block();
      execCb(callback, keyCode, this, this.props);
    }
  },

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

});

export default Keys;
<|endoftext|>


<commit_before>var key = process.env.HUBOT_TRELLO_KEY;
var Promise = require('bluebird');
var Trello = require('node-trello');
var message = require('./slackMsgs.js');

module.exports = function (robot) {
    var db = require('./mlab-login.js').db();
    var encryption = require('./encryption.js');
    var CronJob = require('cron').CronJob;
    var job = new CronJob('00 24 19 * * *', // note that heroku free plan is not running 24/7
        function () { trelloNotifications(); },
        function () { }, /* This function is executed when the job stops */
        false, /* Start the job right now */
        'Europe/Athens' /* Time zone of this job. */
    );

    // check if trello notifications feature is enabled
    db.bind('settings');
    db.settings.find().toArrayAsync().then(dbData => {
        if (dbData.trelloNotifications) {
            job.start();
        } else {
            job.stop();
        }
    }).catch(dbError => {
        robot.logger.info(dbError)
    });

    trelloNotifications(); //for debugging
    function trelloNotifications() {
        robot.logger.info('started')
        db.bind('trelloTokens');
        db.trelloTokens.find().toArrayAsync().then(dbData => {
            var usersNum = dbData.length;
            for (let i = 0; i < usersNum; i++) { // i: the number of authorized trello users
                var encryptedToken = dbData[i].token;
                var token = encryption.decrypt(encryptedToken);
                var trello = Promise.promisifyAll(new Trello(key, token));
                var args = { read_filter: 'unread' }; // get only the unread notifications

                trello.getAsync('/1/member/me/notifications', args).then(notif => {

                    if (notif.length > 0) {
                        let msg = getMsg(notif);
                        let userId = dbData[i].id;      // get user's id (on chat platform)
                        robot.messageRoom(userId, msg); // send massage to that user
                    }
                }).catch(trError => {
                    robot.messageRoom('general', 'trError on scheduler.js. Please check server log');
                    robot.logger.error(trError);
                })
            }
        }).catch(dbError => {
            robot.messageRoom('general', 'dbError on scheduler.js. Please check server log');
            robot.logger.error(dbError)
        })
    }

    function getMsg(notif) {
        var msg = { attachments: [] };
        var notifNum = notif.length;

        for (let j = 0; j < notifNum; j++) { // j: the number of notifications per user
            let attachment = message.attachment();
            let type, creator, text, pretext, cardUrl, cardName;
            creator = notif[j].memberCreator.username;
            cardUrl = `https://trello.com/c/${notif[j].data.card.shortLink}`
            cardName = notif[j].data.card.name;
            switch (notif[j].type) {
                // case 'addAdminToBoard':
                // case 'addAdminToOrganization':
                // case 'addedAttachmentToCard':
                // case 'addedMemberToCard':
                // case 'addedToBoard':
                // case 'addedToCard':
                // case 'addedToOrganization':
                //     break;
                case 'cardDueSoon':
                case 'changeCard':
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    attachment.pretext = `${type} by ${creator}`;
                    attachment.text = notif[i].data.card
                    break;
                case 'closeBoard':
                    break;
                case 'commentCard':
                    attachment.pretext = `New comment on card <${cardUrl}|${cardName}> by ${creator}`
                    attachment.text = notif[j].data.text
                                msg.attachments.push(attachment);

                    break;
                // case 'createdCard':
                // case 'declinedInvitationToBoard':
                // case 'declinedInvitationToOrganization':
                // case 'invitedToBoard':
                // case 'invitedToOrganization':
                // case 'makeAdminOfBoard':
                // case 'makeAdminOfOrganization':
                // case 'memberJoinedTrello':
                // case 'mentionedOnCard':
                // case 'removedFromBoard':
                // case 'removedFromCard':
                // case 'removedFromOrganization':
                // case 'removedMemberFromCard':
                // case 'unconfirmedInvitedToBoard':
                // case 'unconfirmedInvitedToOrganization':
                // case 'updateCheckItemStateOnCard':
                // break;

                default:
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    attachment.pretext = `${type} by ${creator}`;
                    break;
            }
        }
        return msg;
    }
}<commit_msg>trello scheduler<commit_after>var key = process.env.HUBOT_TRELLO_KEY;
var Promise = require('bluebird');
var Trello = require('node-trello');
var message = require('./slackMsgs.js');

module.exports = function (robot) {
    var db = require('./mlab-login.js').db();
    var encryption = require('./encryption.js');
    var CronJob = require('cron').CronJob;
    var job = new CronJob('00 24 19 * * *', // note that heroku free plan is not running 24/7
        function () { trelloNotifications(); },
        function () { }, /* This function is executed when the job stops */
        false, /* Start the job right now */
        'Europe/Athens' /* Time zone of this job. */
    );

    // check if trello notifications feature is enabled
    db.bind('settings');
    db.settings.find().toArrayAsync().then(dbData => {
        if (dbData.trelloNotifications) {
            job.start();
        } else {
            job.stop();
        }
    }).catch(dbError => {
        robot.logger.info(dbError)
    });

    trelloNotifications(); //for debugging
    function trelloNotifications() {
        robot.logger.info('started')
        db.bind('trelloTokens');
        db.trelloTokens.find().toArrayAsync().then(dbData => {
            var usersNum = dbData.length;
            for (let i = 0; i < usersNum; i++) { // i: the number of authorized trello users
                var encryptedToken = dbData[i].token;
                var token = encryption.decrypt(encryptedToken);
                var trello = Promise.promisifyAll(new Trello(key, token));
                var args = { read_filter: 'unread' }; // get only the unread notifications

                trello.getAsync('/1/member/me/notifications', args).then(notif => {

                    if (notif.length > 0) {
                        let msg = getMsg(notif);
                        let userId = dbData[i].id;      // get user's id (on chat platform)
                        robot.messageRoom(userId, msg); // send massage to that user
                    }
                }).catch(trError => {
                    robot.messageRoom('general', 'trError on scheduler.js. Please check server log');
                    robot.logger.error(trError);
                })
            }
        }).catch(dbError => {
            robot.messageRoom('general', 'dbError on scheduler.js. Please check server log');
            robot.logger.error(dbError)
        })
    }

    function getMsg(notif) {
        var msg = { attachments: [] };
        var notifNum = notif.length;

        for (let j = 0; j < notifNum; j++) { // j: the number of notifications per user
            let attachment = message.attachment();
            let type, creator, text, pretext, cardUrl, cardName;
            creator = notif[j].memberCreator.username;
            cardUrl = `https://trello.com/c/${notif[j].data.card.shortLink}`
            cardName = notif[j].data.card.name;
            switch (notif[j].type) {
                // case 'addAdminToBoard':
                // case 'addAdminToOrganization':
                // case 'addedAttachmentToCard':
                // case 'addedMemberToCard':
                // case 'addedToBoard':
                // case 'addedToCard':
                // case 'addedToOrganization':
                //     break;
                case 'cardDueSoon':
                case 'changeCard':
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    attachment.pretext = `${type} by ${creator}`;
                    attachment.text = notif[j].data.card
                    break;
                case 'closeBoard':
                    break;
                case 'commentCard':
                    attachment.pretext = `New comment on card <${cardUrl}|${cardName}> by ${creator}`
                    attachment.text = notif[j].data.text
                                msg.attachments.push(attachment);

                    break;
                // case 'createdCard':
                // case 'declinedInvitationToBoard':
                // case 'declinedInvitationToOrganization':
                // case 'invitedToBoard':
                // case 'invitedToOrganization':
                // case 'makeAdminOfBoard':
                // case 'makeAdminOfOrganization':
                // case 'memberJoinedTrello':
                // case 'mentionedOnCard':
                // case 'removedFromBoard':
                // case 'removedFromCard':
                // case 'removedFromOrganization':
                // case 'removedMemberFromCard':
                // case 'unconfirmedInvitedToBoard':
                // case 'unconfirmedInvitedToOrganization':
                // case 'updateCheckItemStateOnCard':
                // break;

                default:
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    attachment.pretext = `${type} by ${creator}`;
                    break;
            }
        }
        return msg;
    }
}<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { isBlocked, block } from './clock';
import { addListener, removeListener } from './listener';
import { addKeyBinderToStore, _updateBinderState } from './redux/actions';
import {
  BACK,
  DOWN,
  ENTER,
  UP,
  MENU,
  NEXTPROG,
  PREVPROG,
  NUM0,
  NUM1,
  NUM2,
  NUM3,
  NUM4,
  NUM5,
  NUM6,
  NUM7,
  NUM8,
  NUM9,
} from './keys';
import { execCb } from './funcHandler';

class Keys extends Component {

  static get propTypes() {
    return {
      children: React.PropTypes.oneOfType([
        React.PropTypes.object,
        React.PropTypes.array,
      ]),
      id: PropTypes.string.isRequired,
      onBack: PropTypes.func,
      onDown: PropTypes.func,
      onUp: PropTypes.func,
      onDigit: PropTypes.func,
      onMenu: PropTypes.func,
      onNextProg: PropTypes.func,
      onPrevProg: PropTypes.func,
      active: PropTypes.bool,
    }
  }

  static get defaultProps() {
    return {
      active: true,
    }
  }

  constructor(props) {
    super(props);
    this.listenerId = addListener(this.keysHandler, this);
  }

  keysHandler(keyCode) {
    if (this.props.active && !isBlocked()) {
      switch (keyCode) {
        case BACK:
          this.performAction(this.props.onBack);
          break;
        case ENTER:
          this.performAction(this.props.onEnter);
          break;
        case UP:
          this.performAction(this.props.onUp);
          break;
        case DOWN:
          this.performAction(this.props.onDown);
          break;
        case MENU:
          this.performAction(this.props.onMenu);
          break;
        case NEXTPROG:
          this.performAction(this.props.onNextProg);
          break;
        case PREVPROG:
          this.performAction(this.props.onPrevProg);
          break;
        case NUM0:
        case NUM1:
        case NUM2:
        case NUM3:
        case NUM4:
        case NUM5:
        case NUM6:
        case NUM7:
        case NUM8:
        case NUM9:
          this.performAction(this.props.onDigit, keyCode);
          break;
        default:
      }
    }
  }

  performAction(callback, keyCode) {
    if (callback) {
      block();
      execCb(callback, keyCode, this, this.props);
    }
  }

  componentDidMount() {
    addKeyBinderToStore(this.props.id, this.props.active);
		_updateBinderState(this.props.id, {
			press: false
  });
  }

	componentWillUnmount() {
		removeListener(this.listenerId);
	}

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

export default Keys;
<commit_msg>add react props for onEnter function<commit_after>import React, { Component, PropTypes } from 'react';
import { isBlocked, block } from './clock';
import { addListener, removeListener } from './listener';
import { addKeyBinderToStore, _updateBinderState } from './redux/actions';
import {
  BACK,
  DOWN,
  ENTER,
  UP,
  MENU,
  NEXTPROG,
  PREVPROG,
  NUM0,
  NUM1,
  NUM2,
  NUM3,
  NUM4,
  NUM5,
  NUM6,
  NUM7,
  NUM8,
  NUM9,
} from './keys';
import { execCb } from './funcHandler';

class Keys extends Component {

  static get propTypes() {
    return {
      children: React.PropTypes.oneOfType([
        React.PropTypes.object,
        React.PropTypes.array,
      ]),
      id: PropTypes.string.isRequired,
      onBack: PropTypes.func,
      onDown: PropTypes.func,
      onEnter: PropTypes.func,
      onUp: PropTypes.func,
      onDigit: PropTypes.func,
      onMenu: PropTypes.func,
      onNextProg: PropTypes.func,
      onPrevProg: PropTypes.func,
      active: PropTypes.bool,
    }
  }

  static get defaultProps() {
    return {
      active: true,
    }
  }

  constructor(props) {
    super(props);
    this.listenerId = addListener(this.keysHandler, this);
  }

  keysHandler(keyCode) {
    if (this.props.active && !isBlocked()) {
      switch (keyCode) {
        case BACK:
          this.performAction(this.props.onBack);
          break;
        case ENTER:
          this.performAction(this.props.onEnter);
          break;
        case UP:
          this.performAction(this.props.onUp);
          break;
        case DOWN:
          this.performAction(this.props.onDown);
          break;
        case MENU:
          this.performAction(this.props.onMenu);
          break;
        case NEXTPROG:
          this.performAction(this.props.onNextProg);
          break;
        case PREVPROG:
          this.performAction(this.props.onPrevProg);
          break;
        case NUM0:
        case NUM1:
        case NUM2:
        case NUM3:
        case NUM4:
        case NUM5:
        case NUM6:
        case NUM7:
        case NUM8:
        case NUM9:
          this.performAction(this.props.onDigit, keyCode);
          break;
        default:
      }
    }
  }

  performAction(callback, keyCode) {
    if (callback) {
      block();
      execCb(callback, keyCode, this, this.props);
    }
  }

  componentDidMount() {
    addKeyBinderToStore(this.props.id, this.props.active);
    _updateBinderState(this.props.id, {
      press: false
    });
  }

  componentWillUnmount() {
    removeListener(this.listenerId);
  }

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

export default Keys;
<|endoftext|>


<commit_before>var key = process.env.HUBOT_TRELLO_KEY;
var Promise = require('bluebird');
var Trello = require('node-trello');
var message = require('./slackMsgs.js');

module.exports = function (robot) {
    var db = require('./mlab-login.js').db();
    var encryption = require('./encryption.js');
    var CronJob = require('cron').CronJob;
    var job = new CronJob('00 24 19 * * *', // note that heroku free plan is not running 24/7
        function () { trelloNotifications(); },
        function () { }, /* This function is executed when the job stops */
        false, /* Start the job right now */
        'Europe/Athens' /* Time zone of this job. */
    );

    // check if trello notifications feature is enabled
    db.bind('settings');
    db.settings.find().toArrayAsync().then(dbData => {
        if (dbData.trelloNotifications) {
            job.start();
        } else {
            job.stop();
        }
    }).catch(dbError => {
        robot.logger.info(dbError)
    });

    trelloNotifications(); //for debugging
    function trelloNotifications() {
        robot.logger.info('started')
        db.bind('trelloTokens');
        db.trelloTokens.find().toArrayAsync().then(dbData => {
            var usersNum = dbData.length;
            for (let i = 0; i < usersNum; i++) { // i: the number of authorized trello users
                var encryptedToken = dbData[i].token;
                var token = encryption.decrypt(encryptedToken);
                var trello = Promise.promisifyAll(new Trello(key, token));
                var args = { read_filter: 'unread' }; // get only the unread notifications

                trello.getAsync('/1/member/me/notifications', args).then(notif => {

                    if (notif.length > 0) {
                        let msg = getMsg(notif);
                        let userId = dbData[i].id;      // get user's id (on chat platform)
                        robot.messageRoom(userId, msg); // send massage to that user
                    }
                }).catch(trError => {
                    robot.messageRoom('general', 'trError on scheduler.js. Please check server log');
                    robot.logger.error(trError);
                })
            }
        }).catch(dbError => {
            robot.messageRoom('general', 'dbError on scheduler.js. Please check server log');
            robot.logger.error(dbError)
        })
    }

    function getMsg(notif) {
        var msg = { attachments: [] };
        var notifNum = notif.length;

        for (let j = 0; j < notifNum; j++) { // j: the number of notifications per user
            let attachment = message.attachment();
            let type, creator, text, pretext, cardUrl, cardName;
            creator = notif[j].memberCreator.username;
            cardUrl = `https://trello.com/c/${notif[j].data.card.shortLink}`
            cardName = notif[j].data.card.name;
            switch (notif[j].type) {
                // case 'addAdminToBoard':
                // case 'addAdminToOrganization':
                // case 'addedAttachmentToCard':
                // case 'addedMemberToCard':
                // case 'addedToBoard':
                // case 'addedToCard':
                // case 'addedToOrganization':
                //     break;
                case 'cardDueSoon':
                case 'changeCard':
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    pretext = `Card <${cardUrl}|{cardName}> edited by ${creator}`;
                    if (notif[j].data.card.due){
                        let fullDate = notif[j].data.card.due;
                        text = fullDate;
                } else {
                        text = notif[j].data.listAfter;
                    }
                    break;
                case 'closeBoard':
                    break;
                case 'commentCard':
                    pretext = `New comment on card <${cardUrl}|${cardName}> by ${creator}`
                    text = notif[j].data.text
                    break;
                // case 'createdCard':
                // case 'declinedInvitationToBoard':
                // case 'declinedInvitationToOrganization':
                // case 'invitedToBoard':
                // case 'invitedToOrganization':
                // case 'makeAdminOfBoard':
                // case 'makeAdminOfOrganization':
                // case 'memberJoinedTrello':
                // case 'mentionedOnCard':
                // case 'removedFromBoard':
                // case 'removedFromCard':
                // case 'removedFromOrganization':
                // case 'removedMemberFromCard':
                // case 'unconfirmedInvitedToBoard':
                // case 'unconfirmedInvitedToOrganization':
                // case 'updateCheckItemStateOnCard':
                // break;

                default:
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    text = 'default';
                    pretext = `${type} by ${creator}`;
                    break;
            }
            attachment.text = 'text';
            attachment.pretext = pretext;
            msg.attachments.push(attachment);
        }
        return msg;
    }
}<commit_msg>trello scheduler<commit_after>var key = process.env.HUBOT_TRELLO_KEY;
var Promise = require('bluebird');
var Trello = require('node-trello');
var message = require('./slackMsgs.js');

module.exports = function (robot) {
    var db = require('./mlab-login.js').db();
    var encryption = require('./encryption.js');
    var CronJob = require('cron').CronJob;
    var job = new CronJob('00 24 19 * * *', // note that heroku free plan is not running 24/7
        function () { trelloNotifications(); },
        function () { }, /* This function is executed when the job stops */
        false, /* Start the job right now */
        'Europe/Athens' /* Time zone of this job. */
    );

    // check if trello notifications feature is enabled
    db.bind('settings');
    db.settings.find().toArrayAsync().then(dbData => {
        if (dbData.trelloNotifications) {
            job.start();
        } else {
            job.stop();
        }
    }).catch(dbError => {
        robot.logger.info(dbError)
    });

    trelloNotifications(); //for debugging
    function trelloNotifications() {
        robot.logger.info('started')
        db.bind('trelloTokens');
        db.trelloTokens.find().toArrayAsync().then(dbData => {
            var usersNum = dbData.length;
            for (let i = 0; i < usersNum; i++) { // i: the number of authorized trello users
                var encryptedToken = dbData[i].token;
                var token = encryption.decrypt(encryptedToken);
                var trello = Promise.promisifyAll(new Trello(key, token));
                var args = { read_filter: 'unread' }; // get only the unread notifications

                trello.getAsync('/1/member/me/notifications', args).then(notif => {

                    if (notif.length > 0) {
                        let msg = getMsg(notif);
                        let userId = dbData[i].id;      // get user's id (on chat platform)
                        robot.messageRoom(userId, msg); // send massage to that user
                    }
                }).catch(trError => {
                    robot.messageRoom('general', 'trError on scheduler.js. Please check server log');
                    robot.logger.error(trError);
                })
            }
        }).catch(dbError => {
            robot.messageRoom('general', 'dbError on scheduler.js. Please check server log');
            robot.logger.error(dbError)
        })
    }

    function getMsg(notif) {
        var msg = { attachments: [] };
        var notifNum = notif.length;

        for (let j = 0; j < notifNum; j++) { // j: the number of notifications per user
            let attachment = message.attachment();
            let type, creator, text, pretext, cardUrl, cardName;
            creator = notif[j].memberCreator.username;
            cardUrl = `https://trello.com/c/${notif[j].data.card.shortLink}`
            cardName = notif[j].data.card.name;
            switch (notif[j].type) {
                // case 'addAdminToBoard':
                // case 'addAdminToOrganization':
                // case 'addedAttachmentToCard':
                // case 'addedMemberToCard':
                // case 'addedToBoard':
                // case 'addedToCard':
                // case 'addedToOrganization':
                //     break;
                case 'cardDueSoon':
                case 'changeCard':
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    pretext = `Card <${cardUrl}|{cardName}> edited by ${creator}`;
                    if (notif[j].data.card.due != null) {
                        let fullDate = notif[j].data.card.due;
                        text = fullDate;
                    } else {
                        text = notif[j].data.listAfter;
                    }
                    break;
                case 'closeBoard':
                    break;
                case 'commentCard':
                    pretext = `New comment on card <${cardUrl}|${cardName}> by ${creator}`
                    text = notif[j].data.text
                    break;
                // case 'createdCard':
                // case 'declinedInvitationToBoard':
                // case 'declinedInvitationToOrganization':
                // case 'invitedToBoard':
                // case 'invitedToOrganization':
                // case 'makeAdminOfBoard':
                // case 'makeAdminOfOrganization':
                // case 'memberJoinedTrello':
                // case 'mentionedOnCard':
                // case 'removedFromBoard':
                // case 'removedFromCard':
                // case 'removedFromOrganization':
                // case 'removedMemberFromCard':
                // case 'unconfirmedInvitedToBoard':
                // case 'unconfirmedInvitedToOrganization':
                // case 'updateCheckItemStateOnCard':
                // break;

                default:
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    text = 'default';
                    pretext = `${type} by ${creator}`;
                    break;
            }
            attachment.text = text;
            attachment.pretext = pretext;
            msg.attachments.push(attachment);
        }
        return msg;
    }
}<|endoftext|>


<commit_before>var key = process.env.HUBOT_TRELLO_KEY;
var Promise = require('bluebird');
var Trello = require('node-trello');
var message = require('./slackMsgs.js');

module.exports = function (robot) {
    var db = require('./mlab-login.js').db();
    var encryption = require('./encryption.js');
    var CronJob = require('cron').CronJob;
    var job = new CronJob('00 24 19 * * *', // note that heroku free plan is not running 24/7
        function () { trelloNotifications(); },
        function () { }, /* This function is executed when the job stops */
        false, /* Start the job right now */
        'Europe/Athens' /* Time zone of this job. */
    );

    // check if trello notifications feature is enabled
    db.bind('settings');
    db.settings.find().toArrayAsync().then(dbData => {
        if (dbData.trelloNotifications) {
            job.start();
        } else {
            job.stop();
        }
    }).catch(dbError => {
        robot.logger.info(dbError)
    });

    trelloNotifications(); //for debugging
    function trelloNotifications() {
        robot.logger.info('started')
        db.bind('trelloTokens');
        db.trelloTokens.find().toArrayAsync().then(dbData => {
            var usersNum = dbData.length;
            for (let i = 0; i < usersNum; i++) { // i: the number of authorized trello users
                var encryptedToken = dbData[i].token;
                var token = encryption.decrypt(encryptedToken);
                var trello = Promise.promisifyAll(new Trello(key, token));
                var args = { read_filter: 'unread' }; // get only the unread notifications

                trello.getAsync('/1/member/me/notifications', args).then(notif => {

                    if (notif.length > 0) {
                        let msg = getMsg(notif);
                        let userId = dbData[i].id;      // get user's id (on chat platform)
                        robot.messageRoom(userId, msg); // send massage to that user
                    }
                }).catch(trError => {
                    robot.messageRoom('general', 'trError on scheduler.js. Please check server log');
                    robot.logger.error(trError);
                })
            }
        }).catch(dbError => {
            robot.messageRoom('general', 'dbError on scheduler.js. Please check server log');
            robot.logger.error(dbError)
        })
    }

    function getMsg(notif) {
        var msg = { attachments: [] };
        var notifNum = notif.length;

        for (let j = 0; j < notifNum; j++) { // j: the number of notifications per user
            let attachment = message.attachment();
            let type, creator;
            switch (notif[j].type) {
                case 'addAdminToBoard':
                case 'addAdminToOrganization':
                case 'addedAttachmentToCard':
                case 'addedMemberToCard':
                case 'addedToBoard':
                case 'addedToCard':
                case 'addedToOrganization':
                    break;
                case 'cardDueSoon':
                case 'changeCard':
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    break; break;
                case 'closeBoard':
                case 'commentCard':
                case 'createdCard':
                case 'declinedInvitationToBoard':
                case 'declinedInvitationToOrganization':
                case 'invitedToBoard':
                case 'invitedToOrganization':
                case 'makeAdminOfBoard':
                case 'makeAdminOfOrganization':
                case 'memberJoinedTrello':
                case 'mentionedOnCard':
                case 'removedFromBoard':
                case 'removedFromCard':
                case 'removedFromOrganization':
                case 'removedMemberFromCard':
                case 'unconfirmedInvitedToBoard':
                case 'unconfirmedInvitedToOrganization':
                case 'updateCheckItemStateOnCard':

                default:
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    attachment.pretext = `${type} by ${creator}`;
                    break;
            }

            msg.attachments.push(attachment);
        }
        return msg;
    }
}<commit_msg>trello scheduler<commit_after>var key = process.env.HUBOT_TRELLO_KEY;
var Promise = require('bluebird');
var Trello = require('node-trello');
var message = require('./slackMsgs.js');

module.exports = function (robot) {
    var db = require('./mlab-login.js').db();
    var encryption = require('./encryption.js');
    var CronJob = require('cron').CronJob;
    var job = new CronJob('00 24 19 * * *', // note that heroku free plan is not running 24/7
        function () { trelloNotifications(); },
        function () { }, /* This function is executed when the job stops */
        false, /* Start the job right now */
        'Europe/Athens' /* Time zone of this job. */
    );

    // check if trello notifications feature is enabled
    db.bind('settings');
    db.settings.find().toArrayAsync().then(dbData => {
        if (dbData.trelloNotifications) {
            job.start();
        } else {
            job.stop();
        }
    }).catch(dbError => {
        robot.logger.info(dbError)
    });

    trelloNotifications(); //for debugging
    function trelloNotifications() {
        robot.logger.info('started')
        db.bind('trelloTokens');
        db.trelloTokens.find().toArrayAsync().then(dbData => {
            var usersNum = dbData.length;
            for (let i = 0; i < usersNum; i++) { // i: the number of authorized trello users
                var encryptedToken = dbData[i].token;
                var token = encryption.decrypt(encryptedToken);
                var trello = Promise.promisifyAll(new Trello(key, token));
                var args = { read_filter: 'unread' }; // get only the unread notifications

                trello.getAsync('/1/member/me/notifications', args).then(notif => {

                    if (notif.length > 0) {
                        let msg = getMsg(notif);
                        let userId = dbData[i].id;      // get user's id (on chat platform)
                        robot.messageRoom(userId, msg); // send massage to that user
                    }
                }).catch(trError => {
                    robot.messageRoom('general', 'trError on scheduler.js. Please check server log');
                    robot.logger.error(trError);
                })
            }
        }).catch(dbError => {
            robot.messageRoom('general', 'dbError on scheduler.js. Please check server log');
            robot.logger.error(dbError)
        })
    }

    function getMsg(notif) {
        var msg = { attachments: [] };
        var notifNum = notif.length;

        for (let j = 0; j < notifNum; j++) { // j: the number of notifications per user
            let attachment = message.attachment();
            let type, creator;
            switch (notif[j].type) {
                case 'addAdminToBoard':
                case 'addAdminToOrganization':
                case 'addedAttachmentToCard':
                case 'addedMemberToCard':
                case 'addedToBoard':
                case 'addedToCard':
                case 'addedToOrganization':
                    break;
                case 'cardDueSoon':
                case 'changeCard':
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    attachment.pretext = `${type} by ${creator}`;
                    break;
                case 'closeBoard':
                case 'commentCard':
                case 'createdCard':
                case 'declinedInvitationToBoard':
                case 'declinedInvitationToOrganization':
                case 'invitedToBoard':
                case 'invitedToOrganization':
                case 'makeAdminOfBoard':
                case 'makeAdminOfOrganization':
                case 'memberJoinedTrello':
                case 'mentionedOnCard':
                case 'removedFromBoard':
                case 'removedFromCard':
                case 'removedFromOrganization':
                case 'removedMemberFromCard':
                case 'unconfirmedInvitedToBoard':
                case 'unconfirmedInvitedToOrganization':
                case 'updateCheckItemStateOnCard':

                default:
                    type = notif[j].type.split(/(?=[A-Z])/).join(" ").toLowerCase(); // split capitals, join and convert to lowercase
                    creator = notif[j].memberCreator.username;
                    attachment.pretext = `${type} by ${creator}`;
                    break;
            }
            msg.attachments.push(attachment);
        }
        return msg;
    }
}<|endoftext|>


<commit_before>define(["dcl/dcl"], function(dcl){
	// module:
	//		dui/Stateful

	var apn = {};
	function propNames(name){
		// summary:
		//		Helper function to map "foo" --> "_setFooAttr" with caching to avoid recomputing strings.
		//		Note: in dojo/Stateful they are _fooGetter and _fooSetter.

		if(apn[name]){ return apn[name]; }
		var uc = name.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); });
		return (apn[name] = {
			p: "_" + name + "Attr",		// shadow property, since real property hidden by setter/getter
			s: "_set" + uc + "Attr",	// converts dashes to camel case, ex: accept-charset --> _setAcceptCharsetAttr
			g: "_get" + uc + "Attr"
		});
	}

	var Stateful = dcl(null, {
		// summary:
		//		Base class for objects that provide named properties with optional getter/setter
		//		control and the ability to watch for property changes.
		//
		//		The class also provides the functionality to auto-magically manage getters
		//		and setters for class attributes/properties.  Note though that expando properties
		//		(i.e. properties added to an instance but not in the prototype) are not supported.
		//
		//		Getters and Setters should follow the format of _setXxxAttr or _getXxxAttr where
		//		the xxx is a name of the attribute to handle.  So an attribute of "foo"
		//		would have a custom getter of _getFooAttr and a custom setter of _setFooAttr.
		//		Setters must save and announce the new property value by calling this._set("foo", val),
		//		and getters should access the property value as this._fooAttr.
		//
		// example:
		//	|	var MyClass = dcl(Stateful, {});
		//	|	var obj = new MyClass();
		//	|	obj.watch("foo", function(){
		//	|		console.log("foo changed to " + this.foo);
		//	|	});
		//	|	obj.foo = bar;

		_getProps: function(){
			// summary:
			//		Return the list of properties that should be watchable

			var list = [];
			for(var prop in this){
				if(typeof proto[prop] != "function" && !/^_/.test(prop)){
					list.push(prop);
				}
			}
			return list;
		},

		_introspect: function(/*String[]*/ props){
			// summary:
			//		Sets up ES5 getters/setters for each class property.
			//		Inside _introspect(), "this" is a reference to the prototype rather than any individual instance.

			props.forEach(function(prop){
				var names = propNames(prop),
					shadowProp = names.p,
					getter = names.g,
					setter = names.s;

				// Setup ES5 getter and setter for this property, if not already setup.
				// For a property named foo, saves raw value in _fooAttr.
				// ES5 setter intentionally does late checking for this[names.s] in case a subclass sets up a
				// _setFooAttr method.
				if(!(shadowProp in this)){
					this[shadowProp] = this[prop];
					Object.defineProperty(this, prop, {
						set: function(x){
							setter in this ? this[setter](x) : this._set(prop, x);
						},
						get: function(){
							return getter in this ? this[getter]() : this[shadowProp];
						}
					});
				}
			}, this);
		},

		constructor: dcl.advise({
			before: function(){
				// First time this class is instantiated, introspect it.
				// Use _introspected flag on constructor, rather than prototype, to avoid hits when superclass
				// was already inspected but this class wasn't.
				var ctor = this.constructor;
				if(!ctor._introspected){
					// note: inside _introspect() this refs prototype
					ctor.prototype._introspect(ctor.prototype.getProps());
					ctor._introspected = true;
				}
			},

			after: function(args){
				// Automatic setting of params during construction.
				// In after() advice so that it runs after all the subclass constructor methods.
				if (args.length){ this.mix(args[0]); }
			}
		}),

		mix: function(/*Object*/ hash){
			// summary:
			//		Set a hash of properties on a Stateful instance
			//	|	myObj.mix({
			//	|		foo: "Howdy",
			//	|		bar: 3
			//	|	})

			for(var x in hash){
				if(hash.hasOwnProperty(x) && x != "_watchCallbacks"){
					this[x] = hash[x];
				}
			}
		},

		_set: function(name, value){		// note: called _changeAttrValue() in dojo/Stateful
			// summary:
			//		Internal helper for directly changing an attribute value.
			// name: String
			//		The property to set.
			// value: Mixed
			//		The value to set in the property.
			// description:
			//		Directly change the value of an attribute on an object, bypassing any
			//		accessor setter.  Also notifies callbacks registered via watch().
			//		It is designed to be used by descendant class when there are two values
			//		of attributes that are linked, but calling .set() is not appropriate.

			var shadowPropName = propNames(name).p;
			var oldValue = this[shadowPropName];
			this[shadowPropName] = value;
			if(this._watchCallbacks){
				this._watchCallbacks(name, oldValue, value);
			}
		},

		_get: function(name){
			// summary:
			//		Internal helper for directly accessing an attribute value.
			// name: String
			//		The property to get.
			// description:
			//		Directly get the value of an attribute on an object, bypassing any
			//		accessor getter.
			//		It is designed to be used by descendant class if they want in their custom getter to access the value
			//		before returning it.

			return this[propNames(name).p];
		},

		watch: function(/*String?*/ name, /*Function*/ callback){
			// summary:
			//		Watches a property for changes
			// name:
			//		Indicates the property to watch. This is optional (the callback may be the
			//		only parameter), and if omitted, all the properties will be watched
			// returns:
			//		An object handle for the watch. The unwatch method of this object
			//		can be used to discontinue watching this property:
			//		|	var watchHandle = obj.watch("foo", callback);
			//		|	watchHandle.unwatch(); // callback won't be called now
			// callback:
			//		The function to execute when the property changes. This will be called after
			//		the property has been changed. The callback will be called with the |this|
			//		set to the instance, the first argument as the name of the property, the
			//		second argument as the old value and the third argument as the new value.

			var callbacks = this._watchCallbacks;
			if(!callbacks){
				var self = this;
				callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
					var notify = function(propertyCallbacks){
						if(propertyCallbacks){
							propertyCallbacks = propertyCallbacks.slice();
							for(var i = 0, l = propertyCallbacks.length; i < l; i++){
								propertyCallbacks[i].call(self, name, oldValue, value);
							}
						}
					};
					notify(callbacks['_' + name]);
					if(!ignoreCatchall){
						notify(callbacks["*"]); // the catch-all
					}
				}; // we use a function instead of an object so it will be ignored by JSON conversion
			}
			if(!callback && typeof name === "function"){
				callback = name;
				name = "*";
			}else{
				// prepend with dash to prevent name conflicts with function (like "name" property)
				name = '_' + name;
			}
			var propertyCallbacks = callbacks[name];
			if(typeof propertyCallbacks !== "object"){
				propertyCallbacks = callbacks[name] = [];
			}
			propertyCallbacks.push(callback);

			return {
				remove: function(){
					var index = propertyCallbacks.indexOf(callback);
					if(index > -1){
						propertyCallbacks.splice(index, 1);
					}
				}
			}; //Object
		}
	});

	dcl.chainAfter(Stateful, "_introspect");

	return Stateful;
});
<commit_msg>fix typos in previous Stateful check in<commit_after>define(["dcl/dcl"], function(dcl){
	// module:
	//		dui/Stateful

	var apn = {};
	function propNames(name){
		// summary:
		//		Helper function to map "foo" --> "_setFooAttr" with caching to avoid recomputing strings.
		//		Note: in dojo/Stateful they are _fooGetter and _fooSetter.

		if(apn[name]){ return apn[name]; }
		var uc = name.replace(/^[a-z]|-[a-zA-Z]/g, function(c){ return c.charAt(c.length-1).toUpperCase(); });
		return (apn[name] = {
			p: "_" + name + "Attr",		// shadow property, since real property hidden by setter/getter
			s: "_set" + uc + "Attr",	// converts dashes to camel case, ex: accept-charset --> _setAcceptCharsetAttr
			g: "_get" + uc + "Attr"
		});
	}

	var Stateful = dcl(null, {
		// summary:
		//		Base class for objects that provide named properties with optional getter/setter
		//		control and the ability to watch for property changes.
		//
		//		The class also provides the functionality to auto-magically manage getters
		//		and setters for class attributes/properties.  Note though that expando properties
		//		(i.e. properties added to an instance but not in the prototype) are not supported.
		//
		//		Getters and Setters should follow the format of _setXxxAttr or _getXxxAttr where
		//		the xxx is a name of the attribute to handle.  So an attribute of "foo"
		//		would have a custom getter of _getFooAttr and a custom setter of _setFooAttr.
		//		Setters must save and announce the new property value by calling this._set("foo", val),
		//		and getters should access the property value as this._fooAttr.
		//
		// example:
		//	|	var MyClass = dcl(Stateful, {});
		//	|	var obj = new MyClass();
		//	|	obj.watch("foo", function(){
		//	|		console.log("foo changed to " + this.foo);
		//	|	});
		//	|	obj.foo = bar;

		_getProps: function(){
			// summary:
			//		Return the list of properties that should be watchable

			var list = [];
			for(var prop in this){
				if(typeof this[prop] != "function" && !/^_/.test(prop)){
					list.push(prop);
				}
			}
			return list;
		},

		_introspect: function(/*String[]*/ props){
			// summary:
			//		Sets up ES5 getters/setters for each class property.
			//		Inside _introspect(), "this" is a reference to the prototype rather than any individual instance.

			props.forEach(function(prop){
				var names = propNames(prop),
					shadowProp = names.p,
					getter = names.g,
					setter = names.s;

				// Setup ES5 getter and setter for this property, if not already setup.
				// For a property named foo, saves raw value in _fooAttr.
				// ES5 setter intentionally does late checking for this[names.s] in case a subclass sets up a
				// _setFooAttr method.
				if(!(shadowProp in this)){
					this[shadowProp] = this[prop];
					Object.defineProperty(this, prop, {
						set: function(x){
							setter in this ? this[setter](x) : this._set(prop, x);
						},
						get: function(){
							return getter in this ? this[getter]() : this[shadowProp];
						}
					});
				}
			}, this);
		},

		constructor: dcl.advise({
			before: function(){
				// First time this class is instantiated, introspect it.
				// Use _introspected flag on constructor, rather than prototype, to avoid hits when superclass
				// was already inspected but this class wasn't.
				var ctor = this.constructor;
				if(!ctor._introspected){
					// note: inside _introspect() this refs prototype
					ctor.prototype._introspect(ctor.prototype._getProps());
					ctor._introspected = true;
				}
			},

			after: function(args){
				// Automatic setting of params during construction.
				// In after() advice so that it runs after all the subclass constructor methods.
				if (args.length){ this.mix(args[0]); }
			}
		}),

		mix: function(/*Object*/ hash){
			// summary:
			//		Set a hash of properties on a Stateful instance
			//	|	myObj.mix({
			//	|		foo: "Howdy",
			//	|		bar: 3
			//	|	})

			for(var x in hash){
				if(hash.hasOwnProperty(x) && x != "_watchCallbacks"){
					this[x] = hash[x];
				}
			}
		},

		_set: function(name, value){		// note: called _changeAttrValue() in dojo/Stateful
			// summary:
			//		Internal helper for directly changing an attribute value.
			// name: String
			//		The property to set.
			// value: Mixed
			//		The value to set in the property.
			// description:
			//		Directly change the value of an attribute on an object, bypassing any
			//		accessor setter.  Also notifies callbacks registered via watch().
			//		It is designed to be used by descendant class when there are two values
			//		of attributes that are linked, but calling .set() is not appropriate.

			var shadowPropName = propNames(name).p;
			var oldValue = this[shadowPropName];
			this[shadowPropName] = value;
			if(this._watchCallbacks){
				this._watchCallbacks(name, oldValue, value);
			}
		},

		_get: function(name){
			// summary:
			//		Internal helper for directly accessing an attribute value.
			// name: String
			//		The property to get.
			// description:
			//		Directly get the value of an attribute on an object, bypassing any
			//		accessor getter.
			//		It is designed to be used by descendant class if they want in their custom getter to access the value
			//		before returning it.

			return this[propNames(name).p];
		},

		watch: function(/*String?*/ name, /*Function*/ callback){
			// summary:
			//		Watches a property for changes
			// name:
			//		Indicates the property to watch. This is optional (the callback may be the
			//		only parameter), and if omitted, all the properties will be watched
			// returns:
			//		An object handle for the watch. The unwatch method of this object
			//		can be used to discontinue watching this property:
			//		|	var watchHandle = obj.watch("foo", callback);
			//		|	watchHandle.unwatch(); // callback won't be called now
			// callback:
			//		The function to execute when the property changes. This will be called after
			//		the property has been changed. The callback will be called with the |this|
			//		set to the instance, the first argument as the name of the property, the
			//		second argument as the old value and the third argument as the new value.

			var callbacks = this._watchCallbacks;
			if(!callbacks){
				var self = this;
				callbacks = this._watchCallbacks = function(name, oldValue, value, ignoreCatchall){
					var notify = function(propertyCallbacks){
						if(propertyCallbacks){
							propertyCallbacks = propertyCallbacks.slice();
							for(var i = 0, l = propertyCallbacks.length; i < l; i++){
								propertyCallbacks[i].call(self, name, oldValue, value);
							}
						}
					};
					notify(callbacks['_' + name]);
					if(!ignoreCatchall){
						notify(callbacks["*"]); // the catch-all
					}
				}; // we use a function instead of an object so it will be ignored by JSON conversion
			}
			if(!callback && typeof name === "function"){
				callback = name;
				name = "*";
			}else{
				// prepend with dash to prevent name conflicts with function (like "name" property)
				name = '_' + name;
			}
			var propertyCallbacks = callbacks[name];
			if(typeof propertyCallbacks !== "object"){
				propertyCallbacks = callbacks[name] = [];
			}
			propertyCallbacks.push(callback);

			return {
				remove: function(){
					var index = propertyCallbacks.indexOf(callback);
					if(index > -1){
						propertyCallbacks.splice(index, 1);
					}
				}
			}; //Object
		}
	});

	dcl.chainAfter(Stateful, "_introspect");

	return Stateful;
});
<|endoftext|>


<commit_before>"use strict";

window.requestAnimFrame = (function () {
    return window.requestAnimationFrame   ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function (callback, element) {
            window.setTimeout(callback, 1000 / 60);
        };
}());

game.engine = {};

game.engine.startScreen = (function () {
    var frames = 0, x = 200, y = 200;

    function tick() {
        var move = null;

        frames = frames + 1;
        move = game.controls.getMovement();
        x += move[0];
        y += move[1];
    }
    function draw() {
        game.ctx.clearRect(0, 0, game.ctx.canvas.width, game.ctx.canvas.height);
        game.ctx.fillStyle = "20pt Arial Sans-serif";
        game.ctx.fillText("Start Screen: " + frames, x, y);
    }

    return {
        tick: tick,
        draw: draw
    };
}());

game.engine.gameScreen = (function () {
    var frames = 0, x = 200, y = 200;

    function tick() {
        var move = null;

        frames = frames + 1;
        move = game.controls.getMovement();
        x += move[0];
        y += move[1];
    }
    function draw() {
        game.ctx.clearRect(0, 0, game.ctx.canvas.width, game.ctx.canvas.height);
        game.ctx.fillStyle = "20pt Arial Sans-serif";
        game.ctx.fillText("Game Screen: " + frames, x, y);
    }

    return {
        tick: tick,
        draw: draw
    };
}());

game.engine.main = (function () {
    var currentMode = game.engine.startScreen, timerDebug = false, frameNum = 0, frametime = null;

    frametime = {
        start: null,
        prev: null,
        now: null,
        current: null,
        sum: 0,
        maxVal: 0
    };

    function debug(debugging) {
        if (typeof debugging !== 'boolean') {
            timerDebug = !timerDebug;
        } else {
            timerDebug = debugging;
        }
    }

    function state(newState) {
        if (newState === "game") {
            currentMode = game.engine.gameScreen;
        } else {
            currentMode = game.engine.startScreen;
        }
    }

    function tick() {
        frametime.start = new Date().valueOf();

        currentMode.tick();
        currentMode.draw();

        frameNum = frameNum + 1;
        if (frameNum > 59) {
            if (timerDebug) {
                console.log('Average % of allowed time used by frames:', frametime.sum / 60, '\nHighest % of allowed time used by a frame:', frametime.maxVal);
            }
            frameNum = 0;
            frametime.sum = 0;
            frametime.maxVal = 0;
        }
        frametime.prev = frametime.now;
        frametime.now = new Date().valueOf();
        frametime.current = ((frametime.now - frametime.start) / (frametime.now - frametime.prev) * 100);
        frametime.sum = frametime.sum + frametime.current;
        if (frametime.current > frametime.maxVal) { frametime.maxVal = frametime.current; }
        window.requestAnimFrame(game.engine.main.tick);
    }

    return {
        debug: debug,
        state: state,
        tick: tick
    };
}());
<commit_msg>color added to fillStyle<commit_after>"use strict";

window.requestAnimFrame = (function () {
    return window.requestAnimationFrame   ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
        window.oRequestAnimationFrame      ||
        window.msRequestAnimationFrame     ||
        function (callback, element) {
            window.setTimeout(callback, 1000 / 60);
        };
}());

game.engine = {};

game.engine.startScreen = (function () {
    var frames = 0, x = 200, y = 200;

    function tick() {
        var move = null;

        frames = frames + 1;
        move = game.controls.getMovement();
        x += move[0];
        y += move[1];
    }
    function draw() {
        game.ctx.clearRect(0, 0, game.ctx.canvas.width, game.ctx.canvas.height);
        game.ctx.fillStyle = "#000 20pt Arial Sans-serif";
        game.ctx.fillText("Start Screen: " + frames, x, y);
    }

    return {
        tick: tick,
        draw: draw
    };
}());

game.engine.gameScreen = (function () {
    var frames = 0, x = 200, y = 200;

    function tick() {
        var move = null;

        frames = frames + 1;
        move = game.controls.getMovement();
        x += move[0];
        y += move[1];
    }
    function draw() {
        game.ctx.clearRect(0, 0, game.ctx.canvas.width, game.ctx.canvas.height);
        game.ctx.fillStyle = "20pt Arial Sans-serif";
        game.ctx.fillText("Game Screen: " + frames, x, y);
    }

    return {
        tick: tick,
        draw: draw
    };
}());

game.engine.main = (function () {
    var currentMode = game.engine.startScreen, timerDebug = false, frameNum = 0, frametime = null;

    frametime = {
        start: null,
        prev: null,
        now: null,
        current: null,
        sum: 0,
        maxVal: 0
    };

    function debug(debugging) {
        if (typeof debugging !== 'boolean') {
            timerDebug = !timerDebug;
        } else {
            timerDebug = debugging;
        }
    }

    function state(newState) {
        if (newState === "game") {
            currentMode = game.engine.gameScreen;
        } else {
            currentMode = game.engine.startScreen;
        }
    }

    function tick() {
        frametime.start = new Date().valueOf();

        currentMode.tick();
        currentMode.draw();

        frameNum = frameNum + 1;
        if (frameNum > 59) {
            if (timerDebug) {
                console.log('Average % of allowed time used by frames:', frametime.sum / 60, '\nHighest % of allowed time used by a frame:', frametime.maxVal);
            }
            frameNum = 0;
            frametime.sum = 0;
            frametime.maxVal = 0;
        }
        frametime.prev = frametime.now;
        frametime.now = new Date().valueOf();
        frametime.current = ((frametime.now - frametime.start) / (frametime.now - frametime.prev) * 100);
        frametime.sum = frametime.sum + frametime.current;
        if (frametime.current > frametime.maxVal) { frametime.maxVal = frametime.current; }
        window.requestAnimFrame(game.engine.main.tick);
    }

    return {
        debug: debug,
        state: state,
        tick: tick
    };
}());
<|endoftext|>


<commit_before>var gulp = require('gulp');
var sequence = require('run-sequence');

gulp.task('copy:fonts', function() {
  return gulp.src(['node_modules/lightgallery.js/dist/fonts/**/*', 'src/fonts/**/*'])
  .pipe(gulp.dest('./dist/fonts/'));
});

gulp.task('copy:gif', function() {
  return gulp.src(['node_modules/lightgallery.js/dist/img/loading.gif'])
  .pipe(gulp.dest('./dist/img/'));
});

gulp.task('copy:favicon', function() {
  return gulp.src(['src/images/favicon.ico'])
  .pipe(gulp.dest('./dist/'));
});

gulp.task('copy:cname', function() {
  return gulp.src(['CNAME'])
  .pipe(gulp.dest('./dist/'));
});

gulp.task('copy', function() {
  sequence('copy:fonts', 'copy:gif', 'copy:favicon', 'copy:cname');
});
<commit_msg>Changed gulp copy step<commit_after>var gulp = require('gulp');
var sequence = require('run-sequence');

gulp.task('copy:fonts', function() {
  return gulp.src(['node_modules/lightgallery.js/dist/fonts/**/*', 'src/fonts/**/*'])
  .pipe(gulp.dest('./dist/fonts/'));
});

gulp.task('copy:gif', function() {
  return gulp.src(['node_modules/lightgallery.js/dist/img/loading.gif'])
  .pipe(gulp.dest('./dist/img/'));
});

gulp.task('copy:favicon', function() {
  return gulp.src(['src/images/favicon.ico'])
  .pipe(gulp.dest('./dist/'));
});

gulp.task('copy:cname', function() {
  return gulp.src(['./CNAME'])
  .pipe(gulp.dest('./dist/'));
});

gulp.task('copy', function() {
  sequence('copy:fonts', 'copy:gif', 'copy:favicon', 'copy:cname');
});
<|endoftext|>


<commit_before>let gulp = require('gulp');
let install = require('gulp-install');
let conflict = require('gulp-conflict');
let inquirer = require('inquirer');
let mustache = require('gulp-mustache');
let rename = require('gulp-rename');
let path = require('path');
let fs = require('fs');

let paths = {
  common: [
    'build/**',
    'src/styles/**',
    'src/model/**',
    'src/util/**',
    'test/**',
    '.eslintignore',
    '.eslintrc.json',
    '.gitignore',
    'gulpfile.js',
    'nodemon.json',
    'package.json',
    'README.md'
  ],
  server: ['private/**', 'public/**', 'src/server/**', 'src/views/**'],
  client: ['src/client/**'],
  clientOnly: ['index.html'],
  mit: ['LICENSE']
};

let whenUsingGithub = answers => answers.useGithub;
let whenServer = answers => answers.type.server;

gulp.task('default', function( next ){
  inquirer.prompt([
    {
      type: 'checkbox',
      name: 'type',
      message: 'Project type',
      choices: [
        { name: 'Clientside', value: 'client', checked: true },
        { name: 'Serverside', value: 'server', checked: true }
      ]
    },

    {
      type: 'input',
      name: 'name',
      message: 'Lowercase project name (e.g. foo-bar)\n>'
    },

    {
      type: 'input',
      name: 'author',
      message: 'Author/organisation name (e.g. John Doe)\n>'
    },

    {
      type: 'input',
      name: 'description',
      message: 'One-line project description\n>'
    },

    {
      type: 'confirm',
      name: 'useGithub',
      message: 'Use Github?'
    },

    {
      type: 'input',
      name: 'githubProj',
      message: 'Github project name (e.g. org/foo-bar)\n>',
      when: whenUsingGithub
    },

    {
      type: 'confirm',
      name: 'mit',
      message: 'Use MIT license?'
    },

    {
      type: 'confirm',
      name: 'moveon',
      message: 'Create project with above options?'
    }
  ],
  function( answers ){
    if( !answers.moveon ){
      return next();
    }

    answers.client = answers.type.includes('client');
    answers.server = answers.type.includes('server');

    if( !answers.server && !answers.client ){
      console.log('Can not build project without both clientside and serverside; aborting...');
      return next();
    }

    answers.clientOnly = answers.client && !answers.server;
    answers.serverOnly = answers.server && !answers.client;

    let pathsIf = conditionName => answers[ conditionName ] ? paths[ conditionName ] : [];
    let addPathsForConditionName = ( list, name ) => list.concat( paths[ name ] );
    let eachPathsIf = conditionNames => conditionNames.reduce( addPathsForConditionName, [] );
    let relDir = p => path.join( __dirname, 'template', p ); // Note use of __dirname to be relative to generator

    gulp.src(
      eachPathsIf( Object.keys( paths ) ).map( relDir ),

      { base: path.join( __dirname, 'template' ) }
    )
      .pipe( mustache(answers) )             // Mustache template support
      .pipe( conflict('./') )                // Confirms overwrites on file conflicts
      .pipe( gulp.dest('./') )               // Without __dirname here = relative to cwd
      .pipe( install() )                     // Run `npm install` if necessary
      .on('finish', function(){

        if( answers.client ){
          fs.symlinkSync( '../build/app.js', './public/app.js' );
          fs.symlinkSync( '../build/deps.js', './public/deps.js' );
        }

        fs.symlinkSync( '../build/app.css', './public/app.css' );

        next();
      })
    ;
  });
});
<commit_msg>some fixes for clientside only projects<commit_after>let gulp = require('gulp');
let install = require('gulp-install');
let conflict = require('gulp-conflict');
let inquirer = require('inquirer');
let mustache = require('gulp-mustache');
let rename = require('gulp-rename');
let path = require('path');
let fs = require('fs');

let paths = {
  common: [
    'build/**',
    'src/styles/**',
    'src/model/**',
    'src/util/**',
    'test/**',
    '.eslintignore',
    '.eslintrc.json',
    '.gitignore',
    'gulpfile.js',
    'package.json',
    'README.md'
  ],
  server: ['private/**', 'public/**', 'src/server/**', 'src/views/**', 'nodemon.json'],
  client: ['src/client/**'],
  clientOnly: ['index.html'],
  mit: ['LICENSE']
};

let whenUsingGithub = answers => answers.useGithub;
let whenServer = answers => answers.type.server;

gulp.task('default', function( next ){
  inquirer.prompt([
    {
      type: 'checkbox',
      name: 'type',
      message: 'Project type',
      choices: [
        { name: 'Clientside', value: 'client', checked: true },
        { name: 'Serverside', value: 'server', checked: true }
      ]
    },

    {
      type: 'input',
      name: 'name',
      message: 'Lowercase project name (e.g. foo-bar)\n>'
    },

    {
      type: 'input',
      name: 'author',
      message: 'Author/organisation name (e.g. John Doe)\n>'
    },

    {
      type: 'input',
      name: 'description',
      message: 'One-line project description\n>'
    },

    {
      type: 'confirm',
      name: 'useGithub',
      message: 'Use Github?'
    },

    {
      type: 'input',
      name: 'githubProj',
      message: 'Github project name (e.g. org/foo-bar)\n>',
      when: whenUsingGithub
    },

    {
      type: 'confirm',
      name: 'mit',
      message: 'Use MIT license?'
    },

    {
      type: 'confirm',
      name: 'moveon',
      message: 'Create project with above options?'
    }
  ],
  function( answers ){
    if( !answers.moveon ){
      return next();
    }

    answers.common = true;
    answers.client = answers.type.includes('client');
    answers.server = answers.type.includes('server');

    if( !answers.server && !answers.client ){
      console.log('Can not build project without both clientside and serverside; aborting...');
      return next();
    }

    answers.clientOnly = answers.client && !answers.server;
    answers.serverOnly = answers.server && !answers.client;

    let pathsIf = conditionName => answers[ conditionName ] ? paths[ conditionName ] : [];
    let addPathsForConditionName = ( list, name ) => list.concat( answers[ name ] ? paths[ name ] : [] );
    let eachPathsIf = conditionNames => conditionNames.reduce( addPathsForConditionName, [] );
    let relDir = p => path.join( __dirname, 'template', p ); // Note use of __dirname to be relative to generator

    gulp.src(
      eachPathsIf( Object.keys( paths ) ).map( relDir ),

      { base: path.join( __dirname, 'template' ) }
    )
      .pipe( mustache(answers) )             // Mustache template support
      .pipe( conflict('./') )                // Confirms overwrites on file conflicts
      .pipe( gulp.dest('./') )               // Without __dirname here = relative to cwd
      .pipe( install() )                     // Run `npm install` if necessary
      .on('finish', function(){

        if( answers.server ){
          fs.symlinkSync( '../build/build.js', './public/build.js' );
          fs.symlinkSync( '../build/deps.js', './public/deps.js' );
          fs.symlinkSync( '../build/build.css', './public/build.css' );
        }

        next();
      })
    ;
  });
});
<|endoftext|>


<commit_before>define([
    'jsiso/canvas/Control',
    'jsiso/canvas/Input',
    'jsiso/img/load',
    'jsiso/json/load',
    'jsiso/tile/Field',
    'jsiso/pathfind/pathfind',
    '../../player',
    '../../action'
  ],
  (CanvasControl, CanvasInput, imgLoader, jsonLoader, TileField, pathfind, Player, Action) => {

  let requestAnimFrame = (function() {
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame  ||
    window.mozRequestAnimationFrame     ||
    window.oRequestAnimationFrame       ||
    window.msRequestAnimationFrame      ||
    function(callback, element) {
      window.setTimeout(callback, 1000 / 60);
    };
  })();

  const ELEMENT_NAMES = {
    containerName: 'container',
    frameName: 'text-frame',
    messageName: 'text-message',
    indicatorName: 'text-indicator'
  };

  let appendHtml = (el, str) => {
    let div = document.createElement('div');
    div.innerHTML = str;
    while (div.children.length > 0) {
      el.appendChild(div.children[0]);
    }
  }

  let createElements = (container, names) => {
    let elements = '\

\

\
        \
        ▼\

\
    ';
    appendHtml(container, elements);
  }

  return function TileEngine(x, y, xrange, yrange, parent=document.body, overrides) {
    let self = this;
    overrides = overrides || {};

    let elementNames = overrides.elementNames || ELEMENT_NAMES;
    createElements(parent, elementNames);
    const container = document.getElementById(elementNames.containerName);

    let textMessages = [];
    const textMessageFrame = document.getElementById(elementNames.frameName);
    const textMessage = document.getElementById(elementNames.messageName);
    const textIndicator = document.getElementById(elementNames.indicatorName)

    const controlWidth = container.clientWidth;
    const controlHeight = container.clientHeight;
    const context = CanvasControl.create("canvas", controlWidth, controlHeight, {}, elementNames.containerName, true);

    let backgroundLayers = [];
    let foregroundLayers = [];

    let paused = false;
    let mapLayers = [];
    let players = [];

    //CanvasControl.fullScreen();
    const input = new CanvasInput(document, CanvasControl());

    input.mouse_action(function(coords) {
      mapLayers.map(function(layer) {
        let t = layer.applyMouseFocus(coords.x, coords.y);
        players[0].goTo(t.x, t.y);
      });
    });

    input.keyboard(function(pressed, status) {
      let player = players[0];
      if (status) {
        if (paused) {
          if ([13, 32].indexOf(pressed) >= 0) {
            drawMessages();
          }
        } else {
          switch (pressed) {
            case 37: player.moveTo(player.getTile().x - 1, player.getTile().y); break;
            case 38: player.moveTo(player.getTile().x, player.getTile().y - 1); break;
            case 39: player.moveTo(player.getTile().x + 1, player.getTile().y); break;
            case 40: player.moveTo(player.getTile().x, player.getTile().y + 1); break;
            case 13: case 32: interact(player, player.getLookedAtTile()); break;
          }
        }
      }
    });

    let interact = (player, tile) => {
      if (!player.isMoving()) {
        let layers = mapLayers.filter((layer) => layer.zIndex === player.properties.zIndex);
        let actions = [];
        layers.forEach((layer) => actions = actions.concat(layer.actions));
        actions
          .filter((action) => action.x === tile.x && action.y == tile.y)
          .forEach((action) => (new Action(action)).execute(self, player));
      }
    };

    let pause = () => {
      paused = true;
    }

    let unpause = () => {
      paused = false;
      draw();
    }

    let clearText = () => {
      textMessages = [];
      textMessageFrame.classList.remove("in");
      textMessage.innerHTML = "";
      textIndicator.classList.remove("in");
      if (paused) {
        unpause();
      }
    }

    this.displayText = (text) => {
      textMessages = textMessages.concat(text);
    }

    let drawMessages = () => {
      if (textMessages.length > 0) {
        pause();
        let text = textMessages.splice(0, 1)[0];
        textMessage.innerHTML = text;
        if (!("in" in textMessageFrame.classList)) {
          textMessageFrame.classList.add("in");
        }
        if (textMessages.length >= 1) {
          textIndicator.classList.add("in");
        } else {
          textIndicator.classList.remove("in");
        }
      } else {
        clearText();
      }
    }

    let drawLayers = (layers) => {
      for (let i = y; i < yrange; i++) {
        for (let j = x; j < xrange; j++) {
          layers.forEach((layer) => layer.draw(i, j));
        }
      }
    }

    let setPlayerLighting = (tile) => {
      mapLayers.forEach((layer) => layer.setLight(tile.x, tile.y));
    }

    let draw = () => {
      context.clearRect(0, 0, controlWidth, controlHeight);
      drawLayers(backgroundLayers);
      for (let player of players) {
        player.draw();
        player.move();
        setPlayerLighting(player.getTile());
      }
      drawLayers(foregroundLayers);
      drawMessages();
      if (!paused) {
        requestAnimationFrame(draw);
      }
    }

    let initLayer = (layer) => {
      let mapLayer = new TileField(context, controlWidth, controlHeight);
      mapLayer.setup(layer);
      mapLayer.flip("horizontal");
      mapLayer.rotate("left");
      mapLayer.setLightmap(layer.lightmap);
      mapLayer = Object.assign(mapLayer, layer);
      return mapLayer;
    }

    this.init = (map) => {
      const player = map.characters["player"];
      imgLoader([{
        graphics: [player.sprites],
        spritesheet: {
          width: player.width,
          height: player.height
        }
      }]).then((playerImages) => {
        mapLayers = map.layers.sort((a, b) => a.zIndex > b.zIndex).map(initLayer);
        backgroundLayers = mapLayers.filter((layer) => layer.zIndex < player.zIndex && layer.visible);
        foregroundLayers = mapLayers.filter((layer) => layer.zIndex >= player.zIndex && layer.visible);

        player.files = playerImages[0].files;
        player.layer = mapLayers[0];
        player.pathfindingLayer = mapLayers[player.pathfindingLayer];
        player.tileWidth = map.tileWidth;
        player.tileHeight = map.tileHeight;

        players.push(new Player(context, player, player.x, player.y, pathfind));

        draw();
      });
    }
  }
});<commit_msg>Implement locked framerate<commit_after>define([
    'jsiso/canvas/Control',
    'jsiso/canvas/Input',
    'jsiso/img/load',
    'jsiso/json/load',
    'jsiso/tile/Field',
    'jsiso/pathfind/pathfind',
    '../../player',
    '../../action'
  ],
  (CanvasControl, CanvasInput, imgLoader, jsonLoader, TileField, pathfind, Player, Action) => {

  let requestAnimFrame = (function() {
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame  ||
    window.mozRequestAnimationFrame     ||
    window.oRequestAnimationFrame       ||
    window.msRequestAnimationFrame      ||
    function(callback, element) {
      window.setTimeout(callback, 1000 / 60);
    };
  })();

  const ELEMENT_NAMES = {
    containerName: 'container',
    frameName: 'text-frame',
    messageName: 'text-message',
    indicatorName: 'text-indicator'
  };

  let appendHtml = (el, str) => {
    let div = document.createElement('div');
    div.innerHTML = str;
    while (div.children.length > 0) {
      el.appendChild(div.children[0]);
    }
  }

  let createElements = (container, names) => {
    let elements = '\

\

\
        \
        ▼\

\
    ';
    appendHtml(container, elements);
  }

  return function TileEngine(x, y, xrange, yrange, parent=document.body, overrides) {
    let self = this;
    overrides = Object.assign({}, overrides);

    let elementNames = Object.assign(ELEMENT_NAMES, overrides.elementNames);
    createElements(parent, elementNames);
    const container = document.getElementById(elementNames.containerName);

    let textMessages = [];
    const textMessageFrame = document.getElementById(elementNames.frameName);
    const textMessage = document.getElementById(elementNames.messageName);
    const textIndicator = document.getElementById(elementNames.indicatorName)

    const controlWidth = container.clientWidth;
    const controlHeight = container.clientHeight;
    const context = CanvasControl.create("canvas", controlWidth, controlHeight, {}, elementNames.containerName, true);

    let backgroundLayers = [];
    let foregroundLayers = [];

    let paused = false;
    let mapLayers = [];
    let players = [];

    //CanvasControl.fullScreen();
    const input = new CanvasInput(document, CanvasControl());

    input.mouse_action(function(coords) {
      mapLayers.map(function(layer) {
        let t = layer.applyMouseFocus(coords.x, coords.y);
        players[0].goTo(t.x, t.y);
      });
    });

    input.keyboard(function(pressed, status) {
      let player = players[0];
      if (status) {
        if (paused) {
          if ([13, 32].indexOf(pressed) >= 0) {
            drawMessages();
          }
        } else {
          switch (pressed) {
            case 37: player.moveTo(player.getTile().x - 1, player.getTile().y); break;
            case 38: player.moveTo(player.getTile().x, player.getTile().y - 1); break;
            case 39: player.moveTo(player.getTile().x + 1, player.getTile().y); break;
            case 40: player.moveTo(player.getTile().x, player.getTile().y + 1); break;
            case 13: case 32: interact(player, player.getLookedAtTile()); break;
          }
        }
      }
    });

    let interact = (player, tile) => {
      if (!player.isMoving()) {
        let layers = mapLayers.filter((layer) => layer.zIndex === player.properties.zIndex);
        let actions = [];
        layers.forEach((layer) => actions = actions.concat(layer.actions));
        actions
          .filter((action) => action.x === tile.x && action.y == tile.y)
          .forEach((action) => (new Action(action)).execute(self, player));
      }
    };

    let pause = () => {
      paused = true;
    }

    let unpause = () => {
      paused = false;
      draw();
    }

    let clearText = () => {
      textMessages = [];
      textMessageFrame.classList.remove("in");
      textMessage.innerHTML = "";
      textIndicator.classList.remove("in");
      if (paused) {
        unpause();
      }
    }

    this.displayText = (text) => {
      textMessages = textMessages.concat(text);
    }

    let drawMessages = () => {
      if (textMessages.length > 0) {
        pause();
        let text = textMessages.splice(0, 1)[0];
        textMessage.innerHTML = text;
        if (!("in" in textMessageFrame.classList)) {
          textMessageFrame.classList.add("in");
        }
        if (textMessages.length >= 1) {
          textIndicator.classList.add("in");
        } else {
          textIndicator.classList.remove("in");
        }
      } else {
        clearText();
      }
    }

    let drawLayers = (layers) => {
      for (let i = y; i < yrange; i++) {
        for (let j = x; j < xrange; j++) {
          layers.forEach((layer) => layer.draw(i, j));
        }
      }
    }

    let setPlayerLighting = (tile) => {
      mapLayers.forEach((layer) => layer.setLight(tile.x, tile.y));
    }

    let previousTime = 0;
    let timeToDraw = (time) => !overrides.lockFramerate || (time - previousTime) >= 30;

    let draw = (time) => {
      if (!timeToDraw(time)) {
        requestAnimationFrame(draw);
      } else {
        previousTime = time;
        context.clearRect(0, 0, controlWidth, controlHeight);
        drawLayers(backgroundLayers);
        for (let player of players) {
          player.draw();
          player.move();
          setPlayerLighting(player.getTile());
        }
        drawLayers(foregroundLayers);
        drawMessages();
        if (!paused) {
          requestAnimationFrame(draw);
        }
      }
    }

    let initLayer = (layer) => {
      let mapLayer = new TileField(context, controlWidth, controlHeight);
      mapLayer.setup(layer);
      mapLayer.flip("horizontal");
      mapLayer.rotate("left");
      mapLayer.setLightmap(layer.lightmap);
      mapLayer = Object.assign(mapLayer, layer);
      return mapLayer;
    }

    this.init = (map) => {
      const player = map.characters["player"];
      imgLoader([{
        graphics: [player.sprites],
        spritesheet: {
          width: player.width,
          height: player.height
        }
      }]).then((playerImages) => {
        mapLayers = map.layers.sort((a, b) => a.zIndex > b.zIndex).map(initLayer);
        backgroundLayers = mapLayers.filter((layer) => layer.zIndex < player.zIndex && layer.visible);
        foregroundLayers = mapLayers.filter((layer) => layer.zIndex >= player.zIndex && layer.visible);

        player.files = playerImages[0].files;
        player.layer = mapLayers[0];
        player.pathfindingLayer = mapLayers[player.pathfindingLayer];
        player.tileWidth = map.tileWidth;
        player.tileHeight = map.tileHeight;

        players.push(new Player(context, player, player.x, player.y, pathfind));

        draw();
      });
    }
  }
});<|endoftext|>