<commit_before>'use strict';

const mongoose = require('mongoose');
const Promise = require('bluebird');
const moment = require('moment');

const logger = require('../../lib/logger');
const Message = require('./Message');
const helpers = require('../../lib/helpers');
const front = require('../../lib/front');
const twilio = require('../../lib/twilio');
const bertly = require('../../lib/bertly');

const config = require('../../config/app/models/conversation');

/**
 * Schema.
 */
const conversationSchema = new mongoose.Schema({
  userId: {
    type: String,
    index: true,
  },
  platform: String,
  platformUserId: {
    type: String,
    index: true,
  },
  topic: String,
  campaignId: Number,
  signupStatus: String,
  lastOutboundMessage: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Message',
  },
}, { timestamps: true });

conversationSchema.index({ createdAt: 1 });
conversationSchema.index({ updatedAt: 1 });
conversationSchema.index({ userId: 1, platform: 1 });

/**
 * @param {Object} req - Express request
 * @return {Promise}
 */
conversationSchema.statics.createFromReq = function (req) {
  const data = {
    userId: req.userId,
    platform: req.platform,
    platformUserId: req.platformUserId,
    topic: config.topics.default,
  };

  return this.create(data);
};

/**
 * @param {Object} req - Express request
 * @return {Promise}
 */
conversationSchema.statics.getFromReq = function (req) {
  const queryByUserId = { userId: req.userId, platform: req.platform };

  return this.findOneAndPopulateLastOutboundMessage(queryByUserId, req)
    .then((conversation) => {
      if (conversation) {
        return Promise.resolve(conversation);
      }
      // Have we already saved a Conversation for this User before we added userId?
      // TODO: Remove this when all Conversations have been backfilled with userId.
      const queryByPlatformUserId = { platform: 'sms', platformUserId: req.platformUserId };
      return this.findOneAndPopulateLastOutboundMessage(queryByPlatformUserId, req);
    });
};

/**
 * @param {Object} query - Mongoose query object
 * @param {Object} req - Express request
 * @return {Promise}
 */
conversationSchema.statics.findOneAndPopulateLastOutboundMessage = function (query, req) {
  logger.debug('Conversation.findOne', query, req);
  return this.findOne(query).populate('lastOutboundMessage');
};

/**
 * Updates topic and campaign per given topic object.
 * @param {Object} topic
 * @return {Promise}
 */
conversationSchema.methods.changeTopic = function (topicObject) {
  this.topic = topicObject.id;
  this.campaignId = topicObject.campaign ? topicObject.campaign.id : null;
  logger.debug('conversation.changeTopic', { topic: this.topic, campaignId: this.campaignId });
  return this.save();
};

/**
 * TODO: This will be deprecated once broadcast content type is split out into multiple types.
 * Sets Rivescript topic property to a string.
 * @param {String} topic
 * @return {Promise}
 */
conversationSchema.methods.setTopic = function (topic) {
  logger.debug('Conversation.setTopic', { topic });

  let promise = Promise.resolve();
  if (topic === this.topic) {
    return promise;
  }

  if (topic === config.topics.askSubscriptionStatus) {
    promise = helpers.user.setPendingSubscriptionStatusForUserId(this.userId);
  }

  this.topic = topic;
  return promise.then(() => this.save());
};

/**
 * @return {Promise}
 */
conversationSchema.methods.setDefaultTopic = function () {
  return this.setTopic(config.topics.default);
};

/**
 * @return {Promise}
 */
conversationSchema.methods.setCampaignTopic = function () {
  return this.setTopic(config.topics.campaign);
};

/**
 * @return {Promise}
 */
conversationSchema.methods.setSupportTopic = function () {
  return this.setTopic(config.topics.support);
};

/**
 * Returns save of User for updating given Campaign and its topic.
 * TODO: Refactor to just pass a campaignId. We were initially passing a campaign
 * model to set Conversation.topic (if Campaign had its own Rivescript topic defined).
 *
 * @param {Campaign} campaign
 * @return {Promise}
 */
conversationSchema.methods.setCampaignWithSignupStatus = function (campaign, signupStatus) {
  this.campaignId = campaign.id;
  this.signupStatus = signupStatus;
  logger.debug('setCampaignWithSignupStatus', { campaign: this.campaignId, signupStatus });

  return this.setCampaignTopic();
};

/**
 * Post signup for current campaign and set it as the topic.
 * @param {Campaign} campaign
 * @param {string} source
 * @param {string} keyword
 */
conversationSchema.methods.setCampaign = function (campaign) {
  return this.setCampaignWithSignupStatus(campaign, 'doing');
};

/**
 * Prompt signup for current campaign.
 * @param {Campaign} campaign
 * @param {string} source
 * @param {string} keyword
 */
conversationSchema.methods.promptSignupForCampaign = function (campaign) {
  return this.setCampaignWithSignupStatus(campaign, 'prompt');
};

/**
 * Decline signup for current campaign.
 * @param {Campaign} campaign
 * @param {string} source
 * @param {string} keyword
 */
conversationSchema.methods.declineSignup = function () {
  this.signupStatus = 'declined';
  return this.save();
};

/**
 * Gets data for a Conversation Message.
 * @param {string} text
 * @param {string} template
 * @return {object}
 */
conversationSchema.methods.getDefaultMessagePayload = function (text, template) {
  const data = {
    conversationId: this,
    campaignId: this.campaignId,
    topic: this.topic,
    userId: this.userId,
  };
  if (text) {
    data.text = text;
  }
  if (template) {
    data.template = template;
  }
  return data;
};

/**
 * Gets data from a req object for a Conversation Message.
 * TODO: refactor to use the req.inbound and req.outbound properties
 * @param {string} text
 * @param {string} template
 * @return {object}
 */
conversationSchema.methods.getMessagePayloadFromReq = function (req = {}, direction = '') {
  let broadcastId = null;

  // Attachments are stored in sub objects named according to the direction of the message
  // 'inbound' or 'outbound'
  const isOutbound = direction.includes('outbound');
  const isInbound = !isOutbound;
  const attachmentDirection = isOutbound ? 'outbound' : 'inbound';

  // Should only exist in outbound broadcast messages
  if (req.broadcastId) {
    broadcastId = req.broadcastId;
  // Set broadcastId when this is an inbound message responding to an outbound broadcast:
  } else if (direction === 'inbound') {
    broadcastId = req.lastOutboundBroadcastId;
  }

  // TODO: Handle platform dependent message properties here
  const data = {
    broadcastId,
    metadata: req.metadata || {},
    attachments: req.attachments ? req.attachments[attachmentDirection] : [],
  };

  // Add extras if present.

  // If inbound message and includes platformMessageId
  if (isInbound && req.platformMessageId) {
    data.platformMessageId = req.platformMessageId;
  }
  if (req.agentId) {
    data.agentId = req.agentId;
  }
  if (req.rivescriptMatch) {
    data.match = req.rivescriptMatch;
  }
  if (req.macro) {
    data.macro = req.macro;
  }
  return data;
};

/**
 * Creates Message for a Conversation with given params.
 * @param {string} direction
 * @param {string} text
 * @param {string} template
 * @param {array} attachments
 * @return {Promise}
 */
conversationSchema.methods.createMessage = async function (direction, text, template, req) {
  logger.debug('createMessage', { direction }, req);
  let messageText;
  if (direction !== 'inbound') {
    messageText = helpers.tags.render(text, req);

    if (bertly.isEnabled() && bertly.textHasLinks(messageText)) {
      messageText = await bertly.parseLinksInTextIntoRedirects(messageText);
    }
  } else {
    messageText = text;
  }

  const data = {
    text: messageText,
    direction,
    template,
  };

  // Merge default payload and payload from req
  const defaultPayload = this.getDefaultMessagePayload();
  Object.assign(data, defaultPayload, this.getMessagePayloadFromReq(req, direction));

  return Message.create(data);
};

/**
 * Sets and populates lastOutboundMessage for this conversation
 *
 * @param  {object} outboundMessage
 * @return {promise}
 */
conversationSchema.methods.setLastOutboundMessage = function (outboundMessage) {
  this.lastOutboundMessage = outboundMessage;
  return this.save()
    .then(() => this.populate('lastOutboundMessage').execPopulate());
};

/**
 * Creates Message with given params and saves it to lastOutboundMessage.
 * @param {string} direction
 * @param {string} text
 * @param {string} template
 * @return {Promise}
 */
conversationSchema.methods.createAndSetLastOutboundMessage = function (direction, text, template, req) { // eslint-disable-line max-len
  return this.createMessage(direction, text, template, req)
    .then((message) => {
      logger.debug('created message', { messageId: message.id }, req);
      // Backfill Conversations that may not have userId set.
      if (!this.userId) {
        logger.debug('Backfilling Conversation.userId', {
          userId: req.userId,
          conversationId: this.id,
        }, req);
        this.userId = req.userId;
      }
      return this.setLastOutboundMessage(message);
    });
};

/**
 * Posts the Last Outbound Message to Twilio for SMS conversations.
 */
conversationSchema.methods.postLastOutboundMessageToPlatform = function (req) {
  const messageText = this.lastOutboundMessage.text;

  if (!messageText || !this.isSms()) {
    return Promise.resolve();
  }

  const mediaUrl = this.lastOutboundMessage.attachments.map(attachment => attachment.url);

  return new Promise((resolve, reject) => {
    twilio.postMessage(req.platformUserId, messageText, mediaUrl)
      .then((twilioRes) => {
        const sid = twilioRes.sid;
        const status = twilioRes.status;
        logger.debug('twilio.postMessage', { sid, status }, req);

        // @see https://www.twilio.com/docs/api/messaging/message#resource-properties
        this.lastOutboundMessage.platformMessageId = sid;
        this.lastOutboundMessage.metadata.delivery.queuedAt = twilioRes.dateCreated;
        this.lastOutboundMessage.metadata.delivery.totalSegments = twilioRes.numSegments;
        return resolve(this.lastOutboundMessage.save());
      })
      .catch((error) => {
        /**
         * Save failure metadata before bubbling the error up the Promise chain when the error is
         * an unrecoverable error, since retries are suppressed when they are detected.
         */
        if (helpers.twilio.isBadRequestError(error)) {
          this.lastOutboundMessage.metadata.delivery.failedAt = moment().format();
          this.lastOutboundMessage.metadata.delivery.failureData = {
            code: error.code,
            message: error.message,
          };
          this.lastOutboundMessage.save()
            .then(() => reject(error))
            .catch((saveError) => {
              logger.error(
                'twilio.postMessage error: this.lastOutboundMessage.save() failed',
                saveError, req);
              reject(error);
            });
        } else {
          /**
           * Bubble up error so we can either suppress (unrecoverable error) or retry.
           */
          reject(error);
        }
      });
  });
};

/**
 * Posts the given Message from User to Support inbox for SMS conversations.
 */
conversationSchema.methods.postMessageToSupport = function (req, message) {
  if (!this.isSms()) {
    logger.debug('Support not available for platform.', { platform: this.platform }, req);
    return Promise.resolve();
  }

  return front.postMessage(req.userId, message.text)
    .then((res) => {
      logger.debug('front.postMessage response', { body: res.body }, req);
      return res;
    });
};

/**
 * @return {boolean}
 */
conversationSchema.methods.isSms = function () {
  return this.platform === 'sms';
};

/**
 * @return {boolean}
 */
conversationSchema.methods.isSupportTopic = function () {
  return this.topic === config.topics.support;
};

module.exports = mongoose.model('Conversation', conversationSchema);
<commit_msg>patch to stop trying to send a sms_status update to users we dont have an userId for<commit_after>'use strict';

const mongoose = require('mongoose');
const Promise = require('bluebird');
const moment = require('moment');

