<commit_before>// An html parser written in JavaScript
// Based on http://ejohn.org/blog/pure-javascript-html-parser/

(function() {
  var supports = (function() {
    var supports = {};

    var html;
    var work = this.document.createElement('div');

    html = "

";
    work.innerHTML = html;
    supports.tagSoup = work.innerHTML !== html;

    work.innerHTML = "

";
    supports.selfClose = work.childNodes.length === 2;

    return supports;
  })();

  // Regular Expressions for parsing tags and attributes
  var startTag = /^<([\-A-Za-z0-9_]+)((?:\s+[\w\-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
  var endTag = /^<\/([\-A-Za-z0-9_]+)[^>]*>/;
  var attr = /([\-A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
  var fillAttr = /^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noresize|noshade|nowrap|readonly|selected)$/i;

  var DEBUG = false;

  function htmlParser(stream, options) {
    stream = stream || '';

    // Options
    options = options || {};

    for(var key in supports) {
      if(supports.hasOwnProperty(key)) {
        if(options.autoFix) {
          options['fix_'+key] = true;//!supports[key];
        }
        options.fix = options.fix || options['fix_'+key];
      }
    }

    var stack = [];

    var append = function(str) {
      stream += str;
    };

    var prepend = function(str) {
      stream = str + stream;
    };

    // Order of detection matters: detection of one can only
    // succeed if detection of previous didn't
    var detect = {
      comment: /^");
        if ( index >= 0 ) {
          return {
            content: stream.substr(4, index),
            length: index + 3
          };
        }
      },

      endTag: function() {
        var match = stream.match( endTag );

        if ( match ) {
          return {
            tagName: match[1],
            length: match[0].length
          };
        }
      },

      atomicTag: function() {
        var start = reader.startTag();
        if(start) {
          var rest = stream.slice(start.length);
          // for optimization, we check first just for the end tag
          if(rest.match(new RegExp("<\/\\s*" + start.tagName + "\\s*>", "i"))) {
            // capturing the content is inefficient, so we do it inside the if
            var match = rest.match(new RegExp("([\\s\\S]*?)<\/\\s*" + start.tagName + "\\s*>", "i"));
            if(match) {
              // good to go
              return {
                tagName: start.tagName,
                attrs: start.attrs,
                content: match[1],
                length: match[0].length + start.length
              }
            }
          }
        }
      },

      startTag: function() {
        var match = stream.match( startTag );

        if ( match ) {
          var attrs = {};

          match[2].replace(attr, function(match, name) {
            var value = arguments[2] || arguments[3] || arguments[4] ||
              fillAttr.test(name) && name || null;

            attrs[name] = value;
          });

          return {
            tagName: match[1],
            attrs: attrs,
            unary: !!match[3],
            length: match[0].length
          };
        }
      },

      chars: function() {
        var index = stream.indexOf("<");
        return {
          length: index >= 0 ? index : stream.length
        };
      }
    };

    var readToken = function() {

      // Enumerate detects in order
      for (var type in detect) {

        if(detect[type].test(stream)) {
          if(DEBUG) { console.log('suspected ' + type); }

          var token = reader[type]();
          if(token) {
            if(DEBUG) { console.log('parsed ' + type, token); }
            // Type
            token.type = token.type || type;
            // Entire text
            token.text = stream.substr(0, token.length);
            // Update the stream
            stream = stream.slice(token.length);

            return token;
          }
          return null;
        }
      }
    };

    var readTokens = function(handlers) {
      var tok;
      while(tok = readToken()) {
        // continue until we get an explicit "false" return
        if(handlers[tok.type] && handlers[tok.type](tok) === false) {
          return;
        }
      }
    };

    var clear = function() {
      var rest = stream;
      stream = '';
      return rest;
    };

    var rest = function() {
      return stream;
    };

    if(options.fix) {
      (function() {
        // Empty Elements - HTML 4.01
        var EMPTY = /^(AREA|BASE|BASEFONT|BR|COL|FRAME|HR|IMG|INPUT|ISINDEX|LINK|META|PARAM|EMBED)$/i;

        // Elements that you can| intentionally| leave open
        // (and which close themselves)
        var CLOSESELF = /^(COLGROUP|DD|DT|LI|OPTIONS|P|TD|TFOOT|TH|THEAD|TR)$/i;

        var stack = [];
        stack.last = function() {
          return this[this.length - 1];
        };
        stack.lastTagNameEq = function(tagName) {
          var last = this.last();
          return last && last.tagName &&
            last.tagName.toUpperCase() === tagName.toUpperCase();
        };

        stack.containsTagName = function(tagName) {
          for(var i = 0, tok; tok = this[i]; i++) {
            if(tok.tagName === tagName) {
              return true;
            }
          }
          return false;
        };

        var correct = function(tok) {
          if(tok && tok.type === 'startTag') {
            // unary
            tok.unary = EMPTY.test(tok.tagName) || tok.unary;
          }
          return tok;
        };

        var readTokenImpl = readToken;

        var peekToken = function() {
          var tmp = stream;
          var tok = correct(readTokenImpl());
          stream = tmp;
          return tok;
        };

        var closeLast = function() {
          var tok = stack.pop();

          // prepend close tag to stream.
          prepend('</'+tok.tagName+'>');
        };

        var handlers = {
          startTag: function(tok) {
            var tagName = tok.tagName;
            // Fix tbody
            if(tagName.toUpperCase() === 'TR' && stack.lastTagNameEq('TABLE')) {
              prepend('
');
              prepareNextToken();
            } else if(options.fix_selfClose &&
              CLOSESELF.test(tagName) &&
              stack.containsTagName(tagName)) {
                if(stack.lastTagNameEq(tagName)) {
                  closeLast();
                } else {
                  prepend('</'+tok.tagName+'>');
                  prepareNextToken();
                }
            } else if (!tok.unary) {
              stack.push(tok);
            }
          },

          endTag: function(tok) {
            var last = stack.last();
            if(last) {
              if(options.fix_tagSoup && !stack.lastTagNameEq(tok.tagName)) {
                // cleanup tag soup
                closeLast();
              } else {
                stack.pop();
              }
            } else if (options.fix_tagSoup) {
              // cleanup tag soup part 2: skip this token
              skipToken();
            }
          }
        };

        var skipToken = function() {
          // shift the next token
          readTokenImpl();

          prepareNextToken();
        };

        var prepareNextToken = function() {
          var tok = peekToken();
          if(tok && handlers[tok.type]) {
            handlers[tok.type](tok);
          }
        };

        // redefine readToken
        readToken = function() {
          prepareNextToken();
          return correct(readTokenImpl());
        };
      })();
    }

    return {
      append: append,
      readToken: readToken,
      readTokens: readTokens,
      clear: clear,
      rest: rest,
      stack: stack
    };

  }

  htmlParser.supports = supports;

  htmlParser.tokenToString = function(tok) {
    var handler = {
      comment: function(tok) {
        return '<--' + tok.content + '-->';
      },
      endTag: function(tok) {
        return '</'+tok.tagName+'>';
      },
      atomicTag: function(tok) {
        console.log(tok);
        return handler.startTag(tok) +
              tok.content +
              handler.endTag(tok);
      },
      startTag: function(tok) {
        var str = '<'+tok.tagName;
        for (var key in tok.attrs) {
          var val = tok.attrs[key];
          // escape quotes
          str += ' '+key+'="'+(val ? val.replace(/(^|[^\\])"/g, '$1\\\"') : '')+'"';
        }
        return str + (tok.unary ? '/>' : '>');
      },
      chars: function(tok) {
        return tok.text;
      }
    };
    return handler[tok.type](tok);
  };

  htmlParser.escapeAttributes = function(attrs) {
    var escapedAttrs = {};
    // escape double-quotes for writing html as a string

    for(var name in attrs) {
      var value = attrs[name];
      escapedAttrs[name] = value && value.replace(/(^|[^\\])"/g, '$1\\\"');
    }
    return escapedAttrs;
  };

  for(var key in supports) {
    htmlParser.browserHasFlaw = htmlParser.browserHasFlaw || (!supports[key]) && key;
  }

  this.htmlParser = htmlParser;
})();
<commit_msg>jshint<commit_after>// An html parser written in JavaScript
// Based on http://ejohn.org/blog/pure-javascript-html-parser/

(function() {
  var supports = (function() {
    var supports = {};

    var html;
    var work = this.document.createElement('div');

    html = "

";
    work.innerHTML = html;
    supports.tagSoup = work.innerHTML !== html;

    work.innerHTML = "

";
    supports.selfClose = work.childNodes.length === 2;

    return supports;
  })();

  // Regular Expressions for parsing tags and attributes
  var startTag = /^<([\-A-Za-z0-9_]+)((?:\s+[\w\-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
  var endTag = /^<\/([\-A-Za-z0-9_]+)[^>]*>/;
  var attr = /([\-A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
  var fillAttr = /^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noresize|noshade|nowrap|readonly|selected)$/i;

  var DEBUG = false;

  function htmlParser(stream, options) {
    stream = stream || '';

    // Options
    options = options || {};

    for(var key in supports) {
      if(supports.hasOwnProperty(key)) {
        if(options.autoFix) {
          options['fix_'+key] = true;//!supports[key];
        }
        options.fix = options.fix || options['fix_'+key];
      }
    }

    var stack = [];

    var append = function(str) {
      stream += str;
    };

    var prepend = function(str) {
      stream = str + stream;
    };

    // Order of detection matters: detection of one can only
    // succeed if detection of previous didn't
    var detect = {
      comment: /^");
        if ( index >= 0 ) {
          return {
            content: stream.substr(4, index),
            length: index + 3
          };
        }
      },

      endTag: function() {
        var match = stream.match( endTag );

        if ( match ) {
          return {
            tagName: match[1],
            length: match[0].length
          };
        }
      },

      atomicTag: function() {
        var start = reader.startTag();
        if(start) {
          var rest = stream.slice(start.length);
          // for optimization, we check first just for the end tag
          if(rest.match(new RegExp("<\/\\s*" + start.tagName + "\\s*>", "i"))) {
            // capturing the content is inefficient, so we do it inside the if
            var match = rest.match(new RegExp("([\\s\\S]*?)<\/\\s*" + start.tagName + "\\s*>", "i"));
            if(match) {
              // good to go
              return {
                tagName: start.tagName,
                attrs: start.attrs,
                content: match[1],
                length: match[0].length + start.length
              };
            }
          }
        }
      },

      startTag: function() {
        var match = stream.match( startTag );

        if ( match ) {
          var attrs = {};

          match[2].replace(attr, function(match, name) {
            var value = arguments[2] || arguments[3] || arguments[4] ||
              fillAttr.test(name) && name || null;

            attrs[name] = value;
          });

          return {
            tagName: match[1],
            attrs: attrs,
            unary: !!match[3],
            length: match[0].length
          };
        }
      },

      chars: function() {
        var index = stream.indexOf("<");
        return {
          length: index >= 0 ? index : stream.length
        };
      }
    };

    var readToken = function() {

      // Enumerate detects in order
      for (var type in detect) {

        if(detect[type].test(stream)) {
          if(DEBUG) { console.log('suspected ' + type); }

          var token = reader[type]();
          if(token) {
            if(DEBUG) { console.log('parsed ' + type, token); }
            // Type
            token.type = token.type || type;
            // Entire text
            token.text = stream.substr(0, token.length);
            // Update the stream
            stream = stream.slice(token.length);

            return token;
          }
          return null;
        }
      }
    };

    var readTokens = function(handlers) {
      var tok;
      while(tok = readToken()) {
        // continue until we get an explicit "false" return
        if(handlers[tok.type] && handlers[tok.type](tok) === false) {
          return;
        }
      }
    };

    var clear = function() {
      var rest = stream;
      stream = '';
      return rest;
    };

    var rest = function() {
      return stream;
    };

    if(options.fix) {
      (function() {
        // Empty Elements - HTML 4.01
        var EMPTY = /^(AREA|BASE|BASEFONT|BR|COL|FRAME|HR|IMG|INPUT|ISINDEX|LINK|META|PARAM|EMBED)$/i;

        // Elements that you can| intentionally| leave open
        // (and which close themselves)
        var CLOSESELF = /^(COLGROUP|DD|DT|LI|OPTIONS|P|TD|TFOOT|TH|THEAD|TR)$/i;

        var stack = [];
        stack.last = function() {
          return this[this.length - 1];
        };
        stack.lastTagNameEq = function(tagName) {
          var last = this.last();
          return last && last.tagName &&
            last.tagName.toUpperCase() === tagName.toUpperCase();
        };

        stack.containsTagName = function(tagName) {
          for(var i = 0, tok; tok = this[i]; i++) {
            if(tok.tagName === tagName) {
              return true;
            }
          }
          return false;
        };

        var correct = function(tok) {
          if(tok && tok.type === 'startTag') {
            // unary
            tok.unary = EMPTY.test(tok.tagName) || tok.unary;
          }
          return tok;
        };

        var readTokenImpl = readToken;

        var peekToken = function() {
          var tmp = stream;
          var tok = correct(readTokenImpl());
          stream = tmp;
          return tok;
        };

        var closeLast = function() {
          var tok = stack.pop();

          // prepend close tag to stream.
          prepend('</'+tok.tagName+'>');
        };

        var handlers = {
          startTag: function(tok) {
            var tagName = tok.tagName;
            // Fix tbody
            if(tagName.toUpperCase() === 'TR' && stack.lastTagNameEq('TABLE')) {
              prepend('
');
              prepareNextToken();
            } else if(options.fix_selfClose &&
              CLOSESELF.test(tagName) &&
              stack.containsTagName(tagName)) {
                if(stack.lastTagNameEq(tagName)) {
                  closeLast();
                } else {
                  prepend('</'+tok.tagName+'>');
                  prepareNextToken();
                }
            } else if (!tok.unary) {
              stack.push(tok);
            }
          },

          endTag: function(tok) {
            var last = stack.last();
            if(last) {
              if(options.fix_tagSoup && !stack.lastTagNameEq(tok.tagName)) {
                // cleanup tag soup
                closeLast();
              } else {
                stack.pop();
              }
            } else if (options.fix_tagSoup) {
              // cleanup tag soup part 2: skip this token
              skipToken();
            }
          }
        };

        var skipToken = function() {
          // shift the next token
          readTokenImpl();

          prepareNextToken();
        };

        var prepareNextToken = function() {
          var tok = peekToken();
          if(tok && handlers[tok.type]) {
            handlers[tok.type](tok);
          }
        };

        // redefine readToken
        readToken = function() {
          prepareNextToken();
          return correct(readTokenImpl());
        };
      })();
    }

    return {
      append: append,
      readToken: readToken,
      readTokens: readTokens,
      clear: clear,
      rest: rest,
      stack: stack
    };

  }

  htmlParser.supports = supports;

  htmlParser.tokenToString = function(tok) {
    var handler = {
      comment: function(tok) {
        return '<--' + tok.content + '-->';
      },
      endTag: function(tok) {
        return '</'+tok.tagName+'>';
      },
      atomicTag: function(tok) {
        console.log(tok);
        return handler.startTag(tok) +
              tok.content +
              handler.endTag(tok);
      },
      startTag: function(tok) {
        var str = '<'+tok.tagName;
        for (var key in tok.attrs) {
          var val = tok.attrs[key];
          // escape quotes
          str += ' '+key+'="'+(val ? val.replace(/(^|[^\\])"/g, '$1\\\"') : '')+'"';
        }
        return str + (tok.unary ? '/>' : '>');
      },
      chars: function(tok) {
        return tok.text;
      }
    };
    return handler[tok.type](tok);
  };

  htmlParser.escapeAttributes = function(attrs) {
    var escapedAttrs = {};
    // escape double-quotes for writing html as a string

    for(var name in attrs) {
      var value = attrs[name];
      escapedAttrs[name] = value && value.replace(/(^|[^\\])"/g, '$1\\\"');
    }
    return escapedAttrs;
  };

  for(var key in supports) {
    htmlParser.browserHasFlaw = htmlParser.browserHasFlaw || (!supports[key]) && key;
  }

  this.htmlParser = htmlParser;
})();
<|endoftext|>


<commit_before>'use strict';

const { StackedError } = require('kixx-server-errors');
const { createAPI } = require('./api');

const {
	isFunction,
	isPromise,
	union
} = require('./lib');

const BASE_PLUGIN_MODULE_PATH = '../plugins';

module.exports = function (applicationPlugin, overrides = {}) {
	const API = createAPI();
	const loadedPlugins = new Map();

	function getPlugin(id) {
		const plugin1 = overrides[id] || null;

		try {
			const plugin2 = require(`${BASE_PLUGIN_MODULE_PATH}/${id}`);
			return [ plugin1, plugin2 ];
		} catch (err) {
			if (!plugin1) {
				return Promise.reject(new StackedError(
					`Module loading error for plugin ${JSON.stringify(id)}`,
					err
				));
			}

			return [ plugin1, null ];
		}
	}

	function loadPlugin(api, id) {
		if (loadedPlugins.has(id)) {
			return Promise.resolve(api);
		}

		const [ plugin1, plugin2 ] = getPlugin(id);

		let dependencies;
		let initialize;

		if (plugin1 && plugin2) {
			const deps1 = Array.isArray(plugin1.dependencies) ? plugin1.dependencies : [];
			const deps2 = Array.isArray(plugin2.dependencies) ? plugin2.dependencies : [];
			dependencies = union(deps1, deps2);

			const init1 = plugin1.initialize;
			const init2 = plugin2.initialize;

			if (!isFunction(init1)) {
				return Promise.reject(new Error(
					`Plugin override ${JSON.stringify(id)} did not provide an initialize function`
				));
			}

			if (!isFunction(init2)) {
				return Promise.reject(new Error(
					`Plugin ${JSON.stringify(id)} did not export an initialize function`
				));
			}

			initialize = function (newApi) {
				const res = init2(newApi);

				if (isPromise(res)) {
					return res.then((latestApi) => {
						return init1(latestApi);
					});
				}

				if (!res) {
					throw new Error(`Plugin '${id}' did not return the api from initialize()`);
				}

				return init1(res);
			};
		} else if (plugin1) {
			dependencies = Array.isArray(plugin1.dependencies) ? plugin1.dependencies : [];
			initialize = plugin1.initialize;

			if (!isFunction(initialize)) {
				return Promise.reject(new Error(
					`Plugin ${JSON.stringify(id)} did not provide an initialize function`
				));
			}
		} else if (plugin2) {
			dependencies = Array.isArray(plugin2.dependencies) ? plugin2.dependencies : [];
			initialize = plugin2.initialize;

			if (!isFunction(initialize)) {
				return Promise.reject(new Error(
					`Plugin ${JSON.stringify(id)} did not export an initialize function`
				));
			}
		}

		const withDependencies = dependencies.reduce((promise, dependencyId) => {
			return promise.then((newApi) => loadPlugin(newApi, dependencyId));
		}, Promise.resolve(api));

		return withDependencies.then((newApi) => {
			const res = initialize(newApi);

			if (isPromise(res)) {
				return res.then((mutatedApi) => {
					if (!mutatedApi) {
						throw new Error(`Plugin '${id}' did not return the api from initialize()`);
					}
					return mutatedApi;
				});
			}

			if (!res) {
				throw new Error(`Plugin '${id}' did not return the api from initialize()`);
			}

			return res;
		}).then((newApi) => {
			loadedPlugins.set(id, newApi);
			return newApi;
		});
	}

	return loadPlugin(API, applicationPlugin);
};
<commit_msg>Lint updates to application initialization.<commit_after>'use strict';

const { StackedError } = require('kixx-server-errors');
const { createAPI } = require('./api');

const {
	isFunction,
	isPromise,
	union
} = require('./lib');

const BASE_COMPONENT_MODULE_PATH = '../components';

module.exports = function (applicationComponent, overrides = {}) {
	const API = createAPI();
	const loadedComponents = new Map();

	function getComponent(id) {
		const component1 = overrides[id] || null;

		try {
			const component2 = require(`${BASE_COMPONENT_MODULE_PATH}/${id}`);
			return [ component1, component2 ];
		} catch (err) {
			if (!component1) {
				return Promise.reject(new StackedError(
					`Module loading error for component ${JSON.stringify(id)}`,
					err
				));
			}

			return [ component1, null ];
		}
	}

	function loadComponent(api, id) {
		if (loadedComponents.has(id)) {
			return Promise.resolve(api);
		}

		const [ component1, component2 ] = getComponent(id);

		let dependencies;
		let initialize;

		if (component1 && component2) {
			const deps1 = Array.isArray(component1.dependencies) ? component1.dependencies : [];
			const deps2 = Array.isArray(component2.dependencies) ? component2.dependencies : [];
			dependencies = union(deps1, deps2);

			const init1 = component1.initialize;
			const init2 = component2.initialize;

			if (!isFunction(init1)) {
				return Promise.reject(new Error(
					`component override ${JSON.stringify(id)} did not provide an initialize function`
				));
			}

			if (!isFunction(init2)) {
				return Promise.reject(new Error(
					`component ${JSON.stringify(id)} did not export an initialize function`
				));
			}

			initialize = function (newApi) {
				const res = init2(newApi);

				if (isPromise(res)) {
					return res.then((latestApi) => {
						return init1(latestApi);
					});
				}

				if (!res) {
					throw new Error(`component '${id}' did not return the api from initialize()`);
				}

				return init1(res);
			};
		} else if (component1) {
			dependencies = Array.isArray(component1.dependencies) ? component1.dependencies : [];
			initialize = component1.initialize;

			if (!isFunction(initialize)) {
				return Promise.reject(new Error(
					`component ${JSON.stringify(id)} did not provide an initialize function`
				));
			}
		} else if (component2) {
			dependencies = Array.isArray(component2.dependencies) ? component2.dependencies : [];
			initialize = component2.initialize;

			if (!isFunction(initialize)) {
				return Promise.reject(new Error(
					`component ${JSON.stringify(id)} did not export an initialize function`
				));
			}
		}

		const withDependencies = dependencies.reduce((promise, dependencyId) => {
			return promise.then((newApi) => loadComponent(newApi, dependencyId));
		}, Promise.resolve(api));

		return withDependencies.then((newApi) => {
			const res = initialize(newApi);

			if (isPromise(res)) {
				return res.then((mutatedApi) => {
					if (!mutatedApi) {
						throw new Error(`component '${id}' did not return the api from initialize()`);
					}
					return mutatedApi;
				});
			}

			if (!res) {
				throw new Error(`component '${id}' did not return the api from initialize()`);
			}

			return res;
		}).then((newApi) => {
			loadedComponents.set(id, newApi);
			return newApi;
		});
	}

	return loadComponent(API, applicationComponent);
};
<|endoftext|>


<commit_before>'use strict';

var moment = require('moment');
var Jobs = require('../models/jobs_model');
var User = require('../models/user_model');
var JobsQueue = require('../models/jobQueue_model');
var config = require('../config');
var twilio = require('twilio');
var client = twilio(config.accountSid, config.authToken);

function addToQueue(job) {
  var jobDate = moment(job.jobDate).utc().format();
  var later = moment().add(1, 'days').utc().format();
  // if the job date is within the next 24 hrs, add to Queue
  if (moment(jobDate).isBefore(moment(later))) {
    //look for Concierge
    var newConcierge;
    User.findOneRandom({concierge: true}, {conciergeAvailable: true}, function(err, result) {
      if (err) return console.log('could not match with Concierge: ' + err);
      console.log('matched concierge with this user: ' + result);
      newConcierge = result;
      var newQueue = new JobsQueue({
        jobDate: job.jobDate,
        parent: job.parent,
        parentName: {
          first: job.parentName.first,
          last: job.parentName.last
        },
        parentNumber: job.parentNumber,
        optionsList: job.optionsList,
        recurring: job.recurring,
        pickedConcierge: newConcierge._id
      });
      //insert API calls here (weather/stock)
      newQueue.save(function(err, data) {
        if (err) return console.log('error saving job to Queue');
        console.log('newQueue job id: ' + data._id);
        console.log('saved job to queue');
        console.log('The concierge users id is: ' + newConcierge._id);
        User.findById(newConcierge._id, function(err, user) {
          if (err) return console.log('error finding concierge: ' + err);
          if (user === null) return console.log('user is null');
          user.conciergeJobs.push(data._id);
          user.save(function(err, res) {
            if (err) res.status(500).send(err);
            console.log('added Queued Job to Concierges Job array.');
          });
          // if recurring job, add 1 day to the jobs current date.
          if (job.recurring === true) {
            var newJobDate = moment(job.jobDate).add(1, 'days').utc().format();
            var tempJob = job;
            job.jobDate = newJobDate;
            job = job.toObject();
            delete job._id;
            Jobs.findOneAndUpdate({_id: tempJob._id}, job, function(err) {
              if (err) return console.log('error updating recurring job in db: ' + err);
              console.log('successfully updated job: ' + tempJob._id);
            });
          }
          // if not recurring, remove the job from the Jobs database.
          else {
            Jobs.remove({_id: job._id}, function(err) {
              if (err) return console.log('unable to remove job: ' + job._id);
            });
            User.findOneById(job._parent, function(err, user) {
              if (user === null) console.log('user is NULL for removing job from user array.');
              console.log('console log the dang user:' + user);
              var index = user.jobs.indexOf(job._id);
              if (index > -1) user.jobs.splice(index, 1);
              user.save(function(err) {
                if (err) console.log('could not delete job from user array');
                console.log('job removed from user jobs array.');
              });
            });
          }
        });
      });
    });
  }
}

function sendToTwilio(job) {
  var jobDate = moment(job.jobDate).utc().format();
  var later = moment().add(5, 'minutes').utc().format();
  // if the job date is within the next 5 minutes, send to Twilio
  if (moment(jobDate).isBefore(moment(later))) {
    User.findById(job.pickedConcierge, function(err, concierge) {
      if (err) return console.log('error finding picked concierge before call.');
      if (concierge === null) return console.log('concierge is null when finding before call.');
      client.makeCall({
              to: concierge.phone,
              from: config.twilioNumber,
              url: process.env.URL + '/outbound/' + job.parentName.first + '/' + job.parentName.last + '/' + job.parentNumber + '/'
          }, function(err) {
            console.log(err);
            if (err) {
              console.log('error making a call: ' + err);
            } else {
              console.log('call successfully made!');
            }
          });
    });

    JobsQueue.remove({_id: job._id}, function(err) {
      if (err) return console.log('unable to remove job from Queue: ' + job._id);
    });
  }
}

exports.checkJobs = function() {
  var jobStream = Jobs.find().stream();
  jobStream.on('data', function(job) {
    addToQueue(job);
  });
};

exports.checkQueue = function() {
  var queueStream = JobsQueue.find().stream();
  queueStream.on('data', function(job) {
    sendToTwilio(job);
  });
};
<commit_msg>jobmanager wip<commit_after>'use strict';

var moment = require('moment');
var Jobs = require('../models/jobs_model');
var User = require('../models/user_model');
var JobsQueue = require('../models/jobQueue_model');
var config = require('../config');
var twilio = require('twilio');
var client = twilio(config.accountSid, config.authToken);

function addToQueue(job) {
  var jobDate = moment(job.jobDate).utc().format();
  var later = moment().add(1, 'days').utc().format();
  // if the job date is within the next 24 hrs, add to Queue
  if (moment(jobDate).isBefore(moment(later))) {
    //look for Concierge
    var newConcierge;
    User.findOneRandom({concierge: true}, {conciergeAvailable: true}, function(err, result) {
      if (err) return console.log('could not match with Concierge: ' + err);
      console.log('matched concierge with this user: ' + result);
      newConcierge = result;
      var newQueue = new JobsQueue({
        jobDate: job.jobDate,
        parent: job.parent,
        parentName: {
          first: job.parentName.first,
          last: job.parentName.last
        },
        parentNumber: job.parentNumber,
        optionsList: job.optionsList,
        recurring: job.recurring,
        pickedConcierge: newConcierge._id
      });
      //insert API calls here (weather/stock)
      newQueue.save(function(err, data) {
        if (err) return console.log('error saving job to Queue');
        console.log('newQueue job id: ' + data._id);
        console.log('saved job to queue');
        console.log('The concierge users id is: ' + newConcierge._id);
        User.findById(newConcierge._id, function(err, user) {
          if (err) return console.log('error finding concierge: ' + err);
          if (user === null) return console.log('user is null');
          user.conciergeJobs.push(data._id);
          user.save(function(err, res) {
            if (err) res.status(500).send(err);
            console.log('added Queued Job to Concierges Job array.');
          });
          // if recurring job, add 1 day to the jobs current date.
          if (job.recurring === true) {
            var newJobDate = moment(job.jobDate).add(1, 'days').utc().format();
            var tempJob = job;
            job.jobDate = newJobDate;
            job = job.toObject();
            delete job._id;
            Jobs.findOneAndUpdate({_id: tempJob._id}, job, function(err) {
              if (err) return console.log('error updating recurring job in db: ' + err);
              console.log('successfully updated job: ' + tempJob._id);
            });
          }
          // if not recurring, remove the job from the Jobs database.
          else {
            Jobs.remove({_id: job._id}, function(err) {
              if (err) return console.log('unable to remove job: ' + job._id);
            });
            User.findById(job._parent, function(err, user) {
              if (user === null) console.log('user is NULL for removing job from user array.');
              console.log('console log the dang user:' + user);
              var index = user.jobs.indexOf(job._id);
              if (index > -1) user.jobs.splice(index, 1);
              user.save(function(err) {
                if (err) console.log('could not delete job from user array');
                console.log('job removed from user jobs array.');
              });
            });
          }
        });
      });
    });
  }
}

function sendToTwilio(job) {
  var jobDate = moment(job.jobDate).utc().format();
  var later = moment().add(5, 'minutes').utc().format();
  // if the job date is within the next 5 minutes, send to Twilio
  if (moment(jobDate).isBefore(moment(later))) {
    User.findById(job.pickedConcierge, function(err, concierge) {
      if (err) return console.log('error finding picked concierge before call.');
      if (concierge === null) return console.log('concierge is null when finding before call.');
      client.makeCall({
              to: concierge.phone,
              from: config.twilioNumber,
              url: process.env.URL + '/outbound/' + job.parentName.first + '/' + job.parentName.last + '/' + job.parentNumber + '/'
          }, function(err) {
            console.log(err);
            if (err) {
              console.log('error making a call: ' + err);
            } else {
              console.log('call successfully made!');
            }
          });
    });

    JobsQueue.remove({_id: job._id}, function(err) {
      if (err) return console.log('unable to remove job from Queue: ' + job._id);
    });
  }
}

exports.checkJobs = function() {
  var jobStream = Jobs.find().stream();
  jobStream.on('data', function(job) {
    addToQueue(job);
  });
};

exports.checkQueue = function() {
  var queueStream = JobsQueue.find().stream();
  queueStream.on('data', function(job) {
    sendToTwilio(job);
  });
};
<|endoftext|>


<commit_before>var crypto = require('crypto')

var async = require('async')
  , kafka = require('kafka-node')

module.exports =
{ producerPayload:  producerPayload
, outgoingMessage:  outgoingMessage
, consumer:         consumer
}

// A "face" is what you show the world and is a representation of who
// you think you are. Make sure you put on makeup first cause you ugly.

function producerPayload(topic, message, nPartitions, key) {
  var face = {}

  face.get = function () {
    return  [ { topic: topic
              , partition: message.mapToPartition(nPartitions, key)
              , messages: message.toKafkaMessage()
              }
            ]
  }

  return face
}

// nInstances is the number of processes running this code globally
// instanceId is an int 0,1,2,3...
function consumerPayloads(topic, instanceId, nInstances, nPartitions) {
  var partitions = []
    , payloads = []
    , face = {}

  for (var k=0; k < nPartitions; k++) {
    if ((k + instanceId) % nInstances === 0) partitions.push(k)
  }

  payloads = partitions.map(function (p) {
    return  { topic: topic
            , partition: p
            }
  })

  face.getPartitionOffsetMap = function (offsetter, cb) {
    async.map(payloads, function (payload, _cb) {
      offsetter.fetchCommits(group, payload, function (err, data) {
        if (err) { return _cb(err) }

        var partition = parseInt(payload.partition, 10)
          , offset = data[payload.topic][payload.partition]

        _cb(null, [partition, offset])
      })

    }, function (err, pairs) {
      if (err) { return cb(err) }

      var map = pairs.reduce(function (acc, pair) {
        return (acc[pair[0]] = pair[1]) && acc
      })

      cb(null, map)
    })
  }

  face.getPartitions = function () { return partitions }

  face.get = function (partitionToOffsetMap) {
    return payloads.map(function (payload) {
      payload.offset = partitionToOffsetMap[payload.partition]
      return payload
    })
  }

  return face
}

function outgoingMessage(task) {
  var face = {}

  function _getKeyVal(key) {
    var arr = key.split('.')
      , mutator = task

    while (arr.length) { mutator = mutator[arr.shift()] }

    return mutator
  }

  // Takes a key in dot notation to access a field in "task"
  // Hashes that field to obtain number between 0.. nPartitions-1
  face.mapToPartition = function (nPartitions, key) {
    function __mapHash(key, nPartitions) {
      return parseInt(crypto.createHash('sha1')
                            .update(JSON.stringify(_getKeyVal(key)))
                            .digest('hex')
                            .slice(0,6), 16) % nPartitions
    }

    // If key is undefined, map to a random partition
    return (key !== undefined ? __mapHash(key, nPartitions)
                              : Math.floor(Math.random() * nPartitions))
  }

  face.toKafkaMessage = function () {
    return JSON.stringify(task)
  }

  return face
}

function incomingMessage(message) {
  var face = {}

  face.get = function (field) { return message[field] }

  face.toTask = function () {
    return JSON.parse(message.value)
  }

  return face
}

function consumer(client, topic, group, options) {
  var face = {}
    , noop = function () {}

    // OMFG WATCH OUT FOR STATE o_0
    // Consumer has a lot of ferking state
    , shuttingDown = false
    , reading = false
    , offsets = {} // partition to offset map
    , ops = { data:   function () { throw new Error('No data handler supplied') }
            , error:  function (err) { throw new Error(err) }
            , end:    noop
            }

    , fetchMaxMs = options.fetch_max_ms
    , fetchMinBytes = options.fetch_min_bytes

    , offsetter = new kafka.Offset(client)
    , payloads = consumerPayloads(topic,
                                  options.instance_id,
                                  options.num_instances,
                                  options.num_partitions)

  var read = function () {
    if (shuttingDown) { return }

    if (reading) { return }
    reading = true

    var retryDueToError = false
      , mbs = messageBins(payloads.getPartitions())
      , encoder = protocol.encodeFetchRequest(fetchMaxWaitMs, fetchMinBytes)
      , decoder = protocol.decodeFetchResponse(_decoderCb)

    client.send(payloads.get(offsets), encoder, decoder, function (err) {
      if (err) { return (reading = false) && ops.error(err) }
    })

    function _decoderCb(err, type, value) {
      if (shuttingDown) { return }

      if (retryDueToError) { return (reading = false) }

      if (err) { return (retryDueToError = true) && ops.error(err) }

      if (type === "message") {
        mbs.enqueue(incomingMessage(value))

      } else {
        mbs.process(_processMessage, _fin)

      }
    }

    function _processMsg(message, next) {
      if (shuttingDown) { return next() }

      ops.data(message, function (err) {
        if (err) { return next(err) }

        var partition = message.get('partition')
          , offset = message.get('offset')

        // update consumer state and continue
        return (offsets[partition] = offset + 1) && next()
      })
    }

    function _fin(err) {
      if (err) { return ops.error(err) }

      face.read()
    }
  }

  var ensureOffsets = function (next) {
    if (offsets.length) { return next() }

    payloads.getPartitionOffsetMap(offsetter, function (err, map) {
      if (err) { return ops.error(err) }

      // update consumer state
      offsets = map

      return next()
    })
  }

  face.read = ensureOffsets.bind(null, read)

  face.on = function (evt, cb) {
    cb && (ops[evt] = cb)
  }

  face.commit = function (partition, offset, next) {
    return offsetter.commit(group,
        { topic: topic
        , partition: partition
        , offset: offset
        }, next)
  }

  face.end = function (next) {
    shuttingDown = true

    return setImmediate(next)
  }

  return face
}

// creates a queue for each partition in partitions
// messages from these queues are concurrently processed
function messageBins(partitions) {
  var qs = []
    , face = {}

  // Set up the buffer queues
  for (var k = 0; k < partitions.length; k++) {
    qs.push([])
  }

  face.enqueue = function (message) {
    return qs[partitions.indexOf(message.get('partition'))].push(message)
  }

  face.process = function (handler, done) {
    return qs.forEach(function (q) {
      async.eachSeries(q, handler, done)
    })
  }

  return face
}
<commit_msg>make things a little less imperative<commit_after>var crypto = require('crypto')

var async = require('async')
  , kafka = require('kafka-node')

module.exports =
{ producerPayload:  producerPayload
, outgoingMessage:  outgoingMessage
, consumer:         consumer
}

var compose = function () {
  var fns = arguments

  return function (result) {
    for (var i = fns.length - 1; i > -1; i--) {
      result = fns[i].call(this, result)
    }

    return result
  }
}

var catchErr = function (left, right) {
  return function () {
    var err = arguments[0]

    if (err) { return left(errr) }

    return right(arguments.slice(1))
  }
}

// A "face" is what you show the world and is a representation of who
// you think you are. Make sure you put on makeup first cause you ugly.

function producerPayload(topic, message, nPartitions, key) {
  var face = {}

  face.get = function () {
    return  [ { topic: topic
              , partition: message.mapToPartition(nPartitions, key)
              , messages: message.toKafkaMessage()
              }
            ]
  }

  return face
}

// nInstances is the number of processes running this code globally
// instanceId is an int 0,1,2,3...
function consumerPayloads(topic, instanceId, nInstances, nPartitions) {
  var partitions = []
    , payloads = []
    , face = {}

  for (var k=0; k < nPartitions; k++) {
    if ((k + instanceId) % nInstances === 0) partitions.push(k)
  }

  payloads = partitions.map(function (p) {
    return  { topic: topic
            , partition: p
            }
  })

  var toMap = function (results) {
    return pairs.reduce(function (acc, result) {
      var topic = Object.keys(result)[0]
        , partition = Object.keys(result[topic])[0]
        , offset = result[topic][partition]

      return (acc[partition] = pair[offset]) && acc
    }, {})
  }

  face.getPartitionOffsetMap = function (offsetter, group, cb) {
    var _payloads = payloads.map(function (payload) { return [payload] })
    async.map(_payloads,
              offsetter.fetchCommits.bind(offsetter, group),
              catchErr(cb, compose(cb.bind(null, null), toMap)))
  }

  face.getPartitions = function () { return partitions }

  face.get = function (partitionToOffsetMap) {
    return payloads.map(function (payload) {
      payload.offset = partitionToOffsetMap[payload.partition]
      return payload
    })
  }

  return face
}

function outgoingMessage(task) {
  var face = {}

  function _getKeyVal(key) {
    var arr = key.split('.')
      , mutator = task

    while (arr.length) { mutator = mutator[arr.shift()] }

    return mutator
  }

  // Takes a key in dot notation to access a field in "task"
  // Hashes that field to obtain number between 0.. nPartitions-1
  face.mapToPartition = function (nPartitions, key) {
    function __mapHash(key, nPartitions) {
      return parseInt(crypto.createHash('sha1')
                            .update(JSON.stringify(_getKeyVal(key)))
                            .digest('hex')
                            .slice(0,6), 16) % nPartitions
    }

    // If key is undefined, map to a random partition
    return (key !== undefined ? __mapHash(key, nPartitions)
                              : Math.floor(Math.random() * nPartitions))
  }

  face.toKafkaMessage = function () {
    return JSON.stringify(task)
  }

  return face
}

function incomingMessage(message) {
  var face = {}

  face.get = function (field) { return message[field] }

  face.toTask = function () {
    return JSON.parse(message.value)
  }

  return face
}

function consumer(client, topic, group, options) {
  var face = {}
    , noop = function () {}

    // OMFG WATCH OUT FOR STATE o_0
    // Consumer has a lot of ferking state
    , shuttingDown = false
    , reading = false
    , offsets = {} // partition to offset map
    , ops = { data:   function () { throw new Error('No data handler supplied') }
            , error:  function (err) { throw new Error(err) }
            , end:    noop
            }

    , fetchMaxMs = options.fetch_max_ms
    , fetchMinBytes = options.fetch_min_bytes

    , offsetter = new kafka.Offset(client)
    , payloads = consumerPayloads(topic,
                                  options.instance_id,
                                  options.num_instances,
                                  options.num_partitions)

  var read = function () {
    if (shuttingDown || reading) { return }

    reading = true

    var retryDueToError = false
      , mbs = messageBins(payloads.getPartitions())
      , encoder = protocol.encodeFetchRequest(fetchMaxWaitMs, fetchMinBytes)
      , decoder = protocol
                    .decodeFetchResponse(
                        catchErr( compose(ops.error, _setRetry),
                                  _decoderCb))

    client.send(payloads.get(offsets),
                encoder,
                decoder,
                catchErr(_onSenderErr, noop))

    function _onSenderErr(err) { return (reading = false) && ops.error(err) }

    function _setRetry(err) { return (retryDueToError = true) && err }

    function _decoderCb(type, value) {
      if (shuttingDown) { return }

      if (retryDueToError) { return (reading = false) }

      if (type === "message") {
        mbs.enqueue(incomingMessage(value))

      } else {
        mbs.process(_processMessage, _fin)

      }
    }

    function _processMsg(message, next) {
      if (shuttingDown) { return next() }

      ops.data(message, catchErr( next,
                                  compose(next, updateOffsets)))

      function _updateOffsets() {
        var partition = message.get('partition')
          , offset = message.get('offset')

        return (offsets[partition] = offset + 1)
      }
    }

    var _fin = catchErr(ops.error, face.read)
  }

  var ensureOffsets = function (next) {
    if (offsets.length) { return next() }

    payloads
      .getPartitionOffsetMap(
          offsetter,
          group,
          catchErr( ops.error,
                    function(map) { (offsets = map) && next() }))
  }

  face.read = ensureOffsets.bind(null, read)

  face.on = function (evt, cb) {
    cb && (ops[evt] = cb)
  }

  face.commit = function (partition, offset, next) {
    return offsetter.commit(group,
        { topic: topic
        , partition: partition
        , offset: offset
        }, next)
  }

  face.end = function (next) {
    shuttingDown = true

    return setImmediate(next)
  }

  return face
}

// creates a queue for each partition in partitions
// messages from these queues are concurrently processed
function messageBins(partitions) {
  var qs = []
    , face = {}

  // Set up the buffer queues
  for (var k = 0; k < partitions.length; k++) {
    qs.push([])
  }

  face.enqueue = function (message) {
    return qs[partitions.indexOf(message.get('partition'))].push(message)
  }

  face.process = function (handler, done) {
    return qs.forEach(function (q) {
      async.eachSeries(q, handler, done)
    })
  }

  return face
}
<|endoftext|>


<commit_before>
'use strict';

const config = require('../config');
const status = require('../domain/player-status');

const request = require('request');

const sortByRank = require('poker-rank');
const getCombinations = require('poker-combinations');

const save = require('../storage').save;
const safeSum = require('../lib/safe-math').safeSum;
const safeDiff = require('../lib/safe-math').safeDiff;

const winston = require('../log-setup');
const gamestory = winston.loggers.get('gamestory');
const errors = winston.loggers.get('errors');

const fake = Symbol('fake-test');
const progressive = Symbol.for('hand-progressive');
const hasDB = Symbol('hasDB');

const fakePlayers = {};
if (process.env.NODE_ENV === 'test'){
  fakePlayers.aggressive = require('../fake-players/aggressive');
  fakePlayers.caller = require('../fake-players/caller');
  fakePlayers.folder = require('../fake-players/folder');
  fakePlayers.pair = require('../fake-players/pair');
}

const urlHeroku_ = Symbol('heroku-service');

const actions = {

  //
  // prepare the gamestate model with the only information
  // each player should know
  // then send an http request to the bot service
  // to get the bet amount
  talk: function talk(gs){

    //
    // the state of the game, filtered with the only information
    // available to the current player
    const ps = Object.create(null);

    // the unique id of the current tournament
    ps.tournamentId = gs.tournamentId;

    // round number of the current tournament
    ps.round = gs[progressive];

    // value of the small blinds
    // ... big blind is always twice
    ps.sb = gs.sb;

    // value of the pot
    // it's updated after each bet
    ps.pot = gs.pot;

    // list of the community cards on the table
    // everyone is able to access this same list
    ps.commonCards = gs.commonCards;

    // the list of the players...
    // make sure that the current players can see only its cards
    ps.players = gs.players.map((player, id) => {
      // clean player data
      let mysterious = Object.assign({}, player);
      Object.getOwnPropertySymbols(mysterious).forEach(symb => delete mysterious[symb]);
      if (this.id === id){
        return mysterious;
      }
      delete mysterious.cards;
      delete mysterious.bestCards;
      return mysterious;
    });

    // index of the player with the dealer button
    ps.db = Math.max(gs.players.findIndex(player => player[hasDB]), 0);

    // index of the player 'this' in the players array
    ps.me = this.id;

    // amount of chips the current player must bet
    // in order to remain in the game;
    // it depends by how much he bet previously;
    // so it can change for each player
    ps.callAmount = gs.callAmount - this.chipsBet;

    if (this[fake]){
      let lib = fakePlayers[this[fake]];
      return Promise.resolve(lib.bet(Object.freeze(ps), x => x));
    }

    const tag = { id: gs.handId, type: 'bet' };

    gamestory.info('We\'re asking to %s (%d) the amount of his bet on the basis of %s', this.name, this.id, JSON.stringify(ps), tag);

    // send a network request to the Heroku's service
    // to get the bot's bet amount
    const service = `${this[urlHeroku_]}bet`
    return new Promise((resolve, reject) => {
      request.post(service, { body: ps, json: true }, (err, response, playerBetAmount) => {
        if (err){
          return void reject(err);
        }
        gamestory.info('%s (%d) bets %d', this.name, this.id, playerBetAmount, tag);
        resolve(playerBetAmount);
      });
    });

  },

  //
  // updates the player state, and the game state
  // accordingly to the player bet
  bet: function bet(gs, amount){

    //
    // sanitization
    if (typeof amount != 'number'){
      amount = Number.parseFloat(amount);
    }

    if (Number.isNaN(amount)){
      amount = 0;
    }

    //
    // amount should be in the range [ 0 ... player.chips ]
    if (amount < 0){
      amount = 0;
    }
    else if (amount > this.chips){
      amount = this.chips;
    }

    const isAllin = this.isAllin(amount);

    if (safeSum(this.chipsBet, amount) < gs.callAmount){

      //
      // player is betting less than the required amount;
      // unless he is betting all the chips he owns
      // we treat this as a "fold" declaration

      if (!isAllin){
        gamestory.info('%s (%d) folded', this.name, this.id, { id: gs.handId, type: 'status' });
        return this.fold(gs);
      }
    }

    if (isAllin){
      gamestory.info('%s (%d) is allin', this.name, this.id, { id: gs.handId, type: 'status' });
      let allin = Symbol.for('allin');
      this[allin] = true;
    }

    //
    // update chip values
    this.chipsBet = safeSum(amount, this.chipsBet);
    this.chips = safeDiff(this.chips, amount);

    gs.pot = safeSum(gs.pot, amount);
    gs.callAmount = Math.max(this.chipsBet, gs.callAmount);

    gamestory.info('Game state after %s (%d)\'s bet: %s', this.name, this.id, JSON.stringify({ pot:gs.pot, callAmount: gs.callAmount, player: { name: this.name, chips: this.chips, chipsBet: this.chipsBet } }), { id: gs.handId, type: 'bet' });

    return save(gs, { type: 'bet', handId: gs.handId, session: gs.session, playerId: this.id, amount: amount });

  },

  //
  // compute the player best combination
  showdown: function showdown(commonCards){
    let combs = getCombinations(this.cards.concat(commonCards), 5);
    let bestHand = sortByRank(combs)[0];
    this.bestCards = combs[bestHand.index];
    gamestory.info('%s (%d)\'s best combination is: %s', this.name, this.id, JSON.stringify(this.bestCards));
    return this.bestCards;
  },

  //
  // return true if the specified amount
  // is equal to the player total number of chips
  isAllin: function isAllin(amount){
    return amount === this.chips;
  },

  //
  // change the player status to folded
  fold: function fold(gs){
    this.status = status.folded;
    return save(gs, { type: 'status', handId: gs.handId, session: gs.session, playerId: this.id, status: 'folded' });
  }

}

exports = module.exports = function factory(obj, i){

  //
  // create a new player object
  let player = Object.create(actions);

  player.id = i;
  player.name = obj.name;
  player.version = 'Poker folder star!';

  // url of the host where the bot is running
  player[urlHeroku_] = obj.url;

  player.chips = config.BUYIN;
  player.status = status.active;

  // the two private cards of the player
  player.cards = [];

  // the total amount of chips the player bet
  // in the current "hand".
  // it is the sum of the chips the player bet
  // in each "betting session" of the current hand.
  // "betting session": [preflop, flop, turn, river]
  player.chipsBet = 0;

  if (obj.lib){
    // for test...
    // in test this is a fake bot module that simulate the player's behaviour
    player[fake] = obj.lib;
  }

  return player;

}
<commit_msg>callAmount can't be negative<commit_after>
'use strict';

const config = require('../config');
const status = require('../domain/player-status');

const request = require('request');

const sortByRank = require('poker-rank');
const getCombinations = require('poker-combinations');

const save = require('../storage').save;
const safeSum = require('../lib/safe-math').safeSum;
const safeDiff = require('../lib/safe-math').safeDiff;

const winston = require('../log-setup');
const gamestory = winston.loggers.get('gamestory');
const errors = winston.loggers.get('errors');

const fake = Symbol('fake-test');
const progressive = Symbol.for('hand-progressive');
const hasDB = Symbol('hasDB');

const fakePlayers = {};
if (process.env.NODE_ENV === 'test'){
  fakePlayers.aggressive = require('../fake-players/aggressive');
  fakePlayers.caller = require('../fake-players/caller');
  fakePlayers.folder = require('../fake-players/folder');
  fakePlayers.pair = require('../fake-players/pair');
}

const urlHeroku_ = Symbol('heroku-service');

const actions = {

  //
  // prepare the gamestate model with the only information
  // each player should know
  // then send an http request to the bot service
  // to get the bet amount
  talk: function talk(gs){

    //
    // the state of the game, filtered with the only information
    // available to the current player
    const ps = Object.create(null);

    // the unique id of the current tournament
    ps.tournamentId = gs.tournamentId;

    // round number of the current tournament
    ps.round = gs[progressive];

    // value of the small blinds
    // ... big blind is always twice
    ps.sb = gs.sb;

    // value of the pot
    // it's updated after each bet
    ps.pot = gs.pot;

    // list of the community cards on the table
    // everyone is able to access this same list
    ps.commonCards = gs.commonCards;

    // the list of the players...
    // make sure that the current players can see only its cards
    ps.players = gs.players.map((player, id) => {
      // clean player data
      let mysterious = Object.assign({}, player);
      Object.getOwnPropertySymbols(mysterious).forEach(symb => delete mysterious[symb]);
      if (this.id === id){
        return mysterious;
      }
      delete mysterious.cards;
      delete mysterious.bestCards;
      return mysterious;
    });

    // index of the player with the dealer button
    ps.db = Math.max(gs.players.findIndex(player => player[hasDB]), 0);

    // index of the player 'this' in the players array
    ps.me = this.id;

    // amount of chips the current player must bet
    // in order to remain in the game;
    // it depends by how much he bet previously;
    // so it can change for each player
    ps.callAmount = Math.max(gs.callAmount - this.chipsBet, 0);

    if (this[fake]){
      let lib = fakePlayers[this[fake]];
      return Promise.resolve(lib.bet(Object.freeze(ps), x => x));
    }

    const tag = { id: gs.handId, type: 'bet' };

    gamestory.info('We\'re asking to %s (%d) the amount of his bet on the basis of %s', this.name, this.id, JSON.stringify(ps), tag);

    // send a network request to the Heroku's service
    // to get the bot's bet amount
    const service = `${this[urlHeroku_]}bet`
    return new Promise((resolve, reject) => {
      request.post(service, { body: ps, json: true }, (err, response, playerBetAmount) => {
        if (err){
          return void reject(err);
        }
        gamestory.info('%s (%d) bets %d', this.name, this.id, playerBetAmount, tag);
        resolve(playerBetAmount);
      });
    });

  },

  //
  // updates the player state, and the game state
  // accordingly to the player bet
  bet: function bet(gs, amount){

    //
    // sanitization
    if (typeof amount != 'number'){
      amount = Number.parseFloat(amount);
    }

    if (Number.isNaN(amount)){
      amount = 0;
    }

    //
    // amount should be in the range [ 0 ... player.chips ]
    if (amount < 0){
      amount = 0;
    }
    else if (amount > this.chips){
      amount = this.chips;
    }

    const isAllin = this.isAllin(amount);

    if (safeSum(this.chipsBet, amount) < gs.callAmount){

      //
      // player is betting less than the required amount;
      // unless he is betting all the chips he owns
      // we treat this as a "fold" declaration

      if (!isAllin){
        gamestory.info('%s (%d) folded', this.name, this.id, { id: gs.handId, type: 'status' });
        return this.fold(gs);
      }
    }

    if (isAllin){
      gamestory.info('%s (%d) is allin', this.name, this.id, { id: gs.handId, type: 'status' });
      let allin = Symbol.for('allin');
      this[allin] = true;
    }

    //
    // update chip values
    this.chipsBet = safeSum(amount, this.chipsBet);
    this.chips = safeDiff(this.chips, amount);

    gs.pot = safeSum(gs.pot, amount);
    gs.callAmount = Math.max(this.chipsBet, gs.callAmount);

    gamestory.info('Game state after %s (%d)\'s bet: %s', this.name, this.id, JSON.stringify({ pot:gs.pot, callAmount: gs.callAmount, player: { name: this.name, chips: this.chips, chipsBet: this.chipsBet } }), { id: gs.handId, type: 'bet' });

    return save(gs, { type: 'bet', handId: gs.handId, session: gs.session, playerId: this.id, amount: amount });

  },

  //
  // compute the player best combination
  showdown: function showdown(commonCards){
    let combs = getCombinations(this.cards.concat(commonCards), 5);
    let bestHand = sortByRank(combs)[0];
    this.bestCards = combs[bestHand.index];
    gamestory.info('%s (%d)\'s best combination is: %s', this.name, this.id, JSON.stringify(this.bestCards));
    return this.bestCards;
  },

  //
  // return true if the specified amount
  // is equal to the player total number of chips
  isAllin: function isAllin(amount){
    return amount === this.chips;
  },

  //
  // change the player status to folded
  fold: function fold(gs){
    this.status = status.folded;
    return save(gs, { type: 'status', handId: gs.handId, session: gs.session, playerId: this.id, status: 'folded' });
  }

}

exports = module.exports = function factory(obj, i){

  //
  // create a new player object
  let player = Object.create(actions);

  player.id = i;
  player.name = obj.name;
  player.version = 'Poker folder star!';

  // url of the host where the bot is running
  player[urlHeroku_] = obj.url;

  player.chips = config.BUYIN;
  player.status = status.active;

  // the two private cards of the player
  player.cards = [];

  // the total amount of chips the player bet
  // in the current "hand".
  // it is the sum of the chips the player bet
  // in each "betting session" of the current hand.
  // "betting session": [preflop, flop, turn, river]
  player.chipsBet = 0;

  if (obj.lib){
    // for test...
    // in test this is a fake bot module that simulate the player's behaviour
    player[fake] = obj.lib;
  }

  return player;

}
<|endoftext|>


<commit_before>/**
 * @file dummyTest.js
 * @author Vladimir Deminenko
 * @date 20.08.2017
 */

'use strict';

describe(`Dummy / Singleton`, function () {
    let foo;
    let bar;
    let baz;

    before(function () {
        foo = new Dummy();
        bar = new Dummy();
        bar.setValue(123);
        baz = Dummy();
    });

    after(function () {
        baz = null;
        bar = null;
        foo = null;
    });

    it(`foo === bar`, function () {
        assert.isTrue(foo === bar);
    });

    it(`foo.getValue() === bar.getValue()`, function () {
        assert.isTrue(foo.getValue() === bar.getValue());
    });

    it(`baz === bar`, function () {
        assert.isTrue(baz === bar);
    });

    it(`baz.getValue() = 123`, function () {
        assert.isTrue(baz.getValue() === 123);
    });
});
<commit_msg>homework-06<commit_after>/**
 * @file dummyTest.js
 * @author Vladimir Deminenko
 * @date 20.08.2017
 */

'use strict';

describe(`Dummy / Singleton`, function () {
    let foo;
    let bar;
    let baz;

    before(function () {
        baz = Dummy();
        foo = new Dummy();
        bar = new Dummy();
        bar.setValue(123);
    });

    after(function () {
        bar = null;
        foo = null;
        baz = null;
    });

    it(`foo === bar`, function () {
        assert.isTrue(foo === bar);
    });

    it(`foo.getValue() === bar.getValue()`, function () {
        assert.isTrue(foo.getValue() === bar.getValue());
    });

    it(`baz === bar`, function () {
        assert.isTrue(baz === bar);
    });

    it(`baz.getValue() = 123`, function () {
        assert.isTrue(baz.getValue() === 123);
    });
});
<|endoftext|>


<commit_before>'use strict';

var map            = Array.prototype.map
  , push           = Array.prototype.push
  , commonLeft     = require('es5-ext/lib/Array/prototype/common-left')
  , getNull        = require('es5-ext/lib/Function/k')(null)
  , invoke         = require('es5-ext/lib/Function/invoke')
  , extend         = require('es5-ext/lib/Object/extend')
  , forEach        = require('es5-ext/lib/Object/for-each')
  , isCallable     = require('es5-ext/lib/Object/is-callable')
  , endsWith       = require('es5-ext/lib/String/prototype/ends-with')
  , deferred       = require('deferred')
  , promisify      = deferred.promisify
  , fs             = require('fs')
  , path           = require('path')
  , isIgnored      = require('next/lib/fs/is-ignored')
  , sep            = require('next/lib/path/sep')
  , getOptsReader  = require('./_options/read').getReader
  , normalizeOpts  = require('./_options/normalize')
  , lintignoreMode = require('./_lintignore-mode')
  , LintFile       = require('./lint-file').LintFile

  , open = promisify(fs.open), read = promisify(fs.read)
  , dirname = path.dirname, resolve = path.resolve
  , getIsIgnored = isIgnored.getIsIgnored
  , applyGlobalRules = isIgnored.applyGlobalRules

	, reNoExt = /(?:^|[\/\\])[\0-\u002d\u0030-\u005b\u005d-\uffff]+$/
  , reShebang = /^#![\u0021-\uffff]+(?:\/node|\/env node)\s/

  , lintFiles, LintFiles;

LintFiles = function () {
	this.result = {};
	this.linters = {};
	extend(this, deferred());
	this.promise.close = this.close.bind(this);
	this.clear = this.clear.bind(this);
};
LintFiles.prototype = {
	init: function () {
		if (this.watch) {
			this.ignores = {};
		}
		deferred.map(this.files.map(function (name) {
			if (this.globalRules &&
					applyGlobalRules(this.getFilename(name), this.globalRules)) {
				return null;
			}
			if (endsWith.call(name, '.js')) {
				return this.checkIsIgnored(name);
			}
			if (reNoExt.test(name)) {
				return this.checkSheBang(name)(function (isNodeScript) {
					return isNodeScript ? this.checkIsIgnored(name) : null;
				});
			}
			return null;
		}, this)).end(this.resolve.bind(this, this.result), this.resolve);
		this.promise.root = this.root;
		return this.promise;
	},
	getFilename: function (name) {
		return this.root ? (this.root + sep + name) : name;
	},
	checkSheBang: function (name) {
		return open(this.getFilename(name), 'r')(function (fd) {
			var buffer = new Buffer(100);
			return read(fd, buffer, 0, 100, null)(function () {
				return reShebang.test(String(buffer)) ? true : false;
			}.bind(this), getNull);
		}.bind(this), getNull);
	},
	checkIsIgnored: function (name) {
		var isIgnored = this.isIgnored(this.getFilename(name));
		if (this.watch) {
			this.ignores[name] = isIgnored;
			isIgnored.on('change', function (value) {
				if (value) {
					this.linters[name].close();
					this.clear(name);
				} else {
					this.lint(name);
				}
			}.bind(this));
		}
		return isIgnored(function (isIgnored) {
			return isIgnored ? null: this.lint(name);
		}.bind(this));
	},
	lint: function (name) {
		var lint;
		lint = new LintFile();
		lint.filename = this.getFilename(name);
		lint.inputOptions = this.options;
		lint.watch = this.watch;
		lint.cache = this.cache;
		lint.readOptions = this.readOptions;
		lint = this.linters[name] = lint.init();
		if (this.watch) {
			lint.on('change', function (report) {
				this.result[name] = report;
				if (this.promise.resolved || this.progress) {
					this.promise.emit('change',
						{ type: 'update', name: name, report: report });
				}
			}.bind(this));
			lint.on('end', function () {
				if (this.ignores) {
					this.ignores[name].close();
					delete this.ignores[name];
				}
				this.clear(name);
			}.bind(this));
		}
		return lint(function (report) {
			this.result[name] = report;
			if (this.promise.resolved || this.progress) {
				this.promise.emit('change',
					{ type: 'add', name: name, report: report });
			}
		}.bind(this), function () {
			if (this.ignores) {
				this.ignores[name].close();
				delete this.ignores[name];
			}
			delete this.linters[name];
		}.bind(this));
	},
	clear: function (name) {
		if (this.linters[name]) {
			delete this.result[name];
			delete this.linters[name];
			if (this.promise.resolved || this.progress) {
				this.promise.emit('change',
					{ type: 'remove', name: name });
			}
		}
	},
	close: function () {
		if (this.linters) {
			forEach(this.linters, invoke('close'));
			if (this.ignores) {
				forEach(this.ignores, invoke('close'));
			}
			delete this.linters;
		}
	}
};

lintFiles = function (files, options) {
	var lint, rootIndex, root, orgIsRoot, name, ignoreRules;

	if (files.length > 1) {
		rootIndex = commonLeft.apply(files[0], files.slice(1));
		if (rootIndex) {
			root = files[0].slice(0, rootIndex - 1);
			files = files.map(function (name) { return name.slice(rootIndex) });
		}
	}

	lint = new LintFiles();
	lint.files = files;
	lint.root = root;
	lint.options = options.options
	lint.watch = options.watch;
	lint.cache = options.cache;
	if (options.ignoreRules) {
		ignoreRules = isArray(options.ignoreRules) ?
			options.ignoreRules.concat('lint') :
			[String(options.ignoreRules), 'lint'];
	} else {
		ignoreRules = ['lint'];
	}

	// Read options
	lint.readOptions = getOptsReader(options.watch);

	name = options.watch ? 'isRoot' : 'isRootWatch';
	orgIsRoot = lintignoreMode[name];
	lintignoreMode[name] = lint.readOptions.isRoot;
	extend(lint, getIsIgnored(ignoreRules, null, options.watch));
	lintignoreMode[name] = orgIsRoot;

	return lint.init();
};
lintFiles.returnsPromise = true;

module.exports = exports = function (files/*, options, cb*/) {
	var options, cb;

	files = map.call(files, function (file) { return resolve(String(file)) });
	options = arguments[1];
	cb = arguments[2];
	if ((cb == null) && isCallable(options)) {
		cb = options;
		options = {};
	} else {
		options = Object(options);
		if (options.options) {
			options.options = normalizeOpts(options.options);
		}
	}

	return lintFiles(files, options).cb(cb);
};
exports.returnsPromise = true;
exports.lintFiles = lintFiles;
exports.LintFiles = LintFiles;
<commit_msg>Expose EMFILE and not file system errors<commit_after>'use strict';

var map            = Array.prototype.map
  , push           = Array.prototype.push
  , commonLeft     = require('es5-ext/lib/Array/prototype/common-left')
  , getNull        = require('es5-ext/lib/Function/k')(null)
  , invoke         = require('es5-ext/lib/Function/invoke')
  , extend         = require('es5-ext/lib/Object/extend')
  , forEach        = require('es5-ext/lib/Object/for-each')
  , isCallable     = require('es5-ext/lib/Object/is-callable')
  , endsWith       = require('es5-ext/lib/String/prototype/ends-with')
  , deferred       = require('deferred')
  , promisify      = deferred.promisify
  , fs             = require('fs')
  , path           = require('path')
  , isIgnored      = require('next/lib/fs/is-ignored')
  , sep            = require('next/lib/path/sep')
  , getOptsReader  = require('./_options/read').getReader
  , normalizeOpts  = require('./_options/normalize')
  , lintignoreMode = require('./_lintignore-mode')
  , LintFile       = require('./lint-file').LintFile

  , open = promisify(fs.open), read = promisify(fs.read)
  , dirname = path.dirname, resolve = path.resolve
  , getIsIgnored = isIgnored.getIsIgnored
  , applyGlobalRules = isIgnored.applyGlobalRules

	, reNoExt = /(?:^|[\/\\])[\0-\u002d\u0030-\u005b\u005d-\uffff]+$/
  , reShebang = /^#![\u0021-\uffff]+(?:\/node|\/env node)\s/

  , lintFiles, LintFiles;

LintFiles = function () {
	this.result = {};
	this.linters = {};
	extend(this, deferred());
	this.promise.close = this.close.bind(this);
	this.clear = this.clear.bind(this);
};
LintFiles.prototype = {
	init: function () {
		if (this.watch) {
			this.ignores = {};
		}
		deferred.map(this.files.map(function (name) {
			if (this.globalRules &&
					applyGlobalRules(this.getFilename(name), this.globalRules)) {
				return null;
			}
			if (endsWith.call(name, '.js')) {
				return this.checkIsIgnored(name);
			}
			if (reNoExt.test(name)) {
				return this.checkSheBang(name)(function (isNodeScript) {
					return isNodeScript ? this.checkIsIgnored(name) : null;
				});
			}
			return null;
		}, this)).end(this.resolve.bind(this, this.result), this.resolve);
		this.promise.root = this.root;
		return this.promise;
	},
	getFilename: function (name) {
		return this.root ? (this.root + sep + name) : name;
	},
	checkSheBang: function (name) {
		return open(this.getFilename(name), 'r')(function (fd) {
			var buffer = new Buffer(100);
			return read(fd, buffer, 0, 100, null)(function () {
				return reShebang.test(String(buffer)) ? true : false;
			}.bind(this), getNull);
		}.bind(this), getNull);
	},
	checkIsIgnored: function (name) {
		var isIgnored = this.isIgnored(this.getFilename(name));
		if (this.watch) {
			this.ignores[name] = isIgnored;
			isIgnored.on('change', function (value) {
				if (value) {
					this.linters[name].close();
					this.clear(name);
				} else {
					this.lint(name);
				}
			}.bind(this));
		}
		return isIgnored(function (isIgnored) {
			return isIgnored ? null: this.lint(name);
		}.bind(this));
	},
	lint: function (name) {
		var lint;
		lint = new LintFile();
		lint.filename = this.getFilename(name);
		lint.inputOptions = this.options;
		lint.watch = this.watch;
		lint.cache = this.cache;
		lint.readOptions = this.readOptions;
		lint = this.linters[name] = lint.init();
		if (this.watch) {
			lint.on('change', function (report) {
				this.result[name] = report;
				if (this.promise.resolved || this.progress) {
					this.promise.emit('change',
						{ type: 'update', name: name, report: report });
				}
			}.bind(this));
			lint.on('end', function () {
				if (this.ignores) {
					this.ignores[name].close();
					delete this.ignores[name];
				}
				this.clear(name);
			}.bind(this));
		}
		return lint(function (report) {
			this.result[name] = report;
			if (this.promise.resolved || this.progress) {
				this.promise.emit('change',
					{ type: 'add', name: name, report: report });
			}
		}.bind(this), function (err) {
			if (!err.code || (err.code === 'EMFILE')) {
				return err;
			}
			if (this.ignores) {
				this.ignores[name].close();
				delete this.ignores[name];
			}
			delete this.linters[name];
		}.bind(this));
	},
	clear: function (name) {
		if (this.linters[name]) {
			delete this.result[name];
			delete this.linters[name];
			if (this.promise.resolved || this.progress) {
				this.promise.emit('change',
					{ type: 'remove', name: name });
			}
		}
	},
	close: function () {
		if (this.linters) {
			forEach(this.linters, invoke('close'));
			if (this.ignores) {
				forEach(this.ignores, invoke('close'));
			}
			delete this.linters;
		}
	}
};

lintFiles = function (files, options) {
	var lint, rootIndex, root, orgIsRoot, name, ignoreRules;

	if (files.length > 1) {
		rootIndex = commonLeft.apply(files[0], files.slice(1));
		if (rootIndex) {
			root = files[0].slice(0, rootIndex - 1);
			files = files.map(function (name) { return name.slice(rootIndex) });
		}
	}

	lint = new LintFiles();
	lint.files = files;
	lint.root = root;
	lint.options = options.options
	lint.watch = options.watch;
	lint.cache = options.cache;
	if (options.ignoreRules) {
		ignoreRules = isArray(options.ignoreRules) ?
			options.ignoreRules.concat('lint') :
			[String(options.ignoreRules), 'lint'];
	} else {
		ignoreRules = ['lint'];
	}

	// Read options
	lint.readOptions = getOptsReader(options.watch);

	name = options.watch ? 'isRoot' : 'isRootWatch';
	orgIsRoot = lintignoreMode[name];
	lintignoreMode[name] = lint.readOptions.isRoot;
	extend(lint, getIsIgnored(ignoreRules, null, options.watch));
	lintignoreMode[name] = orgIsRoot;

	return lint.init();
};
lintFiles.returnsPromise = true;

module.exports = exports = function (files/*, options, cb*/) {
	var options, cb;

	files = map.call(files, function (file) { return resolve(String(file)) });
	options = arguments[1];
	cb = arguments[2];
	if ((cb == null) && isCallable(options)) {
		cb = options;
		options = {};
	} else {
		options = Object(options);
		if (options.options) {
			options.options = normalizeOpts(options.options);
		}
	}

	return lintFiles(files, options).cb(cb);
};
exports.returnsPromise = true;
exports.lintFiles = lintFiles;
exports.LintFiles = LintFiles;
<|endoftext|>


<commit_before>/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

module.exports = {
    moduleType: 'locale',
    name: 'ja',
    dictionary: {
        'Autoscale': '自動ズーム',                                                                         // components/modebar/buttons.js:139
        'Box Select': '矩形選択',                                                                          // components/modebar/buttons.js:103
        'Click to enter Colorscale title': '色スケールタイトルを入力するにはクリック',                     // plots/plots.js:437
        'Click to enter Component A title': 'コンポーネントAのタイトル入力するにはクリック',               // plots/ternary/ternary.js:386
        'Click to enter Component B title': 'コンポーネントBのタイトル入力するにはクリック',               // plots/ternary/ternary.js:400
        'Click to enter Component C title': 'コンポーネントCのタイトル入力するにはクリック',               // plots/ternary/ternary.js:411
        'Click to enter Plot title': 'プロットタイトルを入力するにはクリック',                             // plot_api/plot_api.js:579
        'Click to enter X axis title': 'X軸タイトルを入力するにはクリック',                                // plots/plots.js:435
        'Click to enter Y axis title': 'Y軸タイトルを入力するにはクリック',                                // plots/plots.js:436
        'Compare data on hover': 'ホバー中のデータを比較',                                                 // components/modebar/buttons.js:167
        'Double-click on legend to isolate one trace': '凡例をダブルクリックして1つのトレースを無効化します',// components/legend/handle_click.js:90
        'Double-click to zoom back out': 'ダブルクリックでズームを戻します',                               // plots/cartesian/dragbox.js:299
        'Download plot as a png': 'PNGファイルでダウンロード',                                             // components/modebar/buttons.js:52
        'Edit in Chart Studio': 'Chart Studioで編集',                                                      // components/modebar/buttons.js:76
        'IE only supports svg.  Changing format to svg.': 'IEはSVGのみサポートしています。SVGに変換します。', // components/modebar/buttons.js:60
        'Lasso Select': '投げ縄選択',                                                                      // components/modebar/buttons.js:112
        'Orbital rotation': '軌道回転',                                                                    // components/modebar/buttons.js:279
        'Pan': '拡大',                                                                                // components/modebar/buttons.js:94
        'Produced with Plotly': 'Plotlyにより作成',                                                        // components/modebar/modebar.js:256
        'Reset': 'リセット',                                                                                // components/modebar/buttons.js:432
        'Reset axes': '軸をリセット',                                                                       // components/modebar/buttons.js:148
        'Reset camera to default': 'カメラをデフォルトに戻す',                                              // components/modebar/buttons.js:314
        'Reset camera to last save': 'カメラを最後の保存状態に戻す',                                        // components/modebar/buttons.js:322
        'Reset view': 'ビューをリセット',                                                                   // components/modebar/buttons.js:583
        'Reset views': 'ビューをリセット',                                                                  // components/modebar/buttons.js:529
        'Show closest data on hover': 'ホバー時に一番近いデータを表示',                                     // components/modebar/buttons.js:157
        'Snapshot succeeded': 'スナップショットに成功',                                                     // components/modebar/buttons.js:66
        'Sorry, there was a problem downloading your snapshot!': 'すみません、スナップショットダウンロードでエラーです!', // components/modebar/buttons.js:69
        'Taking snapshot - this may take a few seconds': 'スナップショットを撮影',                          // components/modebar/buttons.js:57
        'Zoom': 'ズーム',                                                                                // components/modebar/buttons.js:85
        'Zoom in': '拡大',                                                                                // components/modebar/buttons.js:121
        'Zoom out': '縮小',                                                                                // components/modebar/buttons.js:130
        'close:': '閉じる:',                                                                                // traces/ohlc/transform.js:139
        'trace': 'トレース:',                                                                               // plots/plots.js:439
        'lat:': '緯度:',                                                                                // traces/scattergeo/calc.js:48
        'lon:': '経度:',                                                                                // traces/scattergeo/calc.js:49
        'q1:': 'q1:',                                                                                // traces/box/calc.js:130
        'q3:': 'q3:',                                                                                // traces/box/calc.js:131
        'source:': 'ソース:',                                                                               // traces/sankey/plot.js:140
        'target:': 'ターゲット:',                                                                            // traces/sankey/plot.js:141
        'lower fence:': 'フェンス下限:',                                                                     // traces/box/calc.js:134
        'upper fence:': 'フェンス上限:',                                                                     // traces/box/calc.js:135
        'max:': '最大:',                                                                                // traces/box/calc.js:132
        'mean ± σ:': '平均 ± σ:',                                                                       // traces/box/calc.js:133
        'mean:': '平均:',                                                                                // traces/box/calc.js:133
        'median:': '中央値:',                                                                               // traces/box/calc.js:128
        'min:': '最小:',                                                                                // traces/box/calc.js:129
        'Turntable rotation': '軸回転:',                                                                    // components/modebar/buttons.js:288
        'Toggle Spike Lines': 'スパイクラインのオンオフ',                                                   // components/modebar/buttons.js:548
        'open:': '開く:',                                                                                // traces/ohlc/transform.js:136
        'high:': '高:',                                                                                // traces/ohlc/transform.js:137
        'low:': '低:',                                                                                // traces/ohlc/transform.js:138
        'Toggle show closest data on hover': 'ホバー時に一番近いデータを表示のオンオフ',                          // components/modebar/buttons.js:353
        'incoming flow count:': '流入フローカウント:',                                                      // traces/sankey/plot.js:142
        'outgoing flow count:': '流出フローカウント:',                                                      // traces/sankey/plot.js:143
        'kde:': 'kde:'                                                                                // traces/violin/calc.js:73
    },
    format: {
        days: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'],
        shortDays: ['日', '月', '火', '水', '木', '金', '土'],
        months: [
            '1月', '2月', '3月', '4月', '5月', '6月',
            '7月', '8月', '9月', '10月', '11月', '12月'
        ],
        shortMonths: [
            '1月', '2月', '3月', '4月', '5月', '6月',
            '7月', '8月', '9月', '10月', '11月', '12月'
        ],
        date: '%Y/%m/%d'
    }
};
<commit_msg>Update ja.js<commit_after>/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

module.exports = {
    moduleType: 'locale',
    name: 'ja',
    dictionary: {
        'Autoscale': '自動ズーム',                                                                         // components/modebar/buttons.js:139
        'Box Select': '矩形選択',                                                                          // components/modebar/buttons.js:103
        'Click to enter Colorscale title': '色スケールタイトルを入力するにはクリック',                     // plots/plots.js:437
        'Click to enter Component A title': 'コンポーネントAのタイトル入力するにはクリック',               // plots/ternary/ternary.js:386
        'Click to enter Component B title': 'コンポーネントBのタイトル入力するにはクリック',               // plots/ternary/ternary.js:400
        'Click to enter Component C title': 'コンポーネントCのタイトル入力するにはクリック',               // plots/ternary/ternary.js:411
        'Click to enter Plot title': 'プロットタイトルを入力するにはクリック',                             // plot_api/plot_api.js:579
        'Click to enter X axis title': 'X軸タイトルを入力するにはクリック',                                // plots/plots.js:435
        'Click to enter Y axis title': 'Y軸タイトルを入力するにはクリック',                                // plots/plots.js:436
        'Compare data on hover': 'ホバー中のデータを比較',                                                 // components/modebar/buttons.js:167
        'Double-click on legend to isolate one trace': '凡例をダブルクリックして1つのトレースを無効化します', // components/legend/handle_click.js:90
        'Double-click to zoom back out': 'ダブルクリックでズームを戻します',                               // plots/cartesian/dragbox.js:299
        'Download plot as a png': 'PNGファイルでダウンロード',                                             // components/modebar/buttons.js:52
        'Edit in Chart Studio': 'Chart Studioで編集',                                                      // components/modebar/buttons.js:76
        'IE only supports svg.  Changing format to svg.': 'IEはSVGのみサポートしています。SVGに変換します。', // components/modebar/buttons.js:60
        'Lasso Select': '投げ縄選択',                                                                      // components/modebar/buttons.js:112
        'Orbital rotation': '軌道回転',                                                                    // components/modebar/buttons.js:279
        'Pan': '拡大',                                                                                // components/modebar/buttons.js:94
        'Produced with Plotly': 'Plotlyにより作成',                                                        // components/modebar/modebar.js:256
        'Reset': 'リセット',                                                                                // components/modebar/buttons.js:432
        'Reset axes': '軸をリセット',                                                                       // components/modebar/buttons.js:148
        'Reset camera to default': 'カメラをデフォルトに戻す',                                              // components/modebar/buttons.js:314
        'Reset camera to last save': 'カメラを最後の保存状態に戻す',                                        // components/modebar/buttons.js:322
        'Reset view': 'ビューをリセット',                                                                   // components/modebar/buttons.js:583
        'Reset views': 'ビューをリセット',                                                                  // components/modebar/buttons.js:529
        'Show closest data on hover': 'ホバー時に一番近いデータを表示',                                     // components/modebar/buttons.js:157
        'Snapshot succeeded': 'スナップショットに成功',                                                     // components/modebar/buttons.js:66
        'Sorry, there was a problem downloading your snapshot!': 'すみません、スナップショットダウンロードでエラーです!', // components/modebar/buttons.js:69
        'Taking snapshot - this may take a few seconds': 'スナップショットを撮影',                          // components/modebar/buttons.js:57
        'Zoom': 'ズーム',                                                                                // components/modebar/buttons.js:85
        'Zoom in': '拡大',                                                                                // components/modebar/buttons.js:121
        'Zoom out': '縮小',                                                                                // components/modebar/buttons.js:130
        'close:': '閉じる:',                                                                                // traces/ohlc/transform.js:139
        'trace': 'トレース:',                                                                               // plots/plots.js:439
        'lat:': '緯度:',                                                                                // traces/scattergeo/calc.js:48
        'lon:': '経度:',                                                                                // traces/scattergeo/calc.js:49
        'q1:': 'q1:',                                                                                // traces/box/calc.js:130
        'q3:': 'q3:',                                                                                // traces/box/calc.js:131
        'source:': 'ソース:',                                                                               // traces/sankey/plot.js:140
        'target:': 'ターゲット:',                                                                            // traces/sankey/plot.js:141
        'lower fence:': 'フェンス下限:',                                                                     // traces/box/calc.js:134
        'upper fence:': 'フェンス上限:',                                                                     // traces/box/calc.js:135
        'max:': '最大:',                                                                                // traces/box/calc.js:132
        'mean ± σ:': '平均 ± σ:',                                                                       // traces/box/calc.js:133
        'mean:': '平均:',                                                                                // traces/box/calc.js:133
        'median:': '中央値:',                                                                               // traces/box/calc.js:128
        'min:': '最小:',                                                                                // traces/box/calc.js:129
        'Turntable rotation': '軸回転:',                                                                    // components/modebar/buttons.js:288
        'Toggle Spike Lines': 'スパイクラインのオンオフ',                                                   // components/modebar/buttons.js:548
        'open:': '開く:',                                                                                // traces/ohlc/transform.js:136
        'high:': '高:',                                                                                // traces/ohlc/transform.js:137
        'low:': '低:',                                                                                // traces/ohlc/transform.js:138
        'Toggle show closest data on hover': 'ホバー時に一番近いデータを表示のオンオフ',                          // components/modebar/buttons.js:353
        'incoming flow count:': '流入フローカウント:',                                                      // traces/sankey/plot.js:142
        'outgoing flow count:': '流出フローカウント:',                                                      // traces/sankey/plot.js:143
        'kde:': 'kde:'                                                                                // traces/violin/calc.js:73
    },
    format: {
        days: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'],
        shortDays: ['日', '月', '火', '水', '木', '金', '土'],
        months: [
            '1月', '2月', '3月', '4月', '5月', '6月',
            '7月', '8月', '9月', '10月', '11月', '12月'
        ],
        shortMonths: [
            '1月', '2月', '3月', '4月', '5月', '6月',
            '7月', '8月', '9月', '10月', '11月', '12月'
        ],
        date: '%Y/%m/%d'
    }
};
<|endoftext|>