const logger = require('../../lib/logger');
const Message = require('./Message');
const helpers = require('../../lib/helpers');
const front = require('../../lib/front');
const twilio = require('../../lib/twilio');
const bertly = require('../../lib/bertly');

const config = require('../../config/app/models/conversation');

/**
 * Schema.
 */
const conversationSchema = new mongoose.Schema({
  userId: {
    type: String,
    index: true,
  },
  platform: String,
  platformUserId: {
    type: String,
    index: true,
  },
  topic: String,
  campaignId: Number,
  signupStatus: String,
  lastOutboundMessage: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Message',
  },
}, { timestamps: true });

conversationSchema.index({ createdAt: 1 });
conversationSchema.index({ updatedAt: 1 });
conversationSchema.index({ userId: 1, platform: 1 });

/**
 * @param {Object} req - Express request
 * @return {Promise}
 */
conversationSchema.statics.createFromReq = function (req) {
  const data = {
    userId: req.userId,
    platform: req.platform,
    platformUserId: req.platformUserId,
    topic: config.topics.default,
  };

  return this.create(data);
};

/**
 * @param {Object} req - Express request
 * @return {Promise}
 */
conversationSchema.statics.getFromReq = function (req) {
  const queryByUserId = { userId: req.userId, platform: req.platform };

  return this.findOneAndPopulateLastOutboundMessage(queryByUserId, req)
    .then((conversation) => {
      if (conversation) {
        return Promise.resolve(conversation);
      }
      // Have we already saved a Conversation for this User before we added userId?
      // TODO: Remove this when all Conversations have been backfilled with userId.
      const queryByPlatformUserId = { platform: 'sms', platformUserId: req.platformUserId };
      return this.findOneAndPopulateLastOutboundMessage(queryByPlatformUserId, req);
    });
};

/**
 * @param {Object} query - Mongoose query object
 * @param {Object} req - Express request
 * @return {Promise}
 */
conversationSchema.statics.findOneAndPopulateLastOutboundMessage = function (query, req) {
  logger.debug('Conversation.findOne', query, req);
  return this.findOne(query).populate('lastOutboundMessage');
};

/**
 * Updates topic and campaign per given topic object.
 * @param {Object} topic
 * @return {Promise}
 */
conversationSchema.methods.changeTopic = function (topicObject) {
  this.topic = topicObject.id;
  this.campaignId = topicObject.campaign ? topicObject.campaign.id : null;
  logger.debug('conversation.changeTopic', { topic: this.topic, campaignId: this.campaignId });
  return this.save();
};

/**
 * TODO: This will be deprecated once broadcast content type is split out into multiple types.
 * Sets Rivescript topic property to a string.
 * @param {String} topic
 * @return {Promise}
 */
conversationSchema.methods.setTopic = function (topic) {
  logger.debug('Conversation.setTopic', { topic });

  let promise = Promise.resolve();
  if (topic === this.topic) {
    return promise;
  }

  if (topic === config.topics.askSubscriptionStatus) {
    if (this.userId) {
      promise = helpers.user.setPendingSubscriptionStatusForUserId(this.userId);
    }
  }
  this.topic = topic;
  return promise.then(() => this.save());
};

/**
 * @return {Promise}
 */
conversationSchema.methods.setDefaultTopic = function () {
  return this.setTopic(config.topics.default);
};

/**
 * @return {Promise}
 */
conversationSchema.methods.setCampaignTopic = function () {
  return this.setTopic(config.topics.campaign);
};

/**
 * @return {Promise}
 */
conversationSchema.methods.setSupportTopic = function () {
  return this.setTopic(config.topics.support);
};

/**
 * Returns save of User for updating given Campaign and its topic.
 * TODO: Refactor to just pass a campaignId. We were initially passing a campaign
 * model to set Conversation.topic (if Campaign had its own Rivescript topic defined).
 *
 * @param {Campaign} campaign
 * @return {Promise}
 */
conversationSchema.methods.setCampaignWithSignupStatus = function (campaign, signupStatus) {
  this.campaignId = campaign.id;
  this.signupStatus = signupStatus;
  logger.debug('setCampaignWithSignupStatus', { campaign: this.campaignId, signupStatus });

  return this.setCampaignTopic();
};

/**
 * Post signup for current campaign and set it as the topic.
 * @param {Campaign} campaign
 * @param {string} source
 * @param {string} keyword
 */
conversationSchema.methods.setCampaign = function (campaign) {
  return this.setCampaignWithSignupStatus(campaign, 'doing');
};

/**
 * Prompt signup for current campaign.
 * @param {Campaign} campaign
 * @param {string} source
 * @param {string} keyword
 */
conversationSchema.methods.promptSignupForCampaign = function (campaign) {
  return this.setCampaignWithSignupStatus(campaign, 'prompt');
};

/**
 * Decline signup for current campaign.
 * @param {Campaign} campaign
 * @param {string} source
 * @param {string} keyword
 */
conversationSchema.methods.declineSignup = function () {
  this.signupStatus = 'declined';
  return this.save();
};

/**
 * Gets data for a Conversation Message.
 * @param {string} text
 * @param {string} template
 * @return {object}
 */
conversationSchema.methods.getDefaultMessagePayload = function (text, template) {
  const data = {
    conversationId: this,
    campaignId: this.campaignId,
    topic: this.topic,
    userId: this.userId,
  };
  if (text) {
    data.text = text;
  }
  if (template) {
    data.template = template;
  }
  return data;
};

/**
 * Gets data from a req object for a Conversation Message.
 * TODO: refactor to use the req.inbound and req.outbound properties
 * @param {string} text
 * @param {string} template
 * @return {object}
 */
conversationSchema.methods.getMessagePayloadFromReq = function (req = {}, direction = '') {
  let broadcastId = null;

  // Attachments are stored in sub objects named according to the direction of the message
  // 'inbound' or 'outbound'
  const isOutbound = direction.includes('outbound');
  const isInbound = !isOutbound;
  const attachmentDirection = isOutbound ? 'outbound' : 'inbound';

  // Should only exist in outbound broadcast messages
  if (req.broadcastId) {
    broadcastId = req.broadcastId;
  // Set broadcastId when this is an inbound message responding to an outbound broadcast:
  } else if (direction === 'inbound') {
    broadcastId = req.lastOutboundBroadcastId;
  }

  // TODO: Handle platform dependent message properties here
  const data = {
    broadcastId,
    metadata: req.metadata || {},
    attachments: req.attachments ? req.attachments[attachmentDirection] : [],
  };

  // Add extras if present.

  // If inbound message and includes platformMessageId
  if (isInbound && req.platformMessageId) {
    data.platformMessageId = req.platformMessageId;
  }
  if (req.agentId) {
    data.agentId = req.agentId;
  }
  if (req.rivescriptMatch) {
    data.match = req.rivescriptMatch;
  }
  if (req.macro) {
    data.macro = req.macro;
  }
  return data;
};

/**
 * Creates Message for a Conversation with given params.
 * @param {string} direction
 * @param {string} text
 * @param {string} template
 * @param {array} attachments
 * @return {Promise}
 */
conversationSchema.methods.createMessage = async function (direction, text, template, req) {
  logger.debug('createMessage', { direction }, req);
  let messageText;
  if (direction !== 'inbound') {
    messageText = helpers.tags.render(text, req);

    if (bertly.isEnabled() && bertly.textHasLinks(messageText)) {
      messageText = await bertly.parseLinksInTextIntoRedirects(messageText);
    }
  } else {
    messageText = text;
  }

  const data = {
    text: messageText,
    direction,
    template,
  };

  // Merge default payload and payload from req
  const defaultPayload = this.getDefaultMessagePayload();
  Object.assign(data, defaultPayload, this.getMessagePayloadFromReq(req, direction));

  return Message.create(data);
};

/**
 * Sets and populates lastOutboundMessage for this conversation
 *
 * @param  {object} outboundMessage
 * @return {promise}
 */
conversationSchema.methods.setLastOutboundMessage = function (outboundMessage) {
  this.lastOutboundMessage = outboundMessage;
  return this.save()
    .then(() => this.populate('lastOutboundMessage').execPopulate());
};

/**
 * Creates Message with given params and saves it to lastOutboundMessage.
 * @param {string} direction
 * @param {string} text
 * @param {string} template
 * @return {Promise}
 */
conversationSchema.methods.createAndSetLastOutboundMessage = function (direction, text, template, req) { // eslint-disable-line max-len
  return this.createMessage(direction, text, template, req)
    .then((message) => {
      logger.debug('created message', { messageId: message.id }, req);
      // Backfill Conversations that may not have userId set.
      if (!this.userId) {
        logger.debug('Backfilling Conversation.userId', {
          userId: req.userId,
          conversationId: this.id,
        }, req);
        this.userId = req.userId;
      }
      return this.setLastOutboundMessage(message);
    });
};

/**
 * Posts the Last Outbound Message to Twilio for SMS conversations.
 */
conversationSchema.methods.postLastOutboundMessageToPlatform = function (req) {
  const messageText = this.lastOutboundMessage.text;

  if (!messageText || !this.isSms()) {
    return Promise.resolve();
  }

  const mediaUrl = this.lastOutboundMessage.attachments.map(attachment => attachment.url);

  return new Promise((resolve, reject) => {
    twilio.postMessage(req.platformUserId, messageText, mediaUrl)
      .then((twilioRes) => {
        const sid = twilioRes.sid;
        const status = twilioRes.status;
        logger.debug('twilio.postMessage', { sid, status }, req);

        // @see https://www.twilio.com/docs/api/messaging/message#resource-properties
        this.lastOutboundMessage.platformMessageId = sid;
        this.lastOutboundMessage.metadata.delivery.queuedAt = twilioRes.dateCreated;
        this.lastOutboundMessage.metadata.delivery.totalSegments = twilioRes.numSegments;
        return resolve(this.lastOutboundMessage.save());
      })
      .catch((error) => {
        /**
         * Save failure metadata before bubbling the error up the Promise chain when the error is
         * an unrecoverable error, since retries are suppressed when they are detected.
         */
        if (helpers.twilio.isBadRequestError(error)) {
          this.lastOutboundMessage.metadata.delivery.failedAt = moment().format();
          this.lastOutboundMessage.metadata.delivery.failureData = {
            code: error.code,
            message: error.message,
          };
          this.lastOutboundMessage.save()
            .then(() => reject(error))
            .catch((saveError) => {
              logger.error(
                'twilio.postMessage error: this.lastOutboundMessage.save() failed',
                saveError, req);
              reject(error);
            });
        } else {
          /**
           * Bubble up error so we can either suppress (unrecoverable error) or retry.
           */
          reject(error);
        }
      });
  });
};

/**
 * Posts the given Message from User to Support inbox for SMS conversations.
 */
conversationSchema.methods.postMessageToSupport = function (req, message) {
  if (!this.isSms()) {
    logger.debug('Support not available for platform.', { platform: this.platform }, req);
    return Promise.resolve();
  }

  return front.postMessage(req.userId, message.text)
    .then((res) => {
      logger.debug('front.postMessage response', { body: res.body }, req);
      return res;
    });
};

/**
 * @return {boolean}
 */
conversationSchema.methods.isSms = function () {
  return this.platform === 'sms';
};

/**
 * @return {boolean}
 */
conversationSchema.methods.isSupportTopic = function () {
  return this.topic === config.topics.support;
};

module.exports = mongoose.model('Conversation', conversationSchema);
<|endoftext|>


<commit_before>exports.definition = {
	config : {
		columns : {
			id : "TEXT UNIQUE NOT NULL PRIMARY KEY",
			name : "TEXT NOT NULL",
			currencyId : "TEXT NOT NULL",
			currentBalance : "REAL NOT NULL",
			remark : "TEXT",
			sharingType : "TEXT NOT NULL",
			accountType : "TEXT NOT NULL",
			accountNumber : "TEXT",
			bankAddress : "TEXT",
			ownerUserId : "TEXT NOT NULL",
		    serverRecordHash : "TEXT",
			lastServerUpdateTime : "INTEGER"
		},
		defaults : {
			currentBalance : 0
		},
		hasMany : {
			moneyExpenses : {
				type : "MoneyExpense",
				attribute : "moneyAccount"
			},
			moneyIncomes : {
				type : "MoneyIncome",
				attribute : "moneyAccount"
			},
			moneyBorrows : {
				type : "MoneyBorrow",
				attribute : "moneyAccount"
			},
			moneyLends : {
				type : "MoneyLend",
				attribute : "moneyAccount"
			},
			moneyPayback : {
				type : "MoneyPayback",
				attribute : "moneyAccount"
			},
			moneyReturns : {
				type : "MoneyReturn",
				attribute : "moneyAccount"
			}
		},
		belongsTo : {
			currency : {
				type : "Currency",
				attribute : "moneyAccounts"
			},
			ownerUser : {
				type : "User",
				attribute : "moneyAccounts"
			}
		},
		rowView : "money/moneyAccount/moneyAccountRow",
		adapter : {
			type : "hyjSql"
		}
	},
	extendModel : function(Model) {
		_.extend(Model.prototype, Alloy.Globals.XModel, {
			// extended functions and properties go here
			validators : {
				currency : function(xValidateComplete) {
					var error;
					if (!this.isNew()) {
						if (this.xGet("currency") !== this.previous("currency")) {
							error = {
								msg : "账户币种不可以修改"
							};
						}
					}
					xValidateComplete(error);
				}
			},
			xDelete : function(xFinishCallback, options) {
				var error;
				if (Alloy.Models.User.xGet("activeMoneyAccount") === this) {
					error = {
						msg : "默认账户不能删除"
					};
				}
				// else if (this.xGet("moneyExpenses") && this.xGet("moneyExpenses").length > 0) {
					// error = {
						// msg : "当前账户有相关支出，不能删除"
					// };
				// } else if (this.xGet("moneyIncomes") && this.xGet("moneyIncomes").length > 0) {
					// error = {
						// msg : "当前账户有相关收入，不能删除"
					// };
				// } else if (this.xGet("moneyBorrows") && this.xGet("moneyBorrows").length > 0) {
					// error = {
						// msg : "当前账户有相关借入，不能删除"
					// };
				// } else if (this.xGet("moneyLends") && this.xGet("moneyLends").length > 0) {
					// error = {
						// msg : "当前账户有相关借出，不能删除"
					// };
				// } else if (this.xGet("moneyPaybacks") && this.xGet("moneyPaybacks").length > 0 || this.xGet("moneyReturns").length > 0) {
					// error = {
						// msg : "当前账户有相关收款，不能删除"
					// };
				// } else if (this.xGet("moneyReturns") && this.xGet("moneyReturns").length > 0) {
					// error = {
						// msg : "当前账户有相关还款，不能删除"
					// };
				// }
				else {
					this._xDelete(xFinishCallback, options);
					return;
				}
				xFinishCallback(error);
			},
			getAccountNameCurrency : function() {
				if (this.xGet("ownerUser") === Alloy.Models.User) {
					return this.xGet("name") + " (" + this.xGet("currency").xGet("symbol") + this.xGet("currentBalance").toUserCurrency() + ")";
				} else {
					return this.xGet("name") + " (" + this.xGet("currency").xGet("symbol") + ")";
				}
			},
			getCurrentBalance : function() {
				if (this.xGet("ownerUser") === Alloy.Models.User) {
					return this.xGet("currentBalance");
				}
			},
			syncUpdate : function(record, dbTrans){
				delete record.currentBalance; // 我们不能将帐户余额同步下来
				this._syncUpdate(record, dbTrans);
			}
		});

		return Model;
	},
	extendCollection : function(Collection) {
		_.extend(Collection.prototype, Alloy.Globals.XCollection, {
			// extended functions and properties go here
		});

		return Collection;
	}
}

<commit_msg>fix #278 this.previous("currency") is undefied when model is edit and currency not change<commit_after>exports.definition = {
	config : {
		columns : {
			id : "TEXT UNIQUE NOT NULL PRIMARY KEY",
			name : "TEXT NOT NULL",
			currencyId : "TEXT NOT NULL",
			currentBalance : "REAL NOT NULL",
			remark : "TEXT",
			sharingType : "TEXT NOT NULL",
			accountType : "TEXT NOT NULL",
			accountNumber : "TEXT",
			bankAddress : "TEXT",
			ownerUserId : "TEXT NOT NULL",
		    serverRecordHash : "TEXT",
			lastServerUpdateTime : "INTEGER"
		},
		defaults : {
			currentBalance : 0
		},
		hasMany : {
			moneyExpenses : {
				type : "MoneyExpense",
				attribute : "moneyAccount"
			},
			moneyIncomes : {
				type : "MoneyIncome",
				attribute : "moneyAccount"
			},
			moneyBorrows : {
				type : "MoneyBorrow",
				attribute : "moneyAccount"
			},
			moneyLends : {
				type : "MoneyLend",
				attribute : "moneyAccount"
			},
			moneyPayback : {
				type : "MoneyPayback",
				attribute : "moneyAccount"
			},
			moneyReturns : {
				type : "MoneyReturn",
				attribute : "moneyAccount"
			}
		},
		belongsTo : {
			currency : {
				type : "Currency",
				attribute : "moneyAccounts"
			},
			ownerUser : {
				type : "User",
				attribute : "moneyAccounts"
			}
		},
		rowView : "money/moneyAccount/moneyAccountRow",
		adapter : {
			type : "hyjSql"
		}
	},
	extendModel : function(Model) {
		_.extend(Model.prototype, Alloy.Globals.XModel, {
			// extended functions and properties go here
			validators : {
				currency : function(xValidateComplete) {
					var error;
					if (!this.isNew() && this.previous("currency")) {
						if (this.xGet("currency") !== this.previous("currency")) {
							error = {
								msg : "账户币种不可以修改"
							};
						}
					}
					xValidateComplete(error);
				}
			},
			xDelete : function(xFinishCallback, options) {
				var error;
				if (Alloy.Models.User.xGet("activeMoneyAccount") === this) {
					error = {
						msg : "默认账户不能删除"
					};
				}
				// else if (this.xGet("moneyExpenses") && this.xGet("moneyExpenses").length > 0) {
					// error = {
						// msg : "当前账户有相关支出，不能删除"
					// };
				// } else if (this.xGet("moneyIncomes") && this.xGet("moneyIncomes").length > 0) {
					// error = {
						// msg : "当前账户有相关收入，不能删除"
					// };
				// } else if (this.xGet("moneyBorrows") && this.xGet("moneyBorrows").length > 0) {
					// error = {
						// msg : "当前账户有相关借入，不能删除"
					// };
				// } else if (this.xGet("moneyLends") && this.xGet("moneyLends").length > 0) {
					// error = {
						// msg : "当前账户有相关借出，不能删除"
					// };
				// } else if (this.xGet("moneyPaybacks") && this.xGet("moneyPaybacks").length > 0 || this.xGet("moneyReturns").length > 0) {
					// error = {
						// msg : "当前账户有相关收款，不能删除"
					// };
				// } else if (this.xGet("moneyReturns") && this.xGet("moneyReturns").length > 0) {
					// error = {
						// msg : "当前账户有相关还款，不能删除"
					// };
				// }
				else {
					this._xDelete(xFinishCallback, options);
					return;
				}
				xFinishCallback(error);
			},
			getAccountNameCurrency : function() {
				if (this.xGet("ownerUser") === Alloy.Models.User) {
					return this.xGet("name") + " (" + this.xGet("currency").xGet("symbol") + this.xGet("currentBalance").toUserCurrency() + ")";
				} else {
					return this.xGet("name") + " (" + this.xGet("currency").xGet("symbol") + ")";
				}
			},
			getCurrentBalance : function() {
				if (this.xGet("ownerUser") === Alloy.Models.User) {
					return this.xGet("currentBalance");
				}
			},
			syncUpdate : function(record, dbTrans){
				delete record.currentBalance; // 我们不能将帐户余额同步下来
				this._syncUpdate(record, dbTrans);
			}
		});

		return Model;
	},
	extendCollection : function(Collection) {
		_.extend(Collection.prototype, Alloy.Globals.XCollection, {
			// extended functions and properties go here
		});

		return Collection;
	}
}

<|endoftext|>


<commit_before>import React from 'react';
import { Route, IndexRoute, Redirect } from 'react-router';

import App from './components/App';
import IndexPage from './components/IndexPage/IndexPage.jsx';
import TaskPage from './components/TaskPage/TaskPage.jsx';
import AddTask from './components/AddTask/AddTask.jsx';
import TasksCatalog from './components/TasksCatalog/component.jsx';
import ContestItem from './components/contestItem/component.jsx';
import SubmitIdea from './components/SumbitIdea/component.jsx';
import NotFoundView from './views/NotFoundView';

export default (
  <Route path="/" component={App}>
    <IndexRoute component={IndexPage} />
    <Route path="task/:taskId" component={TaskPage} />
    <Route path="addtask" component={AddTask} />
    <Route path="404" component={NotFoundView} />
    <Route path="taskscatalog" component={TasksCatalog} />
    <Route path="contestitem/:id" component={ContestItem} />
    <Route path="contestitem/:id/submitidea" component={SubmitIdea} />
    <Redirect from="*" to="404" />
  </Route>
);
<commit_msg>blyad<commit_after>import React from 'react';
import { Route, IndexRoute, Redirect } from 'react-router';

import App from './components/App';
import IndexPage from './components/IndexPage/IndexPage.jsx';
import TaskPage from './components/TaskPage/TaskPage.jsx';
import AddTask from './components/AddTask/AddTask.jsx';
import TasksCatalog from './components/TasksCatalog/component.jsx';
import ContestItem from './components/contestItem/component.jsx';
import NotFoundView from './components/base/404/component.jsx';

export default (
  <Route path="/" component={App}>
    <IndexRoute component={IndexPage} />
    <Route path="task/:taskId" component={TaskPage} />
    <Route path="addtask" component={AddTask} />
    <Route path="404" component={NotFoundView} />
    <Route path="taskscatalog" component={TasksCatalog} />
    <Route path="contestitem/:id" component={ContestItem} />
    <Redirect from="*" to="404" />
  </Route>
);
<|endoftext|>


<commit_before>/*
 * Notes :
 * need to figure out if there is a way to continously check if
 * the alarms sets off.
 */

/**
 * Welcome to Pebble.js!
 * Test
 * This is where you write your app.
 */

// Calls in required stuff
var UI = require('ui');
var Vibe = require('ui/vibe');
var Settings = require('settings');
var date = new Date();

//var Vector2 = require('vector2');

// A for loop to make array of hours
var hours = [];
for (var i = 0; i < 24; i++) {
    hours.push(i + 1);
}

var alarms = Settings.data('alarms') || [];
var createAlarmItems = function(alarms) {
    var items = [];
    items.push({
        title: "Add New Alarm"
    });
    console.log("added new alarm");
    for (var i = 1; i < alarms.length + 1; i++) {
        items.push({
            title: alarms[i].time,
            subtitle: alarms[i].enabled
        });
        console.log(i);
    }
    console.log("Created item list");
    return items;
};

var detectTimeLoop = function() {

	for (var i = 0; i < alarms.length; i++) {
		if ( alarms[i].hour == date.getHours() + 1 && alarms[i].minute == date.getMinutes() ) {

			// vibrates.. add
			Vibe.vibrate('long');
		}
	}

	setTimeout(function() {
		detectTimeLoop();
	}, 1000);
};

detectTimeLoop();

var formatTime = function() {

	var hour = ( ( date.getHours() % 12 != 0 ) ? date.getHours() % 12 : 12 )
	return date.getHours() + ":" + date.getMinutes() + " " + ( ( date.getHours() < 12 ) ? "AM" : "PM" )
}

// Sets up the alarms
var alarmItems = createAlarmItems(alarms);

/*
// Creates a loop to make an array of hours
var createHourItems = function() {
  var items = [];
  for (var i = 0; i < hours.length; i++) {
    items.push({
      title: hours[i]
    });
  }
  return items;
};
*/

/*
var main = new UI.Menu({
   sections:[{
     items: createItems()
  }]
});

main.show();
*/

// The Splashscreen
var splashScreen = new UI.Card({
    title: 'Alarm',
    icon: 'images/menu_icon.png',
    subtitle: 'Welcome to Our App',
    body: 'This is the splash page'
    //banner (future plans)
});

// Makes a menu with New Alarms
var main = new UI.Menu({
    sections: [{
        items: alarmItems
        /*
            [{
            title: 'Add New Alarm',
            subtitle: 'New Alarm'
        }, {
            // Dr. Seuss
            title: 'One Alarm'
        }, {
            title: 'Two Alarm'
        }, {
            title: 'Red Alarm'
        }, {
            title: 'Blue Alarm'
        }]
        */
        //, createAlarmItems(alarms)
    }]
});

// Shows the spashscreen and goes to the menu after 400 ms
splashScreen.show();
setTimeout(function() {
    splashScreen.hide();
    main.show();
}, 400);

main.on('select', function(e) {
    // If it is on the "New Alarm Option"
    if (e.itemIndex === 0) {
        // Has a random card as a placeholder
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();

        // When click the middle button it makes an alarm
        card.on('click', 'select', function() {
            Vibe.vibrate('long');
            alarms.push({
				time: formatTime(),
                hour: date.getHours() + 1,
                minute: date.getMinutes() + 2,
                enabled: true
            });
            //createAlarmItems(alarms);
            card.hide();
        });
    } else {
        // Otherwise the user selects an alarm
        // Creates the Menu for Alarm Options
        var alarmOptions = new UI.Menu({
            sections : [{
                items: [{
                    title: 'Disable'
                }, {
                    title: 'Edit'
                }, {
                    title: 'Delete'
                }]
            }]
        });
        alarmOptions.show();
    }
    // Choose an option to chnage alarm
    alarmOptions.on('select', function(e) {
        switch(e.itemIndex) {
            case 0:
                // Disable or Enable the Alarm
                if (e.item.enabled) {
                    e.item.enabled = false;
                } else {
                    e.item.enabled = true;
                }
                break;
            case 1:
                // Edit the time of the alarm
                break;
            case 2:
                // Deletes the alarm
                alarms.splice(e.itemIndex, 1);
                break;
            default:
                console.log("error");
                break;
        }
        // Update the alarms and gets rid of the option menu
        //createAlarmItems();
        alarmOptions.hide();
    });
});

// Code from before, I don't currently remove it for reference
/*
// Try but doesn't work
main.on('click', 'select', function(e) {
    var item = this.items(0);
    if (item.title == "Add New Alarm") {
        Vibe.vibrate('long');
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();
    }
});
*/

/*
main.on('click', 'up', function(e) {
    var menu = new UI.Menu({
        sections: [{
            items: [{
                title: 'Pebble.js',
                icon: 'images/menu_icon.png',
                subtitle: 'Can do Menus'
            }, {
                title: 'Second Item',
                subtitle: 'Subtitle Text'
            }]
        }]
    });
    menu.on('select', function(e) {
        console.log('Selected item #' + e.itemIndex + ' of section #' + e.sectionIndex);
        console.log('The item is titled "' + e.item.title + '"');
    });
    menu.show();
});
*/

// When click middle button
/*
main.on('click', 'up', function(e) {
    //test vibrqtion and date fubction
    console.log("foo");
    if (new Date() == new Date()) {
        Vibe.vibrate('long');
    }
    var wind = new UI.Window();
    //var time = new UI.TimeText();
    // Time in Text form
    var textfield = new UI.TimeText({
        position: new Vector2(0, 50),
        size: new Vector2(144, 30),
        font: 'gothic-24-bold',
        text: '%M:%S, %a',
        textAlign: 'center'
    });
    wind.add(textfield);
    wind.show();
});
*/

/*
main.on('click', 'down', function(e) {
    var card = new UI.Card();
    card.title('A Card');
    card.subtitle('Is a Window');
    card.body('The simplest window type in Pebble.js.');
    card.show();
});
*/
<commit_msg>made function defined<commit_after>/*
 * Notes :
 * need to figure out if there is a way to continously check if
 * the alarms sets off.
 */

/**
 * Welcome to Pebble.js!
 * Test
 * This is where you write your app.
 */

// Calls in required stuff
var UI = require('ui');
var Vibe = require('ui/vibe');
var Settings = require('settings');
var date = new Date();

//var Vector2 = require('vector2');

// A for loop to make array of hours
var hours = [];
for (var i = 0; i < 24; i++) {
    hours.push(i + 1);
}

var alarms = Settings.data('alarms') || [];
var createAlarmItems = function(alarms) {
    var items = [];
    items.push({
        title: "Add New Alarm"
    });
    console.log("added new alarm");
    for (var i = 1; i < alarms.length + 1; i++) {
        items.push({
            title: alarms[i].time,
            subtitle: alarms[i].enabled
        });
        console.log(i);
    }
    console.log("Created item list");
    return items;
};

var detectTimeLoop = function() {

	for (var i = 0; i < alarms.length; i++) {
		if ( alarms[i].hour == date.getHours() + 1 && alarms[i].minute == date.getMinutes() ) {

			// vibrates.. add
			Vibe.vibrate('long');
		}
	}

	setTimeout(function() {
		detectTimeLoop();
	}, 1000);
};

detectTimeLoop();

var formatTime = function() {
	var hour = ( ( date.getHours() % 12 != 0 ) ? date.getHours() % 12 : 12 )
	return date.getHours() + ":" + date.getMinutes() + " " + ( ( date.getHours() < 12 ) ? "AM" : "PM" )
}

// Sets up the alarms
var alarmItems = createAlarmItems(alarms);

/*
// Creates a loop to make an array of hours
var createHourItems = function() {
  var items = [];
  for (var i = 0; i < hours.length; i++) {
    items.push({
      title: hours[i]
    });
  }
  return items;
};
*/

/*
var main = new UI.Menu({
   sections:[{
     items: createItems()
  }]
});

main.show();
*/

// The Splashscreen
var splashScreen = new UI.Card({
    title: 'Alarm',
    icon: 'images/menu_icon.png',
    subtitle: 'Welcome to Our App',
    body: 'This is the splash page'
    //banner (future plans)
});

// Makes a menu with New Alarms
var main = new UI.Menu({
    sections: [{
        items: alarmItems
        /*
            [{
            title: 'Add New Alarm',
            subtitle: 'New Alarm'
        }, {
            // Dr. Seuss
            title: 'One Alarm'
        }, {
            title: 'Two Alarm'
        }, {
            title: 'Red Alarm'
        }, {
            title: 'Blue Alarm'
        }]
        */
        //, createAlarmItems(alarms)
    }]
});

// Shows the spashscreen and goes to the menu after 400 ms
splashScreen.show();
setTimeout(function() {
    splashScreen.hide();
    main.show();
}, 400);

main.on('select', function(e) {
    // If it is on the "New Alarm Option"
    if (e.itemIndex === 0) {
        // Has a random card as a placeholder
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();

        // When click the middle button it makes an alarm
        card.on('click', 'select', function() {
            Vibe.vibrate('long');
            alarms.push({
				time: formatTime(),
                hour: date.getHours() + 1,
                minute: date.getMinutes() + 2,
                enabled: true
            });
            //createAlarmItems(alarms);
            card.hide();
        });
    } else {
        // Otherwise the user selects an alarm
        // Creates the Menu for Alarm Options
        var alarmOptions = new UI.Menu({
            sections : [{
                items: [{
                    title: 'Disable'
                }, {
                    title: 'Edit'
                }, {
                    title: 'Delete'
                }]
            }]
        });
        alarmOptions.show();

        alarmOptions.on('select', function(e) {
            switch(e.itemIndex) {
                case 0:
                    // Disable or Enable the Alarm
                    if (e.item.enabled) {
                        e.item.enabled = false;
                    } else {
                        e.item.enabled = true;
                    }
                    break;
                case 1:
                    // Edit the time of the alarm
                    break;
                case 2:
                    // Deletes the alarm
                    alarms.splice(e.itemIndex, 1);
                    break;
                default:
                    console.log("error");
                    break;
            }
            // Update the alarms and gets rid of the option menu
            //createAlarmItems();
            //alarmOptions.hide();
            });
    }
    // Choose an option to chnage alarm
});

// Code from before, I don't currently remove it for reference
/*
// Try but doesn't work
main.on('click', 'select', function(e) {
    var item = this.items(0);
    if (item.title == "Add New Alarm") {
        Vibe.vibrate('long');
        var card = new UI.Card();
        card.title('A Card');
        card.subtitle('Is a Window');
        card.body('The simplest window type in Pebble.js.');
        card.show();
    }
});
*/

/*
main.on('click', 'up', function(e) {
    var menu = new UI.Menu({
        sections: [{
            items: [{
                title: 'Pebble.js',
                icon: 'images/menu_icon.png',
                subtitle: 'Can do Menus'
            }, {
                title: 'Second Item',
                subtitle: 'Subtitle Text'
            }]
        }]
    });
    menu.on('select', function(e) {
        console.log('Selected item #' + e.itemIndex + ' of section #' + e.sectionIndex);
        console.log('The item is titled "' + e.item.title + '"');
    });
    menu.show();
});
*/

// When click middle button
/*
main.on('click', 'up', function(e) {
    //test vibrqtion and date fubction
    console.log("foo");
    if (new Date() == new Date()) {
        Vibe.vibrate('long');
    }
    var wind = new UI.Window();
    //var time = new UI.TimeText();
    // Time in Text form
    var textfield = new UI.TimeText({
        position: new Vector2(0, 50),
        size: new Vector2(144, 30),
        font: 'gothic-24-bold',
        text: '%M:%S, %a',
        textAlign: 'center'
    });
    wind.add(textfield);
    wind.show();
});
*/

/*
main.on('click', 'down', function(e) {
    var card = new UI.Card();
    card.title('A Card');
    card.subtitle('Is a Window');
    card.body('The simplest window type in Pebble.js.');
    card.show();
});
*/
<|endoftext|>


<commit_before>'use strict'
// JavaScript Standard Style: http://standardjs.com/

var app = {
  success: function (img) {
    var td = img.parentElement
    td.textContent = '✓'
    td.parentElement.classList.add('reachable')
  },
  fail: function (img) {
    var td = img.parentElement
    td.textContent = '☓'
    td.parentElement.classList.add('unreachable')
  }
}

;(function () {
  // https://www.google.com/supported_domains
  var domainString = '.google.com .google.ad .google.ae .google.com.af .google.com.ag .google.com.ai .google.al .google.am .google.co.ao .google.com.ar .google.as .google.at .google.com.au .google.az .google.ba .google.com.bd .google.be .google.bf .google.bg .google.com.bh .google.bi .google.bj .google.com.bn .google.com.bo .google.com.br .google.bs .google.bt .google.co.bw .google.by .google.com.bz .google.ca .google.cd .google.cf .google.cg .google.ch .google.ci .google.co.ck .google.cl .google.cm .google.cn .google.com.co .google.co.cr .google.com.cu .google.cv .google.com.cy .google.cz .google.de .google.dj .google.dk .google.dm .google.com.do .google.dz .google.com.ec .google.ee .google.com.eg .google.es .google.com.et .google.fi .google.com.fj .google.fm .google.fr .google.ga .google.ge .google.gg .google.com.gh .google.com.gi .google.gl .google.gm .google.gp .google.gr .google.com.gt .google.gy .google.com.hk .google.hn .google.hr .google.ht .google.hu .google.co.id .google.ie .google.co.il .google.im .google.co.in .google.iq .google.is .google.it .google.je .google.com.jm .google.jo .google.co.jp .google.co.ke .google.com.kh .google.ki .google.kg .google.co.kr .google.com.kw .google.kz .google.la .google.com.lb .google.li .google.lk .google.co.ls .google.lt .google.lu .google.lv .google.com.ly .google.co.ma .google.md .google.me .google.mg .google.mk .google.ml .google.com.mm .google.mn .google.ms .google.com.mt .google.mu .google.mv .google.mw .google.com.mx .google.com.my .google.co.mz .google.com.na .google.com.nf .google.com.ng .google.com.ni .google.ne .google.nl .google.no .google.com.np .google.nr .google.nu .google.co.nz .google.com.om .google.com.pa .google.com.pe .google.com.pg .google.com.ph .google.com.pk .google.pl .google.pn .google.com.pr .google.ps .google.pt .google.com.py .google.com.qa .google.ro .google.ru .google.rw .google.com.sa .google.com.sb .google.sc .google.se .google.com.sg .google.sh .google.si .google.sk .google.com.sl .google.sn .google.so .google.sm .google.sr .google.st .google.com.sv .google.td .google.tg .google.co.th .google.com.tj .google.tk .google.tl .google.tm .google.tn .google.to .google.com.tr .google.tt .google.com.tw .google.co.tz .google.com.ua .google.co.ug .google.co.uk .google.com.uy .google.co.uz .google.com.vc .google.co.ve .google.vg .google.co.vi .google.com.vn .google.vu .google.ws .google.rs .google.co.za .google.co.zm .google.co.zw .google.cat'

  var googleList = domainString.split(' .')
  googleList[0] = googleList[0].slice(1)

  var template = document.getElementById('ejs').text

  // ejs version: v2.4.2
  var value = ejs.render(template, {googleList: googleList})
  document.getElementsByTagName('table')[0].innerHTML += value
})()
<commit_msg>change cross mark<commit_after>'use strict'
// JavaScript Standard Style: http://standardjs.com/

var app = {
  success: function (img) {
    var td = img.parentElement
    td.textContent = '✓'
    td.parentElement.classList.add('reachable')
  },
  fail: function (img) {
    var td = img.parentElement
    td.textContent = '✗'
    td.parentElement.classList.add('unreachable')
  }
}

;(function () {
  // https://www.google.com/supported_domains
  var domainString = '.google.com .google.ad .google.ae .google.com.af .google.com.ag .google.com.ai .google.al .google.am .google.co.ao .google.com.ar .google.as .google.at .google.com.au .google.az .google.ba .google.com.bd .google.be .google.bf .google.bg .google.com.bh .google.bi .google.bj .google.com.bn .google.com.bo .google.com.br .google.bs .google.bt .google.co.bw .google.by .google.com.bz .google.ca .google.cd .google.cf .google.cg .google.ch .google.ci .google.co.ck .google.cl .google.cm .google.cn .google.com.co .google.co.cr .google.com.cu .google.cv .google.com.cy .google.cz .google.de .google.dj .google.dk .google.dm .google.com.do .google.dz .google.com.ec .google.ee .google.com.eg .google.es .google.com.et .google.fi .google.com.fj .google.fm .google.fr .google.ga .google.ge .google.gg .google.com.gh .google.com.gi .google.gl .google.gm .google.gp .google.gr .google.com.gt .google.gy .google.com.hk .google.hn .google.hr .google.ht .google.hu .google.co.id .google.ie .google.co.il .google.im .google.co.in .google.iq .google.is .google.it .google.je .google.com.jm .google.jo .google.co.jp .google.co.ke .google.com.kh .google.ki .google.kg .google.co.kr .google.com.kw .google.kz .google.la .google.com.lb .google.li .google.lk .google.co.ls .google.lt .google.lu .google.lv .google.com.ly .google.co.ma .google.md .google.me .google.mg .google.mk .google.ml .google.com.mm .google.mn .google.ms .google.com.mt .google.mu .google.mv .google.mw .google.com.mx .google.com.my .google.co.mz .google.com.na .google.com.nf .google.com.ng .google.com.ni .google.ne .google.nl .google.no .google.com.np .google.nr .google.nu .google.co.nz .google.com.om .google.com.pa .google.com.pe .google.com.pg .google.com.ph .google.com.pk .google.pl .google.pn .google.com.pr .google.ps .google.pt .google.com.py .google.com.qa .google.ro .google.ru .google.rw .google.com.sa .google.com.sb .google.sc .google.se .google.com.sg .google.sh .google.si .google.sk .google.com.sl .google.sn .google.so .google.sm .google.sr .google.st .google.com.sv .google.td .google.tg .google.co.th .google.com.tj .google.tk .google.tl .google.tm .google.tn .google.to .google.com.tr .google.tt .google.com.tw .google.co.tz .google.com.ua .google.co.ug .google.co.uk .google.com.uy .google.co.uz .google.com.vc .google.co.ve .google.vg .google.co.vi .google.com.vn .google.vu .google.ws .google.rs .google.co.za .google.co.zm .google.co.zw .google.cat'

  var googleList = domainString.split(' .')
  googleList[0] = googleList[0].slice(1)

  var template = document.getElementById('ejs').text

  // ejs version: v2.4.2
  var value = ejs.render(template, {googleList: googleList})
  document.getElementsByTagName('table')[0].innerHTML += value
})()
<|endoftext|>


<commit_before>/**
 * Main application module.
 * Project started: 16.03.2014 - 00:21
 * @module app
 * @author Sören Gade
 *
 * @requires config
 * @requires web/index
 * @requires io/rfidreader
 * */

require('./log-replace')();
var package = require('../package');
var config = require('./config');
var web = require('./web/');
var RFIDReader = require('./io/rfidreader');
var Relais = require('./io/relais');
var db = require('./db/');

/* ==========
 * Globals
 * ==========
 * */
var rfidReader = null;
var relais = null;

/* ==========
 * Init
 * ==========
 * */
/**
 * Starts the webserver.
 * */
function startWeb() {
  var port = config.web.port;

  if(typeof PhusionPassenger !== 'undefined') {
    PhusionPassenger.configure({ autoInstall: false });
    port = 'passenger';
  }

  web.init(port, web_RFIDRequest, web_OpenDoor, function() {
    web.start(function() {
      console.log("Web interface running on port " + web.getPort() + ".");
    });
  });
}
// callbacks for web requests
function web_RFIDRequest(callback) {
  rfidReader.on('data', function(data) {
    callback(data);
  });
}
function web_OpenDoor(callback) {
  console.log("Opening door...");

  openDoor(callback);
}

/**
 * Initializes the connection with the RFID reader.
 * */
function initRFIDReader() {
  var port = config.port.rfid;
  if ( !port ) {
    console.log("Please set the rfidreader port in the config.");
    return;
  }

  // create new instance
  rfidReader = new RFIDReader(port);

  // add event listeners
  rfidReader.on('data', function(data) {
    data = data.toString();
    console.log("Data by RFID reader:", data);

    db.Card.find({
      where: {
        uid: data
      }
    }).success(function(card) {
      if ( !card ) {
        console.log("No card found.");

        // switch yellow off, red on
        relais.setSingle(config.relaisport.red, function(err) {
          relais.setSingle(config.relaisport.yellow, function(err) {

            setTimeout(function() {
              // switch yellow on, red off
              relais.delSingle(config.relaisport.red, function(err) {
                relais.delSingle(config.relaisport.yellow);
              });
            }, 1500);
          });
        });
      } else {
        console.log("Card found.");
        card.getUser().success(function(user) {
          if ( !user ) {
            console.log("no user found");
          } else {
            console.log("user is", user.username);

            openDoor(function(err) {
              if ( !!err ) {
                console.log("Error opening door:", err);
                return;
              }

              console.log("Door had been opened.");
            });
          }
        });
      }
    });
  });

  // open connection
  rfidReader.open(function(err) {
    if ( !!err ) {
      console.log("Error opening connection to rfid reader:", err);
    } else {
      console.log("Connection to RFID reader opened (" + port + ").");
    }
  });
}
/**
 * Initializes the connection with the relais card.
 * */
function initRelais() {
  var port = config.port.relais;
  if ( !port ) {
    console.log("Please set the relais card port in the config.");
    return;
  }

  relais = new Relais(port);

  relais.open(function(err) {
    if ( !!err ) {
      console.log("Error opening connection to relais card:", err);
    } else {
      relais.setup(function(err, ok) {
        if ( !!err ) {
          console.log("Error setting up relais card:", err);
        } else {
          if ( !ok ) {
            console.log("Could not open connection to relais card.");
          } else {
            console.log("Connection to relais card opened (" + port + ").");

            relais.deactivateAll();
          }
        }
      });
    }
  });
}

function openDoor(callback) {
  // TODO: Try out if it really works in real environments
  relais.setSingle(config.relaisport.door, function(err) {
    if ( !!err ) {
      console.log("Error opening the door:", err);
      return callback(err);
    }

    // switch green on, yellow off
    relais.setSingle(conig.relaisport.green, function(err) {
      relais.setSingle(config.relaisport.yellow);
    });

    setTimeout(function() {
      relais.delSingle(config.relaisport.door, function(err) {
        if ( !!err ) {
          console.log("Door could not be closed!");
          return callback(err);
        }

        // switch green off, yellow on
        relais.delSingle(conig.relaisport.green, function(err) {
          relais.delSingle(config.relaisport.yellow);
        });

        console.log("Door closed.");
        return callback(null);
      });
    }, config.web.doorOpenTime);

  });
}

if ( !module.parent || typeof PhusionPassenger !== 'undefined') {
  /**
   * The main application entry point.
   * */
  (function main() {
    console.log(package.name, "v" + package.version, "started.");

    initRFIDReader();
    initRelais();
    startWeb();
  }());
}

function exit(err) {
  if ( err ) {
    console.log("Unhandled Error:", err.stack);
  } else {
    console.log("Exiting...");
  }
  if ( rfidReader.isOpen ) {
    rfidReader.close();
  }
  if ( relais.isOpen ) {
    relais.close();
  }

  web.stop();

  // Done
  console.log("Bye!");
  // won't exit otherwise
  process.kill();
}
process.on('SIGINT', exit);
if ( process.env.NODE_ENV !== 'development' ) {
  process.on('exit', exit);
  process.on('uncaughtException', exit);
}
<commit_msg>Fixed typo.<commit_after>/**
 * Main application module.
 * Project started: 16.03.2014 - 00:21
 * @module app
 * @author Sören Gade
 *
 * @requires config
 * @requires web/index
 * @requires io/rfidreader
 * */

require('./log-replace')();
var package = require('../package');
var config = require('./config');
var web = require('./web/');
var RFIDReader = require('./io/rfidreader');
var Relais = require('./io/relais');
var db = require('./db/');

/* ==========
 * Globals
 * ==========
 * */
var rfidReader = null;
var relais = null;

/* ==========
 * Init
 * ==========
 * */
/**
 * Starts the webserver.
 * */
function startWeb() {
  var port = config.web.port;

  if(typeof PhusionPassenger !== 'undefined') {
    PhusionPassenger.configure({ autoInstall: false });
    port = 'passenger';
  }

  web.init(port, web_RFIDRequest, web_OpenDoor, function() {
    web.start(function() {
      console.log("Web interface running on port " + web.getPort() + ".");
    });
  });
}
// callbacks for web requests
function web_RFIDRequest(callback) {
  rfidReader.on('data', function(data) {
    callback(data);
  });
}
function web_OpenDoor(callback) {
  console.log("Opening door...");

  openDoor(callback);
}

/**
 * Initializes the connection with the RFID reader.
 * */
function initRFIDReader() {
  var port = config.port.rfid;
  if ( !port ) {
    console.log("Please set the rfidreader port in the config.");
    return;
  }

  // create new instance
  rfidReader = new RFIDReader(port);

  // add event listeners
  rfidReader.on('data', function(data) {
    data = data.toString();
    console.log("Data by RFID reader:", data);

    db.Card.find({
      where: {
        uid: data
      }
    }).success(function(card) {
      if ( !card ) {
        console.log("No card found.");

        // switch yellow off, red on
        relais.setSingle(config.relaisport.red, function(err) {
          relais.setSingle(config.relaisport.yellow, function(err) {

            setTimeout(function() {
              // switch yellow on, red off
              relais.delSingle(config.relaisport.red, function(err) {
                relais.delSingle(config.relaisport.yellow);
              });
            }, 1500);
          });
        });
      } else {
        console.log("Card found.");
        card.getUser().success(function(user) {
          if ( !user ) {
            console.log("no user found");
          } else {
            console.log("user is", user.username);

            openDoor(function(err) {
              if ( !!err ) {
                console.log("Error opening door:", err);
                return;
              }

              console.log("Door had been opened.");
            });
          }
        });
      }
    });
  });

  // open connection
  rfidReader.open(function(err) {
    if ( !!err ) {
      console.log("Error opening connection to rfid reader:", err);
    } else {
      console.log("Connection to RFID reader opened (" + port + ").");
    }
  });
}
/**
 * Initializes the connection with the relais card.
 * */
function initRelais() {
  var port = config.port.relais;
  if ( !port ) {
    console.log("Please set the relais card port in the config.");
    return;
  }

  relais = new Relais(port);

  relais.open(function(err) {
    if ( !!err ) {
      console.log("Error opening connection to relais card:", err);
    } else {
      relais.setup(function(err, ok) {
        if ( !!err ) {
          console.log("Error setting up relais card:", err);
        } else {
          if ( !ok ) {
            console.log("Could not open connection to relais card.");
          } else {
            console.log("Connection to relais card opened (" + port + ").");

            relais.deactivateAll();
          }
        }
      });
    }
  });
}

function openDoor(callback) {
  // TODO: Try out if it really works in real environments
  relais.setSingle(config.relaisport.door, function(err) {
    if ( !!err ) {
      console.log("Error opening the door:", err);
      return callback(err);
    }

    // switch green on, yellow off
    relais.setSingle(conig.relaisport.green, function(err) {
      relais.setSingle(config.relaisport.yellow);
    });

    setTimeout(function() {
      relais.delSingle(config.relaisport.door, function(err) {
        if ( !!err ) {
          console.log("Door could not be closed!");
          return callback(err);
        }

        // switch green off, yellow on
        relais.delSingle(config.relaisport.green, function(err) {
          relais.delSingle(config.relaisport.yellow);
        });

        console.log("Door closed.");
        return callback(null);
      });
    }, config.web.doorOpenTime);

  });
}

if ( !module.parent || typeof PhusionPassenger !== 'undefined') {
  /**
   * The main application entry point.
   * */
  (function main() {
    console.log(package.name, "v" + package.version, "started.");

    initRFIDReader();
    initRelais();
    startWeb();
  }());
}

function exit(err) {
  if ( err ) {
    console.log("Unhandled Error:", err.stack);
  } else {
    console.log("Exiting...");
  }
  if ( rfidReader.isOpen ) {
    rfidReader.close();
  }
  if ( relais.isOpen ) {
    relais.close();
  }

  web.stop();

  // Done
  console.log("Bye!");
  // won't exit otherwise
  process.kill();
}
process.on('SIGINT', exit);
if ( process.env.NODE_ENV !== 'development' ) {
  process.on('exit', exit);
  process.on('uncaughtException', exit);
}
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const serveStatic = require('feathers').static;
const favicon = require('serve-favicon');
const compress = require('compression');
const cors = require('cors');
const feathers = require('feathers');
const configuration = require('feathers-configuration');
const hooks = require('feathers-hooks');
const rest = require('feathers-rest');
const bodyParser = require('body-parser');
const socketio = require('feathers-socketio');
const middleware = require('./middleware');
const services = require('./services');

const mongoose = require('mongoose');

// const {routes} = require('../public/gyps/routes.jsx');
// const React = require('react');
// const { renderToString } = require('react-dom/server');
// const { match, RouterContext } = require('react-router');

const gypsing = function (request, response, next) {
  const url = request.originalUrl;
  if(url.indexOf('/auth') < 0 && url.indexOf('.') < 0) {
    console.log("Re-Routing ", request.originalUrl);
    return response.sendFile(path.resolve(__dirname, app.get('public') , 'index.html'))
  } else {
    // console.log("Nexting ", url);
    return next();
  }
};

const app = feathers();

app.configure(configuration(path.join(__dirname, '..')));

mongoose.Promise = global.Promise;
mongoose.connect(app.get('mongoose'));

app.use(compress())
  .options('*', cors())
  .use(cors())
  // .use(favicon( path.join(app.get('public'), 'favicon.ico') ))
.get('/auth/success', (req, res, next) => {
  // console.log("\nZ\nZ\nZ\nZ\nZ\nZ\nZ\n\nNexting", next)
  // console.log("\n\n\n\n\n\n\n\n\nNexted", next)
  console.log("==== Response: ", res)
  res.sendFile(path.resolve(__dirname, app.get('public') , 'index.html'))
  next()
})
  .get('*', gypsing)
  .use('/', serveStatic( app.get('public') ))
  .use(bodyParser.json())
  .use(bodyParser.urlencoded({ extended: true }))
  .configure(hooks())
  .configure(rest())
  .configure(socketio())
  .configure(services)
  .configure(middleware);
// app.get('*', (req, res) => {
//   // match the routes to the url
//   match({ routes: routes, location: req.url }, (err, redirect, props) => {
//     // `RouterContext` is what the `Router` renders. `Router` keeps these
//     // `props` in its state as it listens to `browserHistory`. But on the
//     // server our app is stateless, so we need to use `match` to
//     // get these props before rendering.
//     const appHtml = renderToString(React.createElement("RouterContext", props))

//     // dump the HTML into a template, lots of ways to do this, but none are
//     // really influenced by React Router, so we're just using a little
//     // function, `renderPage`
//     res.send(renderPage(appHtml))
//   })
// })

// function renderPage(appHtml) {
//   return `
//     <!doctype html public="storage">
//
//     <meta charset="utf-8" />
//     <title>BFest Router App</title>

//     <link rel="shortcut icon" href="/img/favicon.ico" />
//     <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&subset=cyrillic" rel="stylesheet" />
//     <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
//     <link rel="stylesheet" href="/gyps/bundle/main.css" />
//
${appHtml}

//
//    `
// }

module.exports = app;
<commit_msg>Still fixin fb auth<commit_after>'use strict';

const path = require('path');
const serveStatic = require('feathers').static;
const favicon = require('serve-favicon');
const compress = require('compression');
const cors = require('cors');
const feathers = require('feathers');
const configuration = require('feathers-configuration');
const hooks = require('feathers-hooks');
const rest = require('feathers-rest');
const bodyParser = require('body-parser');
const socketio = require('feathers-socketio');
const middleware = require('./middleware');
const services = require('./services');

const mongoose = require('mongoose');

// const {routes} = require('../public/gyps/routes.jsx');
// const React = require('react');
// const { renderToString } = require('react-dom/server');
// const { match, RouterContext } = require('react-router');

const gypsing = function (request, response, next) {
  const url = request.originalUrl;
  if(url.indexOf('/auth') < 0 && url.indexOf('.') < 0) {
    console.log("Re-Routing ", request.originalUrl);
    return response.sendFile(path.resolve(__dirname, app.get('public') , 'index.html'))
  } else {
    // console.log("Nexting ", url);
    return next();
  }
};

const app = feathers();

app.configure(configuration(path.join(__dirname, '..')));

mongoose.Promise = global.Promise;
mongoose.connect(app.get('mongoose'));

app.use(compress())
  .options('*', cors())
  .use(cors())
  // .use(favicon( path.join(app.get('public'), 'favicon.ico') ))
// .get('/auth/success', (req, res, next) => {
//   // console.log("\nZ\nZ\nZ\nZ\nZ\nZ\nZ\n\nNexting", next)
//   // console.log("\n\n\n\n\n\n\n\n\nNexted", next)
//   console.log("==== Response: ", res)
//   res.sendFile(path.resolve(__dirname, app.get('public') , 'index.html'))
//   next()
// })
  .get('*', gypsing)
  .use('/', serveStatic( app.get('public') ))
  .use(bodyParser.json())
  .use(bodyParser.urlencoded({ extended: true }))
  .configure(hooks())
  .configure(rest())
  .configure(socketio())
  .configure(services)
  .configure(middleware);
// app.get('*', (req, res) => {
//   // match the routes to the url
//   match({ routes: routes, location: req.url }, (err, redirect, props) => {
//     // `RouterContext` is what the `Router` renders. `Router` keeps these
//     // `props` in its state as it listens to `browserHistory`. But on the
//     // server our app is stateless, so we need to use `match` to
//     // get these props before rendering.
//     const appHtml = renderToString(React.createElement("RouterContext", props))

//     // dump the HTML into a template, lots of ways to do this, but none are
//     // really influenced by React Router, so we're just using a little
//     // function, `renderPage`
//     res.send(renderPage(appHtml))
//   })
// })

// function renderPage(appHtml) {
//   return `
//     <!doctype html public="storage">
//
//     <meta charset="utf-8" />
//     <title>BFest Router App</title>

//     <link rel="shortcut icon" href="/img/favicon.ico" />
//     <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&subset=cyrillic" rel="stylesheet" />
//     <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
//     <link rel="stylesheet" href="/gyps/bundle/main.css" />
//
${appHtml}

//
//    `
// }

module.exports = app;
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {

	/**
	 * @class OCA.Files.DetailTabView
	 * @classdesc
	 *
	 * Base class for tab views to display file information.
	 *
	 */
	var DetailTabView = OC.Backbone.View.extend({
		tag: 'div',

		className: 'tab',

		/**
		 * Tab label
		 */
		_label: null,

		_template: null,

		initialize: function() {
			if (!this.id) {
				this.id = 'detailTabView' + DetailTabView._TAB_COUNT;
				DetailTabView._TAB_COUNT++;
			}
		},

		/**
		 * Returns the tab label
		 *
		 * @return {String} label
		 */
		getLabel: function() {
			return 'Tab ' + this.id;
		},

		/**
		 * returns the jQuery object for HTML output
		 *
		 * @returns {jQuery}
		 */
		get$: function() {
			return this.$el;
		},

		/**
		 * Renders this details view
		 *
		 * @abstract
		 */
		render: function() {
			// to be implemented in subclass
			// FIXME: code is only for testing
			this.$el.html('
Hello ' + this.id + '
');
		},

		/**
		 * Sets the file info to be displayed in the view
		 *
		 * @param {OCA.Files.FileInfoModel} fileInfo file info to set
		 */
		setFileInfo: function(fileInfo) {
			if (this.model !== fileInfo) {
				this.model = fileInfo;
				this.render();
			}
		},

		/**
		 * Returns the file info.
		 *
		 * @return {OCA.Files.FileInfoModel} file info
		 */
		getFileInfo: function() {
			return this.model;
		}
	});
	DetailTabView._TAB_COUNT = 0;

	OCA.Files.DetailTabView = DetailTabView;
})();

<commit_msg>Add namespace in case the file is loaded individually<commit_after>/*
 * Copyright (c) 2015
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {

	/**
	 * @class OCA.Files.DetailTabView
	 * @classdesc
	 *
	 * Base class for tab views to display file information.
	 *
	 */
	var DetailTabView = OC.Backbone.View.extend({
		tag: 'div',

		className: 'tab',

		/**
		 * Tab label
		 */
		_label: null,

		_template: null,

		initialize: function() {
			if (!this.id) {
				this.id = 'detailTabView' + DetailTabView._TAB_COUNT;
				DetailTabView._TAB_COUNT++;
			}
		},

		/**
		 * Returns the tab label
		 *
		 * @return {String} label
		 */
		getLabel: function() {
			return 'Tab ' + this.id;
		},

		/**
		 * returns the jQuery object for HTML output
		 *
		 * @returns {jQuery}
		 */
		get$: function() {
			return this.$el;
		},

		/**
		 * Renders this details view
		 *
		 * @abstract
		 */
		render: function() {
			// to be implemented in subclass
			// FIXME: code is only for testing
			this.$el.html('
Hello ' + this.id + '
');
		},

		/**
		 * Sets the file info to be displayed in the view
		 *
		 * @param {OCA.Files.FileInfoModel} fileInfo file info to set
		 */
		setFileInfo: function(fileInfo) {
			if (this.model !== fileInfo) {
				this.model = fileInfo;
				this.render();
			}
		},

		/**
		 * Returns the file info.
		 *
		 * @return {OCA.Files.FileInfoModel} file info
		 */
		getFileInfo: function() {
			return this.model;
		}
	});
	DetailTabView._TAB_COUNT = 0;

	OCA.Files = OCA.Files || {};

	OCA.Files.DetailTabView = DetailTabView;
})();

<|endoftext|>


<commit_before>import luyou from 'luyou';

import './styles/global.css';

import { home } from './pages/home';
import { about } from './pages/about';
import { contact } from './pages/contact';
import { error } from './pages/error';

import firebaseConfig from './assets/datas/firebase.config.json';

firebase.initializeApp(firebaseConfig);

/*if ('serviceWorker' in navigator) {
  navigator.serviceWorker
    .register('service-worker.js')
    .then((registration) => {
      console.log('Service Worker Registered.');

      registration.onupdatefound = () => {
        if (navigator.serviceWorker.controller) {
          let installingWorker = registration.installing;

          installingWorker.onstatechange = () => {
            switch (installingWorker.state) {
              case 'installed':
                if (navigator.serviceWorker.controller) {
                  // New or updated content is available.
                } else {
                  // Content is now available offline!
                }
                break;
              case 'redundant':
                throw new Error('The installing service worker became redundant.');
            }
          };
        }
      };
    });
}*/

home();
about();
contact();
error();
luyou();
<commit_msg>444th Commit<commit_after>import luyou from 'luyou';

import './styles/global.css';

import { home } from './pages/home';
import { about } from './pages/about';
import { contact } from './pages/contact';
import { error } from './pages/error';

import firebaseConfig from './assets/datas/firebase.config.json';

firebase.initializeApp(firebaseConfig);

if ('serviceWorker' in navigator && window.location.protocol === 'https:') {
  navigator.serviceWorker
    .register('service-worker.js')
    .then((registration) => {
      console.log('Service Worker Registered.');

      registration.onupdatefound = () => {
        if (navigator.serviceWorker.controller) {
          let installingWorker = registration.installing;

          installingWorker.onstatechange = () => {
            switch (installingWorker.state) {
              case 'installed':
                if (navigator.serviceWorker.controller) {
                  // New or updated content is available.
                } else {
                  // Content is now available offline!
                }
                break;
              case 'redundant':
                throw new Error('The installing service worker became redundant.');
            }
          };
        }
      };
    });
}

home();
about();
contact();
error();
luyou();
<|endoftext|>


<commit_before>const Commando = require('discord.js-commando')
const CommunityManager = require('./community/community-manager')
const PostgreSQL = require('./postgresql/postgresql')
const SequelizeProvider = require('./postgresql/sequelize-provider')

const path = require('path')
const winston = require('winston')

const config = require('/data/config.json')

winston.level = config.logLevel
String.prototype.capitalizeFirstLetter = function() { return this.charAt(0).toUpperCase() + this.slice(1) }

const client = new Commando.Client({ owner: config.owner, commandPrefix: config.prefix })
    .on('debug', winston.debug)
    .on('warn', winston.warn)
    .on('error', winston.error)
    .on('disconnect', event => { winston.warn(`Disconnected [${event.code}]: ${event.reason || 'Unknown reason'}.`) })
    .on('reconnecting', () => { winston.info('Reconnecting...') })
    .on('guildCreate', guild => { winston.verbose(`Joined guild ${guild.name}.`) })
    .on('guildDelete', guild => { winston.verbose(`Departed guild ${guild.name}.`) })
    .on('ready', () => {
        CommunityManager.start()
        client.user.setGame('Hearthstone')
        winston.info(`Client ready. Currently in ${client.guilds.size} guilds.`)
    })

const postgresql = new PostgreSQL(config.database)
postgresql.init()
client.setProvider(new SequelizeProvider(postgresql.db)).catch(winston.error)

client.registry
    .registerDefaultTypes()
    .registerGroups([
        ['card', 'Card Information'],
        ['community', 'Community']
    ])
    .registerDefaultGroups()
    .registerCommandsIn(path.join(__dirname, 'commands'))
    .registerDefaultCommands({ eval_: false })

client.login(config.token)
<commit_msg>Add a bunch of logging<commit_after>const Commando = require('discord.js-commando')
const CommunityManager = require('./community/community-manager')
const PostgreSQL = require('./postgresql/postgresql')
const SequelizeProvider = require('./postgresql/sequelize-provider')

const path = require('path')
const winston = require('winston')

const config = require('/data/config.json')

winston.level = config.logLevel
String.prototype.capitalizeFirstLetter = function() { return this.charAt(0).toUpperCase() + this.slice(1) }

const client = new Commando.Client({ owner: config.owner, commandPrefix: config.prefix })
    .on('debug', winston.debug)
    .on('warn', winston.warn)
    .on('error', winston.error)
    .on('disconnect', event => { winston.warn(`Disconnected [${event.code}]: ${event.reason || 'Unknown reason'}.`) })
    .on('reconnecting', () => { winston.info('Reconnecting...') })
    .on('guildCreate', guild => { winston.verbose(`Joined guild ${guild.name}.`) })
    .on('guildDelete', guild => { winston.verbose(`Departed guild ${guild.name}.`) })
    .on('commandBlocked', (msg, reason) => {
        winston.info(
            `Command ${msg.command ? `${msg.command.groupID}:${msg.command.memberName}` : ''} blocked.` +
            ` User: ${msg.author.username}#${msg.author.discriminator}. Reason: ${reason}.`
        )
    })
    .on('commandError', (command, error) => {
        if (error instanceof Commando.FriendlyError) { return }
        winston.error(`Error in command ${command.groupID}:${command.memberName}`, error)
    })
    .on('commandPrefixChange', (guild, prefix) => {
        winston.info(`Prefix changed to ${prefix || 'the default'} ${guild ? `in guild ${guild.name}` : 'globally'}.`)
    })
    .on('commandRun', (command, promise, msg, args) => {
        winston.verbose(
            `${command.groupID}:${command.memberName} run by ${msg.author.username}#${msg.author.discriminator}` +
            ` in ${msg.guild ? `${msg.guild.name}` : 'DM'}.${Object.values(args)[0] !== '' ? ` Arguments: ${Object.values(args)}` : ''}.`)
    })
    .on('commandStatusChange', (guild, command, enabled) => {
        winston.info(`Command ${command.groupID}:${command.memberName} ${enabled ? 'enabled' : 'disabled'} ${guild ? `in guild ${guild.name}` : 'globally'}.`)
    })
    .on('groupStatusChange', (guild, group, enabled) => {
        winston.info(`Group ${group.id} ${enabled ? 'enabled' : 'disabled'} ${guild ? `in guild ${guild.name}` : 'globally'}.`)
    })
    .on('ready', () => {
        CommunityManager.start()
        client.user.setGame('Hearthstone')
        winston.info(`Client ready. Currently in ${client.guilds.size} guilds.`)
    })

const postgresql = new PostgreSQL(config.database)
postgresql.init()
client.setProvider(new SequelizeProvider(postgresql.db)).catch(winston.error)

client.registry
    .registerDefaultTypes()
    .registerGroups([
        ['card', 'Card Information'],
        ['community', 'Community']
    ])
    .registerDefaultGroups()
    .registerCommandsIn(path.join(__dirname, 'commands'))
    .registerDefaultCommands({ eval_: false })

client.login(config.token)
<|endoftext|>


<commit_before>'use strict'

// === WATERWHEEL ===
const { spawn } = require('child_process')
const globby = require('globby')

// mostly for instanceof checks inside task
class File {
  constructor(value) {
    this.value = value
  }
}

const task = (props, cb) => (next) => () => {
  console.log('Starting a task')
  let { input, output } = props

  // TODO recursively traverse object
  // TODO use generators to yield Promises to be cleaner
  if (input instanceof File) {
    // If we got special classes as input, they are either stdin or files,
    // so we need to resolve the pattern
    globby(input.value)
      .then((data) => {
        // TODO unhardcoded to one file
        props.input = data[0]
        return ready()
      })
  } else if (input instanceof Array && input[0] instanceof File) {
    input = input.map(file => file.value)
    globby(input).then((data) => {
      console.log(data)
      props.input = data
      return ready()
    })
  } else {
    return ready()
  }

  function ready() {
    const stream = cb(props)

    let ended = false

    const handleFinish = () => {
      if (!ended) {
        ended = true
      } else {
        // Don't start shell process more than once
        return null
      }

      let length = 1

      if (typeof(output) === 'string') {
        length = 1
      } else if (output instanceof File) {
        output = output.value
        length = 1
      } else if (output instanceof Array && output[0] instanceof File) {
        output = output.map(file => file.value)
        length = output.length
      }

      globby(output).then((data) => {
        console.log('Wanted: ')
        console.log(output)
        console.log(data.length === length ? 'File(s) produced as expected: ' : 'File(s) not created: ')
        console.log(data)
        next()
      })
    }

    // Check current dir for files matching the pattern provided to the task
    // Then call next task in the pipeline with the resolved files
    stream.on('end', handleFinish)
    // fs.createWriteStream throws finish
    stream.on('finish', handleFinish)
    // bash processes
    stream.on('close', handleFinish)

    return stream
  }
}

function join(...tasks) {
  // hack to work for parallel
  if (tasks[0] instanceof Array) {
    tasks = tasks[0]
  }

  // return tasks.reduceRight((prev, curr) => curr(prev()))
  let result = tasks[tasks.length-1]()
  for (let i=tasks.length-2; i>=0; i--) {
    result = tasks[i](result)
  }
  return result

  // return tasks[0](tasks[1](tasks[2]()))
  // // return tasks.reduce( (prev, curr) => prev(curr()) )
  // return tasks.reduce((prev, curr, index, arr) => {
  //   console.log(prev)
  //   console.log(curr)
  //   console.log(index)
  //   return prev(curr())
  // })
  // combined({}, () => console.log('after'))
}

function parallel({ taskLists, next }) {
  let max = taskLists.length
  let count = 0

  function after() {
    return task(
    {
      input: null,
      output: null
    },
    () => {
      count++
      if (count === max) {
        console.log('PARALLEL FINISHED')
        next()()
      }
    }
    )()
  }

  const joinedTasks = []

  taskLists.forEach(taskList => {
    taskList.push(after)
    joinedTasks.push(join(taskList))
  })

  // Start parallel tasks
  return () => {
    joinedTasks.forEach(task => task())
  }
}

const shell = (cmd, opts = {}) => {
  console.log('Starting: ' + cmd)
  cmd = cmd.split(' ')

  const process = spawn(cmd[0], cmd.slice(1), Object.assign(opts, { shell: true }))

  process.stdout.on('data', (data) => console.log(`stdout: ${data}`) )

  process.stderr.on('data', (data) => console.log(`stderr: ${data}`) )

  process.on('close', (code) => console.log(`child process exited with code ${code}`) )

  return process
}

// === UTILS ===
const last = (str, sep) => {
  const splitted = str.split(sep)
  return splitted[splitted.length - 1]
}

// === PIPELINE ===
const fs = require('fs')
const ncbi = require('bionode-ncbi')
const request = require('request')

const THREADS = 4
const config = {
  sraAccession: '2492428',
  referenceURL: 'http://ftp.ncbi.nlm.nih.gov/genomes/all/GCA_000988525.2_ASM98852v2/GCA_000988525.2_ASM98852v2_genomic.fna.gz'
}

// thunk'it here or inside task?
// const/let does not get hoisted, and it is unnatural to describe pipelines
// in reverse order:
// const task2 = task(...)
// const task1 = task(,,task2)
// functions do get hoisted, but then we have a somewhat less pretty indented
// return task(...) boilerplate

// const samples = task(...)
// const samples = () => task(...)
function samples(next) {
  // task(props, cb)(next)
  return task(
    // these params are then made available to the cb
    {
      input: {
        db: 'sra',
        accession: config.sraAccession
      },
      // will be globby'ed after cb completes
      output: '**/*.sra'
    },
    // the cb for this task
    ( ({ input }) => ncbi.download(input.db, input.accession) )
  )(next)
}

function fastqDump(next) {
  return task(
  {
    input: new File('**/*.sra'),
    output: [1, 2].map(n => new File(`*_${n}.fastq.gz`))
  },
  ({ input }) => shell(`fastq-dump --split-files --skip-technical --gzip ${input}`)
)(next)
}

function downloadReference(next) {
  return task(
  {
    input: config.referenceURL,
    output: new File(last(config.referenceURL, '/'))
  },
  ({ input, output }) => request(input).pipe(fs.createWriteStream(output.value))
  )(next)
}

function bwaIndex(next) {
  return task(
  {
    input: new File('*_genomic.fna.gz'),
    output: ['amb', 'ann', 'bwt', 'pac', 'sa'].map(suffix => new File(`*_genomic.fna.gz.${suffix}`))
  },
  ({ input }) => shell(`bwa index ${input}`)
  )(next)
}

function alignAndSort(next) {
  return task(
  {
    input: [new File('*_genomic.fna.gz'), new File('*.fastq.gz')],
    output: new File('reads.bam')
  },
  ({ input }) => shell(`
bwa mem -t ${THREADS} ${input[0]} ${input[1]} ${input[2]} | \
samtools view -Sbh - | \
samtools sort - -o reads.bam `)
  )(next)
}

function samtoolsIndex(next) {
  return task(
  {
    input: new File('*.bam'),
    output: new File('*.bam.bai')
  },
  ({ input }) => shell(`samtools index ${input}`)
  )(next)
}

function decompressReference(next) {
  return task(
  {
    input: new File('*_genomic.fna.gz'),
    output: new File('*_genomic.fna')
  },
  ({ input }) => shell(`bgzip -d ${input}`)
  )(next)
}

function mpileupAndCall(next) {
  return task(
  {
    input: [new File('*_genomic.fna'), new File('*.bam'), new File('*.bam.bai')],
    output: new File('variants.vcf')
  },
  ({ input }) => shell(`
samtools mpileup -uf ${input[0]} ${input[1]} | \
bcftools call -c - > variants.vcf
    `)
  )(next)
}

// function after(next) {
//   return task(
//   {
//     input: null,
//     output: null
//   },
//   () => shell('echo AFTER')
//   )(next)
// }

const pipeline = parallel({
  taskLists: [[samples], [downloadReference, bwaIndex]],
  next: join(alignAndSort, samtoolsIndex, decompressReference, mpileupAndCall)
})
pipeline()
<commit_msg>shellPipe for piping between child processes w/o shell:true<commit_after>'use strict'

// === WATERWHEEL ===
const { spawn } = require('child_process')
const globby = require('globby')

// mostly for instanceof checks inside task
class File {
  constructor(value) {
    this.value = value
  }
}

const task = (props, cb) => (next) => () => {
  console.log('Starting a task')
  let { input, output } = props

  // TODO recursively traverse object
  // TODO use generators to yield Promises to be cleaner
  if (input instanceof File) {
    // If we got special classes as input, they are either stdin or files,
    // so we need to resolve the pattern
    globby(input.value)
      .then((data) => {
        // TODO unhardcoded to one file
        props.input = data[0]
        return ready()
      })
  } else if (input instanceof Array && input[0] instanceof File) {
    input = input.map(file => file.value)
    globby(input).then((data) => {
      console.log(data)
      props.input = data
      return ready()
    })
  } else {
    return ready()
  }

  function ready() {
    const stream = cb(props)

    let ended = false

    const handleFinish = () => {
      if (!ended) {
        ended = true
      } else {
        // Don't start shell process more than once
        return null
      }

      let length = 1

      if (typeof(output) === 'string') {
        length = 1
      } else if (output instanceof File) {
        output = output.value
        length = 1
      } else if (output instanceof Array && output[0] instanceof File) {
        output = output.map(file => file.value)
        length = output.length
      }

      globby(output).then((data) => {
        console.log('Wanted: ')
        console.log(output)
        console.log(data.length === length ? 'File(s) produced as expected: ' : 'File(s) not created: ')
        console.log(data)
        next()
      })
    }

    // Check current dir for files matching the pattern provided to the task
    // Then call next task in the pipeline with the resolved files
    stream.on('end', handleFinish)
    // fs.createWriteStream throws finish
    stream.on('finish', handleFinish)
    // bash processes
    stream.on('close', handleFinish)

    return stream
  }
}

function join(...tasks) {
  // hack to work for parallel
  if (tasks[0] instanceof Array) {
    tasks = tasks[0]
  }

  // return tasks.reduceRight((prev, curr) => curr(prev()))
  let result = tasks[tasks.length-1]()
  for (let i=tasks.length-2; i>=0; i--) {
    result = tasks[i](result)
  }
  return result

  // return tasks[0](tasks[1](tasks[2]()))
  // // return tasks.reduce( (prev, curr) => prev(curr()) )
  // return tasks.reduce((prev, curr, index, arr) => {
  //   console.log(prev)
  //   console.log(curr)
  //   console.log(index)
  //   return prev(curr())
  // })
  // combined({}, () => console.log('after'))
}

function parallel({ taskLists, next }) {
  let max = taskLists.length
  let count = 0

  function after() {
    return task(
    {
      input: null,
      output: null
    },
    () => {
      count++
      if (count === max) {
        console.log('PARALLEL FINISHED')
        next()()
      }
    }
    )()
  }

  const joinedTasks = []

  taskLists.forEach(taskList => {
    taskList.push(after)
    joinedTasks.push(join(taskList))
  })

  // Start parallel tasks
  return () => {
    joinedTasks.forEach(task => task())
  }
}

const shell = (cmd, opts = {}) => {
  console.log('Starting: ' + cmd)
  cmd = cmd.split(' ')

  const process = spawn(cmd[0], cmd.slice(1), Object.assign(opts, { shell: true }))

  process.stdout.on('data', (data) => console.log(`stdout: ${data}`) )

  process.stderr.on('data', (data) => console.log(`stderr: ${data}`) )

  process.on('close', (code) => console.log(`child process exited with code ${code}`) )

  return process
}

const shellPipe = (cmds) => {
  const processes = cmds.map((cmd, i) => {
    console.log('Starting: ' + cmd)
    cmd = cmd.split(' ')
    // needs shell:true for bcftools call > variant.vcf to work
    const process = spawn(cmd[0], cmd.slice(1), { shell: true })

    process.stderr.on('data', (data) => console.log(`stderr-${i}: ${data}`) )

    process.on('close', (code) => console.log(`child process-${i} exited with code ${code}`) )

    return process
  })

  for (let i=0; i < processes.length-1; i++) {
    const current = processes[i]
    const next = processes[i+1]

    current.stdout.on('data', data => next.stdin.write(data))
    current.on('close', () => next.stdin.end())
  }

  return processes[processes.length-1]
}

// === UTILS ===
const last = (str, sep) => {
  const splitted = str.split(sep)
  return splitted[splitted.length - 1]
}

// === PIPELINE ===
const fs = require('fs')
const ncbi = require('bionode-ncbi')
const request = require('request')

const THREADS = 4
const config = {
  sraAccession: '2492428',
  referenceURL: 'http://ftp.ncbi.nlm.nih.gov/genomes/all/GCA_000988525.2_ASM98852v2/GCA_000988525.2_ASM98852v2_genomic.fna.gz'
}

// const samples = task(...)
// const samples = () => task(...)
function samples(next) {
  // task(props, cb)(next)
  return task(
    // these params are then made available to the cb
    {
      input: {
        db: 'sra',
        accession: config.sraAccession
      },
      // will be globby'ed after cb completes
      output: '**/*.sra'
    },
    // the cb for this task
    ( ({ input }) => ncbi.download(input.db, input.accession) )
  )(next)
}

function fastqDump(next) {
  return task(
  {
    input: new File('**/*.sra'),
    output: [1, 2].map(n => new File(`*_${n}.fastq.gz`))
  },
  ({ input }) => shell(`fastq-dump --split-files --skip-technical --gzip ${input}`)
)(next)
}

function downloadReference(next) {
  return task(
  {
    input: config.referenceURL,
    output: new File(last(config.referenceURL, '/'))
  },
  ({ input, output }) => request(input).pipe(fs.createWriteStream(output.value))
  )(next)
}

function bwaIndex(next) {
  return task(
  {
    input: new File('*_genomic.fna.gz'),
    output: ['amb', 'ann', 'bwt', 'pac', 'sa'].map(suffix => new File(`*_genomic.fna.gz.${suffix}`))
  },
  ({ input }) => shell(`bwa index ${input}`)
  )(next)
}

function alignAndSort(next) {
  return task(
  {
    input: [new File('*_genomic.fna.gz'), new File('*.fastq.gz')],
    output: new File('reads.bam')
  },
  ({ input }) => shellPipe([
    `bwa mem -t ${THREADS} ${input[0]} ${input[1]} ${input[2]}`,
    'samtools view -Sbh -',
    'samtools sort - -o reads.bam'
  ])
  )(next)
}

function samtoolsIndex(next) {
  return task(
  {
    input: new File('*.bam'),
    output: new File('*.bam.bai')
  },
  ({ input }) => shell(`samtools index ${input}`)
  )(next)
}

function decompressReference(next) {
  return task(
  {
    input: new File('*_genomic.fna.gz'),
    output: new File('*_genomic.fna')
  },
  ({ input }) => shell(`bgzip -d ${input}`)
  )(next)
}

function mpileupAndCall(next) {
  return task(
  {
    input: [new File('*_genomic.fna'), new File('*.bam'), new File('*.bam.bai')],
    output: new File('variants.vcf')
  },
  ({ input }) => shellPipe([
    `samtools mpileup -uf ${input[0]} ${input[1]}`,
    'bcftools call -c - > variants.vcf'
  ])
  )(next)
}

// function after(next) {
//   return task(
//   {
//     input: null,
//     output: null
//   },
//   () => shell('echo AFTER')
//   )(next)
// }

const pipeline = parallel({
  taskLists: [[samples], [downloadReference, bwaIndex]],
  // next: alignAndSort
  next: join(alignAndSort, samtoolsIndex, decompressReference, mpileupAndCall)
})
pipeline()
<|endoftext|>