<commit_before>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import { deburrUpper } from 'app/utils';
import remove from 'lodash/remove';
import pick from 'lodash/pick';
import uniq from 'lodash/uniq';
import { ESP_BLACKLIST, FILTERS_BY_CATEGORY } from 'data/constants';

const getCategory = state =>
  (state.category && state.category.toLowerCase()) || null;
const getData = state => state.categoryData || null;
const getQuery = state => deburrUpper(state.query) || '';
const getSearch = state => state.search || null;

export const getDefaultColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return [
        'full_name',
        'developed_by',
        'geographic_coverage',
        'time_horizon',
        'url'
      ];
    case 'scenarios':
      return ['model', 'name', 'geographic_coverage_country'];
    case 'indicators':
      return ['category', 'subcategory', 'name'];
    default:
      return null;
  }
});

export const getFullTextColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return ['full_name', 'geographic_coverage'];
    case 'scenarios':
      return ['geographic_coverage_country'];
    case 'indicators':
      return [];
    default:
      return null;
  }
});

export const filteredDataBySearch = createSelector(
  [getData, getQuery],
  (data, query) => {
    if (!data || isEmpty(data)) return null;
    if (!query) return data;
    const updatedData = data;
    return updatedData.filter(d =>
      Object.keys(d).some(key => {
        if (Object.prototype.hasOwnProperty.call(d, key) && d[key] !== null) {
          return deburrUpper(d[key]).indexOf(query) > -1;
        }
        return false;
      })
    );
  }
);

export const titleLinks = createSelector(
  [getCategory, getData],
  (categoryName, data) => {
    if (!data || isEmpty(data) || !categoryName) return null;
    const linkInfo = {
      models: [
        { columnName: 'full_name', linkToId: true },
        { columnName: 'url' }
      ],
      scenarios: [{ columnName: 'name', linkToId: true }],
      indicators: []
    };
    const updatedData = data;
    return updatedData.map(d =>
      linkInfo[categoryName].map(l => ({
        columnName: l.columnName,
        url: l.linkToId ? `${categoryName}/${d.id}` : 'self'
      }))
    );
  }
);

const getSelectedFields = createSelector(
  [getSearch, getCategory],
  (search, category) => {
    if (!search) return null;
    let selectedFields = search;
    const selectedKeys = Object.keys(selectedFields).filter(k =>
      k.startsWith(category)
    );
    selectedFields = pick(selectedFields, selectedKeys);

    const fieldsWithoutPrefix = {};
    Object.keys(selectedFields).forEach(k => {
      const keyWithoutPrefix = k.replace(`${category}-`, '');
      fieldsWithoutPrefix[keyWithoutPrefix] = selectedFields[k];
    });
    return fieldsWithoutPrefix;
  }
);

export const getSelectedFieldOptions = createSelector(
  [getSelectedFields],
  fields => {
    if (!fields) return null;
    const fieldOptions = {};
    Object.keys(fields).forEach(key => {
      fieldOptions[key] = { value: fields[key], label: fields[key] };
    });
    return fieldOptions;
  }
);

export const filteredDataByFilters = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters) return data;
    let filteredData = data;
    Object.keys(filters).forEach(key => {
      filteredData = filteredData.filter(
        d => d[key] && (d[key] === filters[key] || d[key].name === filters[key])
      );
    });
    return filteredData;
  }
);

export const getAvailableSubcategories = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters || !filters.category) return [];
    const availableSubcategories = [];
    data.forEach(d => {
      if (d.category.name === filters.category) {
        availableSubcategories.push(d.subcategory.name);
      }
    });
    return uniq(availableSubcategories);
  }
);

export const getFilterOptionsByCategory = createSelector(
  [getCategory, getData, getAvailableSubcategories],
  (category, data, subcategories) => {
    if (!category || !data || isEmpty(data)) return null;
    const filters = FILTERS_BY_CATEGORY[category];
    const categoryOptions = {};
    filters.forEach(f => {
      const sanitizedFilterData = [];
      data.forEach(d => {
        if (d[f] !== null && d[f] !== '' && d[f] !== undefined) {
          const filterName = typeof d[f] === 'string' ? d[f] : d[f].name;
          sanitizedFilterData.push(filterName);
        }
      });
      let availableData = uniq(sanitizedFilterData);
      if (f === 'subcategory') {
        availableData = uniq(sanitizedFilterData).filter(
          d => subcategories.indexOf(d) > -1
        );
      }
      categoryOptions[f] = availableData.map(filterData => ({
        value: filterData,
        label: filterData
      }));
    });
    return categoryOptions;
  }
);

export const filterDataByBlackList = createSelector(
  [filteredDataByFilters, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data[0]),
      n => ESP_BLACKLIST[category].indexOf(n) === -1
    );
    return data.map(d => pick(d, whiteList));
  }
);

export const renameDataColumns = createSelector(
  [filterDataByBlackList, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    if (category === 'models') {
      let renamedData = data;
      const changes = [{ old: 'maintainer_name', new: 'developed_by' }];
      renamedData = renamedData.map(d => {
        const updatedD = d;
        changes.forEach(change => {
          if (d[change.old]) {
            updatedD[change.new] = d[change.old];
            delete updatedD[change.old];
          }
        });
        return updatedD;
      });
      return renamedData;
    }
    return data;
  }
);

export default {
  renameDataColumns,
  titleLinks,
  filteredDataByFilters,
  getFilterOptionsByCategory,
  getSelectedFieldOptions
};
<commit_msg>Add category column to scenarios in ESP table<commit_after>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import { deburrUpper } from 'app/utils';
import remove from 'lodash/remove';
import pick from 'lodash/pick';
import uniq from 'lodash/uniq';
import { ESP_BLACKLIST, FILTERS_BY_CATEGORY } from 'data/constants';

const getCategory = state =>
  (state.category && state.category.toLowerCase()) || null;
const getData = state => state.categoryData || null;
const getQuery = state => deburrUpper(state.query) || '';
const getSearch = state => state.search || null;

export const getDefaultColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return [
        'full_name',
        'developed_by',
        'geographic_coverage',
        'time_horizon',
        'url'
      ];
    case 'scenarios':
      return ['model', 'name', 'category', 'geographic_coverage_country'];
    case 'indicators':
      return ['category', 'subcategory', 'name'];
    default:
      return null;
  }
});

export const getFullTextColumns = createSelector([getCategory], category => {
  switch (category) {
    case 'models':
      return ['full_name', 'geographic_coverage'];
    case 'scenarios':
      return ['geographic_coverage_country'];
    case 'indicators':
      return [];
    default:
      return null;
  }
});

export const filteredDataBySearch = createSelector(
  [getData, getQuery],
  (data, query) => {
    if (!data || isEmpty(data)) return null;
    if (!query) return data;
    const updatedData = data;
    return updatedData.filter(d =>
      Object.keys(d).some(key => {
        if (Object.prototype.hasOwnProperty.call(d, key) && d[key] !== null) {
          return deburrUpper(d[key]).indexOf(query) > -1;
        }
        return false;
      })
    );
  }
);

export const titleLinks = createSelector(
  [getCategory, getData],
  (categoryName, data) => {
    if (!data || isEmpty(data) || !categoryName) return null;
    const linkInfo = {
      models: [
        { columnName: 'full_name', linkToId: true },
        { columnName: 'url' }
      ],
      scenarios: [{ columnName: 'name', linkToId: true }],
      indicators: []
    };
    const updatedData = data;
    return updatedData.map(d =>
      linkInfo[categoryName].map(l => ({
        columnName: l.columnName,
        url: l.linkToId ? `${categoryName}/${d.id}` : 'self'
      }))
    );
  }
);

const getSelectedFields = createSelector(
  [getSearch, getCategory],
  (search, category) => {
    if (!search) return null;
    let selectedFields = search;
    const selectedKeys = Object.keys(selectedFields).filter(k =>
      k.startsWith(category)
    );
    selectedFields = pick(selectedFields, selectedKeys);

    const fieldsWithoutPrefix = {};
    Object.keys(selectedFields).forEach(k => {
      const keyWithoutPrefix = k.replace(`${category}-`, '');
      fieldsWithoutPrefix[keyWithoutPrefix] = selectedFields[k];
    });
    return fieldsWithoutPrefix;
  }
);

export const getSelectedFieldOptions = createSelector(
  [getSelectedFields],
  fields => {
    if (!fields) return null;
    const fieldOptions = {};
    Object.keys(fields).forEach(key => {
      fieldOptions[key] = { value: fields[key], label: fields[key] };
    });
    return fieldOptions;
  }
);

export const filteredDataByFilters = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters) return data;
    let filteredData = data;
    Object.keys(filters).forEach(key => {
      filteredData = filteredData.filter(
        d => d[key] && (d[key] === filters[key] || d[key].name === filters[key])
      );
    });
    return filteredData;
  }
);

export const getAvailableSubcategories = createSelector(
  [filteredDataBySearch, getSelectedFields],
  (data, filters) => {
    if (!data) return null;
    if (!filters || !filters.category) return [];
    const availableSubcategories = [];
    data.forEach(d => {
      if (d.category.name === filters.category) {
        availableSubcategories.push(d.subcategory.name);
      }
    });
    return uniq(availableSubcategories);
  }
);

export const getFilterOptionsByCategory = createSelector(
  [getCategory, getData, getAvailableSubcategories],
  (category, data, subcategories) => {
    if (!category || !data || isEmpty(data)) return null;
    const filters = FILTERS_BY_CATEGORY[category];
    const categoryOptions = {};
    filters.forEach(f => {
      const sanitizedFilterData = [];
      data.forEach(d => {
        if (d[f] !== null && d[f] !== '' && d[f] !== undefined) {
          const filterName = typeof d[f] === 'string' ? d[f] : d[f].name;
          sanitizedFilterData.push(filterName);
        }
      });
      let availableData = uniq(sanitizedFilterData);
      if (f === 'subcategory') {
        availableData = uniq(sanitizedFilterData).filter(
          d => subcategories.indexOf(d) > -1
        );
      }
      categoryOptions[f] = availableData.map(filterData => ({
        value: filterData,
        label: filterData
      }));
    });
    return categoryOptions;
  }
);

export const filterDataByBlackList = createSelector(
  [filteredDataByFilters, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    const whiteList = remove(
      Object.keys(data[0]),
      n => ESP_BLACKLIST[category].indexOf(n) === -1
    );
    return data.map(d => pick(d, whiteList));
  }
);

export const renameDataColumns = createSelector(
  [filterDataByBlackList, getCategory],
  (data, category) => {
    if (!data || isEmpty(data)) return null;
    if (category === 'models') {
      let renamedData = data;
      const changes = [{ old: 'maintainer_name', new: 'developed_by' }];
      renamedData = renamedData.map(d => {
        const updatedD = d;
        changes.forEach(change => {
          if (d[change.old]) {
            updatedD[change.new] = d[change.old];
            delete updatedD[change.old];
          }
        });
        return updatedD;
      });
      return renamedData;
    }
    return data;
  }
);

export default {
  renameDataColumns,
  titleLinks,
  filteredDataByFilters,
  getFilterOptionsByCategory,
  getSelectedFieldOptions
};
<|endoftext|>


<commit_before>(function() {
    var window = this,undefined, __$ = window._$

    //object initializarion
    _$ = window._$ = function(selector) {
        if (typeof selector === "string"){
            selector = document.querySelector(selector)
        }
        return new Pistol(selector)
    }

    //the custom javascript object
    Pistol = function(selector) {
        	this.selection = selector

    // ADDCLASS method
            this.addClass = function(input){
                this.selection.className = this.selection.className + " " + input
            }

    // CONTAINS method
            this.contains = function(input){
                for (i in this.selection) {
                        if (this.selection[i] == input) return true
                }
                return false
            }

    // EACH method
            this.each = function(callback){
                for (var i=0; i<this.selection.length; i++){
                        callback(this.selection[i], i)
                }
            }

    // INJECT method
            this.inject = function(callback){
                var accumulator = 0
                for (var i=0; i<this.selection.length; i++){
                        accumulator = callback(accumulator, this.selection[i], i)
                }
                return accumulator
            }

    // LAST method
            this.last = function(){
                return this.selection[this.selection.length - 1]
            }

    // ON method
            this.on = function(event,callback){
                if (event == "click"){
                    this.selection.onclick = callback
                }
            }

    // MAP method
            this.map = function(callback){
                var output = []
                for (var i=0; i<this.selection.length; i++){
                        output.push(callback(this.selection[i], i))
                }
                return output
            }

    // REMOVECLASS method
            this.removeClass = function(input){
                if (input){
                    var old = this.selection.className.split(' ')
                    var remove = input.split(' ')
                    var seen = [], diff = []
                    for ( var i = 0; i < remove.length; i++)
                        seen[remove[i]] = true
                    for ( var i = 0; i < old.length; i++)
                        if (!seen[old[i]])
                            diff.push(old[i])
                    this.selection.className = diff.join(' ')
                } else {
                    this.selection.className = ""
                }
            }

        }

})()<commit_msg>Added a very simple ajax function. No posting forms, but it can handle simple data. Note: this is because plain JavaScript AJAX is a BITCH.<commit_after>(function() {
  var window = this,undefined, __$ = window._$

    //object initializarion
    _$ = window._$ = function(selector) {
      if (typeof selector === "string"){
        selector = document.querySelector(selector)
      }
      return new Pistol(selector)
    }

    //the custom javascript object
    Pistol = function(selector) {
     this.selection = selector

    // ADDCLASS method
    this.addClass = function(input){
      this.selection.className = this.selection.className + " " + input
    }

    // CONTAINS method
    this.contains = function(input){
      for (i in this.selection) {
        if (this.selection[i] == input) return true
      }
    return false
  }

    // EACH method
    this.each = function(callback){
      for (var i=0; i<this.selection.length; i++){
        callback(this.selection[i], i)
      }
    }

    // INJECT method
    this.inject = function(callback){
      var accumulator = 0
      for (var i=0; i<this.selection.length; i++){
        accumulator = callback(accumulator, this.selection[i], i)
      }
      return accumulator
    }

    // LAST method
    this.last = function(){
      return this.selection[this.selection.length - 1]
    }

    // ON method
    this.on = function(event,callback){
      if (event == "click"){
        this.selection.onclick = callback
      }
    }

    // MAP method
    this.map = function(callback){
      var output = []
      for (var i=0; i<this.selection.length; i++){
        output.push(callback(this.selection[i], i))
      }
      return output
    }

    // REMOVECLASS method
    this.removeClass = function(input){
      if (input){
        var old = this.selection.className.split(' ')
        var remove = input.split(' ')
        var seen = [], diff = []
        for ( var i = 0; i < remove.length; i++)
          seen[remove[i]] = true
        for ( var i = 0; i < old.length; i++)
          if (!seen[old[i]])
            diff.push(old[i])
          this.selection.className = diff.join(' ')
        } else {
          this.selection.className = ""
        }
      }
    }

    // AJAX method
    // only works for simple requests so far, e.g. no sending forms
    // still useful for things like next buttons
    this.ajax = function(request_type, url) {
      function loadXMLDoc() {
        var xmlhttp = new XMLHttpRequest()

        xmlhttp.open(request_type, url, true)
        xmlhttp.send()
      }
    }
})()<|endoftext|>


<commit_before>/**
 * A shim layer to disable interactive vector features and markers
 * without having to hide or update them. It basically propagates all
 * the mouse events straight to the map, bypassing the layers
 */
L.Shim = L.Class.extend( /** @lends {L.Shim.prototype}  */ {

    includes: L.Mixin.Events,

    options: {
        className: 'leaflet-backdrop'
    },

    /**
     * @const
     * @type {Object}
     */
    statics: {
        EVENTS: 'click dblclick mouseover mouseout mousemove ' +
            'contextmenu touchstart touchend touchmove'
    },

    /**
     * @param  {Object} options
     *
     * @constructor
     * @extends {L.Mixin.Events}
     */
    initialize: function(options) {

        /**
         * Cached anchor point
         * @type {L.Point}
         */
        this._anchor = new L.Point(0, 0);

        L.Util.setOptions(this, options);
    },

    /**
     * @param {L.Map} map
     * @return {L.Shim} [description]
     */
    addTo: function(map) {
        this._map = map;
        map.addLayer(this);
        return this;
    },

    /**
     * @param  {L.Map} map
     */
    onAdd: function(map) {
        if (!this._container) {
            this._container = L.DomUtil.create('div', this.options.className);
            map._panes.popupPane.insertBefore(this._container,
                map._panes.popupPane.firstChild);
        }
        L.DomEvent.on(this._container,
            L.Shim.EVENTS,
            this._propagateEvents, this);

        map.on('zoomend moveend', this._update, this);

        this._update();
    },

    /**
     * @param  {L.Map} map
     * @return {L.Shim}
     */
    removeFrom: function(map) {
        if (this._container) {
            this._container.parentNode.removeChild(this._container);
            this._container = null;
        }
        map.removeLayer(this);
        return this;
    },

    /**
     * Updates dom element
     */
    _update: function() {
        var size = this._map.getSize(),
            position = this._map.containerPointToLayerPoint(this._anchor),
            style = this._container.style;

        style.width = size.x + 'px';
        style.height = size.y + 'px';

        L.DomUtil.setPosition(this._container, position);
    },

    /**
     * @param  {L.Map} map
     */
    onRemove: function(map) {
        L.DomEvent.off(this._container, L.Shim.EVENTS,
            this._propagateEvents, this);
        this._map.off('zoomend moveend', this._update, this);
    },

    /**
     * Bypass the layers
     * @param  {Event} e
     */
    _propagateEvents: function(e) {
        this._map.fire(e.type, e);
    }
});
<commit_msg>.onRemove()<commit_after>/**
 * A shim layer to disable interactive vector features and markers
 * without having to hide or update them. It basically propagates all
 * the mouse events straight to the map, bypassing the layers
 */
L.Shim = L.Class.extend( /** @lends {L.Shim.prototype}  */ {

    includes: L.Mixin.Events,

    options: {
        className: 'leaflet-backdrop'
    },

    /**
     * @const
     * @type {Object}
     */
    statics: {
        EVENTS: 'click dblclick mouseover mouseout mousemove ' +
            'contextmenu touchstart touchend touchmove'
    },

    /**
     * @param  {Object} options
     *
     * @constructor
     * @extends {L.Mixin.Events}
     */
    initialize: function(options) {

        /**
         * Cached anchor point
         * @type {L.Point}
         */
        this._anchor = new L.Point(0, 0);

        L.Util.setOptions(this, options);
    },

    /**
     * @param {L.Map} map
     * @return {L.Shim} [description]
     */
    addTo: function(map) {
        this._map = map;
        map.addLayer(this);
        return this;
    },

    /**
     * @param  {L.Map} map
     */
    onAdd: function(map) {
        if (!this._container) {
            this._container = L.DomUtil.create('div', this.options.className);
            map._panes.popupPane.insertBefore(this._container,
                map._panes.popupPane.firstChild);
        }
        L.DomEvent.on(this._container,
            L.Shim.EVENTS,
            this._propagateEvents, this);

        map.on('zoomend moveend', this._update, this);

        this._update();
    },

    /**
     * @param  {L.Map} map
     * @return {L.Shim}
     */
    removeFrom: function(map) {
        map.removeLayer(this);
        return this;
    },

    /**
     * Updates dom element
     */
    _update: function() {
        var size = this._map.getSize(),
            position = this._map.containerPointToLayerPoint(this._anchor),
            style = this._container.style;

        style.width = size.x + 'px';
        style.height = size.y + 'px';

        L.DomUtil.setPosition(this._container, position);
    },

    /**
     * @param  {L.Map} map
     */
    onRemove: function(map) {
        L.DomEvent.off(this._container, L.Shim.EVENTS,
            this._propagateEvents, this);
        if (this._container) {
            this._container.parentNode.removeChild(this._container);
            this._container = null;
        }
        this._map.off('zoomend moveend', this._update, this);
    },

    /**
     * Bypass the layers
     * @param  {Event} e
     */
    _propagateEvents: function(e) {
        this._map.fire(e.type, e);
    }
});
<|endoftext|>


<commit_before>/**
 * Filters
 * Gold Server - http://gold.psim.us/
 *
 * Manually sets filters for chatting and names.
 * In this, we also handle proxy connections with a blacklist feature.
 * Credits: jd, panpawn
 *
 * @license MIT license
 */
'use strict';

const fs = require('fs');

let adWhitelist = Config.adWhitelist ? Config.adWhitelist : [];
let adRegex = new RegExp("(play.pokemonshowdown.com\\/~~)(?!(" + adWhitelist.join('|') + "))", "g");

let bannedMessages = Config.bannedMessages ? Config.bannedMessages : [];

let watchPhrases = Config.watchPhrases ? Config.watchPhrases : [];
let watchUsers = Config.watchUsers ? Config.watchUsers : [];

let proxyWhitelist = Config.proxyWhitelist || false;

/*********************
 * Chatfilter Magic *
 * ******************/

exports.chatfilter = function (message, user, room, connection, targetUser) {
	user.lastActiveTime = Date.now();
	if (!room && !Users(targetUser)) targetUser = {name: 'unknown user'};

	// watch phrases and watch users
	let watchRoom = Rooms('watchroom') ? Rooms('watchroom') : false;
	if (watchRoom) {
		let watchWords = watchPhrases.filter(phrase => { return ~toId(message).indexOf(phrase); }).length;
		let watchUserslist = watchUsers.filter(name => { return ~user.userid.indexOf(name); }).length;
		if (!user.can('hotpatch') && watchWords >= 1 || watchUserslist >= 1) {
			watchRoom.add('|c|' + user.getIdentity() + '| __(' + (room ? "To " + room.id : "Private message to " + targetUser.name) + ")__ " + message).update();
		}
	}

	// global banned messages
	for (let x in bannedMessages) {
		if (message.toLowerCase().indexOf(bannedMessages[x]) > -1 && bannedMessages[x] !== '' && message.substr(0, 1) !== '/') {
			if (user.locked) return false;
			Punishments.lock(user, Date.now() + 7 * 24 * 60 * 60 * 1000, null, "Said a banned word: " + bannedMessages[x]);
			user.popup('You have been automatically locked for sending a message containing a banned word.');
			Monitor.log('[PornMonitor] ' + user.name + ' __(' + (room ? 'In ' + room.id : 'Private message to ' + targetUser.name) + ')__ was automatically locked (and shadow banned) for trying to say "' + message + '"');
			fs.appendFile('logs/modlog/modlog_staff.txt', '[' + (new Date().toJSON()) + '] (staff) ' + user.name + ' was locked from talking by the Server (' +
			bannedMessages[x] + ') (' + connection.ip + ')\n');
			Gold.pmUpperStaff(user.name + ' has been automatically locked for sending a message containing a banned word' +
			(room ? ". **Room:**" + room.id : " in a private message to " + targetUser.name + ".") + ' **Message:** ' + message, '~Server');
			Users.ShadowBan.addUser(user);
		}
	}

	// advertising
	let pre_matches = (message.match(/psim|psim.us|psim us|psm.us|psm us/g) || []).length;
	let final_check = (pre_matches >= 1 ? adWhitelist.filter(server => { return ~message.indexOf(server); }).length : 0);
	if (!user.can('hotpatch') && (pre_matches >= 1 && final_check === 0 || pre_matches >= 2 && final_check >= 1 || message.match(adRegex))) {
		if (user.locked) return false;
		if (!Users.ShadowBan.checkBanned(user)) {
			Users.ShadowBan.addUser(user);
			fs.appendFile('logs/modlog/modlog_staff.txt', '[' + (new Date().toJSON()) + '] (staff) ' + user.name + ' was shadow banned by the Server. (Advertising) (' + connection.ip + ')\n');
			Gold.pmUpperStaff(user.name + " has been sbanned for attempting to advertise" + (room ? ". **Room:**" + room.id : " in a private message to " + targetUser.name + ".") + " **Message:** " + message, "~Server");
			Monitor.log("[AdvMonitor] " + user.name + " has been sbanned for attempting to advertise" + (room ? ". **Room:** " + room.id : " in a private message to " + targetUser.name + ".") + " **Message:** " + message);
		}
	}
	return message;
};
Config.chatfilter = exports.chatfilter;

/*********************
 * Namefilter Magic *
 * ******************/
try {
	Config.bannedNames = fs.readFileSync('config/bannednames.txt', 'utf8').toLowerCase().split('\n');
} catch (e) {
	Config.bannedNames = [];
}

function loadBannedNames() {
	try {
		Config.bannedNames = fs.readFileSync('config/bannednames.txt', 'utf8').toLowerCase().split('\n');
	} catch (e) {
		Config.bannedNames = [];
	}
}
loadBannedNames();

Config.namefilter = function (name, user) {
	let badNames = Config.bannedNames, badHosts = Object.keys(Gold.lockedHosts), nameId = toId(name);
	for (let x in badNames) {
		if (nameId.indexOf(badNames[x]) > -1 && badNames[x] !== '') {
			Monitor.log('[NameFilter] should probably FR: ' + name);
		}
	}

	// Hostfilter stuff
	let conNum = Object.keys(user.connections).length - 1;
	let ip = user.connections[conNum].ip;
	let trusted = trustedHack(nameId);

	Dnsbl.reverse(ip).then(host => {
		if (!host) return;
		if (badHosts.length < 0) return; // there are no blacklisted hosts (yet)

		// handling "trusted" users...
		if (trusted) return;
		if (Gold.userData[toId(name)] && Gold.userData[toId(name)].proxywhitelist) return;
		if (proxyWhitelist && proxyWhitelist.includes(nameId)) return;

		badHosts.forEach(badHost => {
			if (host.includes(badHost)) {
				user.locked = '#hostfilter';
				user.updateIdentity();
				user.popup("|modal|You have been automatically locked due to being on a proxy known for spam and abuse.\n\nLog off PS! and try reconnecting without a proxy to be unlocked.");
				// Monitor.log("[ProxyMonitor] " + name + " (" + ip + ") has been automatically locked. (" + host + ")");
				return;
			}
		});
	});

	Gold.evadeMonitor(user, name);

	return name;
};

// deal with global ranked user's manually...
function trustedHack(name) {
	let nameId = toId(name);
	let userSymbol = (Users.usergroups[nameId] ? Users.usergroups[nameId].substr(0, 1) : ' ');
	let rankIndex = (Config.groupsranking.includes(userSymbol) ? Config.groupsranking.indexOf(userSymbol) : false);
	if (rankIndex && rankIndex > 0) return true;
	return false;
}

/*********************
 * Hostfilter Magic *
 * ******************/
Gold.lockedHosts = Object.create(null);

function loadHostBlacklist() {
	fs.readFile('config/lockedhosts.json', 'utf8', function (err, file) {
		if (err) return;
		Gold.lockedHosts = JSON.parse(file);
	});
}
loadHostBlacklist();

function saveHost() {
	fs.writeFileSync('config/lockedhosts.json', JSON.stringify(Gold.lockedHosts));
}

Gold.evadeMonitor = function (user, name, punished) {
	if (punished && punished.alts) { // handles when user is unlocked
		punished.alts.forEach(alt => {
			if (Gold.punishments[toId(alt)]) delete Gold.punishments[toId(alt)];
		});
		Gold.savePunishments();
		return;
	}
	let points = 0;
	let matched = false;
	let userAgent = user.useragent;
	let ip = user.latestIp;

	if (punished) {
		let tarId = toId(name); // since user.userid can be a guest number here...
		Object.keys(Gold.punishments).forEach(punished => {
			if (Gold.punishments[punished].ip === ip) matched = true;
		});
		if (!matched && !Gold.punishments[tarId]) {
			Gold.punishments[tarId] = {
				'useragent': userAgent,
				'ip': ip,
				'iprange': Gold.getIpRange(ip)[0],
				'ipclass': Gold.getIpRange(ip)[1],
				'type': punished.type,
				'exires': punished.expires,
			};
			Gold.savePunishments();
		}
	} else {
		if (user.locked || Users.ShadowBan.checkBanned(user) || trustedHack(name)) return;

		let reasons = [];
		let evader = '', offender = '';
		let alertStaff = false;
		let defaultAvatars = [1, 2, 101, 102, 169, 170, 265, 266];
		let punishedUsers = Object.keys(Gold.punishments);

		for (let i = 0; i < punishedUsers.length; i++) {
			offender = Gold.punishments[punishedUsers[i]];
			if (offender.ip === ip) break;
			if (reasons.length >= 3) break; // this should never happen
			if (offender.exires < Date.now()) {
				delete Gold.punishments[punishedUsers[i]];
				Gold.savePunishments();
			}
			if (offender.useragent && offender.useragent === userAgent) {
				points++;
				reasons.push(`have the same user agent`);
				evader = `${offender.type} user: ${punishedUsers[i]}`;
				alertStaff = true;
			}
			if (offender.iprange && ip.startsWith(offender.iprange)) {
				points++;
				reasons.push(`have the IPv4 class ${offender.ipclass} range (${offender.iprange}.*)`);
				evader = `${punishments[offender].type} user: ${punishedUsers[i]}`;
			}
			// this does not count AS a reason (points), but merely to add to the list of reasons
			if (defaultAvatars.includes(user.avatar)) {
				reasons.push(`have a default avatar`);
				points = points + 0.5;
			}
		}
		let staff = Rooms('staff');
		if (staff) {
			if (points >= 2) {
				Users.ShadowBan.addUser(name);
				staff.add(`[EvadeMonitor] SHADOWBANNED: ${name}, evading alt of ${evader} because they ${reasons.join(' and ')}`).update();
			} else if (points === 1.5) {
				staff.add(`[EvadeMonitor] SUSPECTED EVADER: ${name} is possibly an evading alt of ${evader} because they ${reasons.join(' and ')}.`).update();
			}
		}
	}
};

exports.commands = {
	lockhost: function (target, room, user) {
		if (!this.can('pban')) return false;
		if (!target) return this.parse('/help lockhost');
		if (Gold.lockedHosts[target]) return this.errorReply("The host '" + target + "' is was already locked by " + Gold.lockedHosts[target].by + ".");

		Gold.lockedHosts[target] = {
			by: user.name,
			on: Date.now(),
		};
		saveHost();

		this.privateModCommand("(" + user.name + " has blacklisted host: " + target + ")");
	},
	lockhosthelp: ["/lockhost [host] - Adds host to server blacklist.  Users connecting with these hosts will be automatically locked from connection, so use this carefully! Requires & ~"],

	unlockhost: function (target, room, user) {
		if (!this.can('pban')) return false;
		if (!target) return this.parse('/help unlockhost');
		if (!Gold.lockedHosts[target]) return this.errorReply("The host '" + target + "' is not currently blacklisted.");

		delete Gold.lockedHosts[target];
		saveHost();

		this.privateModCommand("(" + user.name + " has unblacklisted host: " + target + ")");
	},
	unlockhosthelp: ["/unlockhost [host] - Removes a host from the server's blacklist.  Requires & ~"],

	proxylist: function (target, room, user) {
		if (!this.can('pban')) return false;
		let badHosts = Object.keys(Gold.lockedHosts);
		if (badHosts.length < 0) return this.errorReply("Weird, no proxies have been blacklisted (yet).");

		let buff = '

Proxy:	Blacklisted By:	Blacklisted:
';
		badHosts.forEach(proxy => {
			buff += '
' + proxy + '	' + Gold.nameColor(Gold.lockedHosts[proxy].by, false) + '	' + Chat.toDurationString(Date.now() - Gold.lockedHosts[proxy].on) + ' ago
';
		});
		buff += '
';

		return this.sendReplyBox(buff);
	},
};
<commit_msg>Fix having repeated reasons in evade monitor<commit_after>/**
 * Filters
 * Gold Server - http://gold.psim.us/
 *
 * Manually sets filters for chatting and names.
 * In this, we also handle proxy connections with a blacklist feature.
 * Credits: jd, panpawn
 *
 * @license MIT license
 */
'use strict';

const fs = require('fs');

let adWhitelist = Config.adWhitelist ? Config.adWhitelist : [];
let adRegex = new RegExp("(play.pokemonshowdown.com\\/~~)(?!(" + adWhitelist.join('|') + "))", "g");

let bannedMessages = Config.bannedMessages ? Config.bannedMessages : [];

let watchPhrases = Config.watchPhrases ? Config.watchPhrases : [];
let watchUsers = Config.watchUsers ? Config.watchUsers : [];

let proxyWhitelist = Config.proxyWhitelist || false;

/*********************
 * Chatfilter Magic *
 * ******************/

exports.chatfilter = function (message, user, room, connection, targetUser) {
	user.lastActiveTime = Date.now();
	if (!room && !Users(targetUser)) targetUser = {name: 'unknown user'};

	// watch phrases and watch users
	let watchRoom = Rooms('watchroom') ? Rooms('watchroom') : false;
	if (watchRoom) {
		let watchWords = watchPhrases.filter(phrase => { return ~toId(message).indexOf(phrase); }).length;
		let watchUserslist = watchUsers.filter(name => { return ~user.userid.indexOf(name); }).length;
		if (!user.can('hotpatch') && watchWords >= 1 || watchUserslist >= 1) {
			watchRoom.add('|c|' + user.getIdentity() + '| __(' + (room ? "To " + room.id : "Private message to " + targetUser.name) + ")__ " + message).update();
		}
	}

	// global banned messages
	for (let x in bannedMessages) {
		if (message.toLowerCase().indexOf(bannedMessages[x]) > -1 && bannedMessages[x] !== '' && message.substr(0, 1) !== '/') {
			if (user.locked) return false;
			Punishments.lock(user, Date.now() + 7 * 24 * 60 * 60 * 1000, null, "Said a banned word: " + bannedMessages[x]);
			user.popup('You have been automatically locked for sending a message containing a banned word.');
			Monitor.log('[PornMonitor] ' + user.name + ' __(' + (room ? 'In ' + room.id : 'Private message to ' + targetUser.name) + ')__ was automatically locked (and shadow banned) for trying to say "' + message + '"');
			fs.appendFile('logs/modlog/modlog_staff.txt', '[' + (new Date().toJSON()) + '] (staff) ' + user.name + ' was locked from talking by the Server (' +
			bannedMessages[x] + ') (' + connection.ip + ')\n');
			Gold.pmUpperStaff(user.name + ' has been automatically locked for sending a message containing a banned word' +
			(room ? ". **Room:**" + room.id : " in a private message to " + targetUser.name + ".") + ' **Message:** ' + message, '~Server');
			Users.ShadowBan.addUser(user);
		}
	}

	// advertising
	let pre_matches = (message.match(/psim|psim.us|psim us|psm.us|psm us/g) || []).length;
	let final_check = (pre_matches >= 1 ? adWhitelist.filter(server => { return ~message.indexOf(server); }).length : 0);
	if (!user.can('hotpatch') && (pre_matches >= 1 && final_check === 0 || pre_matches >= 2 && final_check >= 1 || message.match(adRegex))) {
		if (user.locked) return false;
		if (!Users.ShadowBan.checkBanned(user)) {
			Users.ShadowBan.addUser(user);
			fs.appendFile('logs/modlog/modlog_staff.txt', '[' + (new Date().toJSON()) + '] (staff) ' + user.name + ' was shadow banned by the Server. (Advertising) (' + connection.ip + ')\n');
			Gold.pmUpperStaff(user.name + " has been sbanned for attempting to advertise" + (room ? ". **Room:**" + room.id : " in a private message to " + targetUser.name + ".") + " **Message:** " + message, "~Server");
			Monitor.log("[AdvMonitor] " + user.name + " has been sbanned for attempting to advertise" + (room ? ". **Room:** " + room.id : " in a private message to " + targetUser.name + ".") + " **Message:** " + message);
		}
	}
	return message;
};
Config.chatfilter = exports.chatfilter;

/*********************
 * Namefilter Magic *
 * ******************/
try {
	Config.bannedNames = fs.readFileSync('config/bannednames.txt', 'utf8').toLowerCase().split('\n');
} catch (e) {
	Config.bannedNames = [];
}

function loadBannedNames() {
	try {
		Config.bannedNames = fs.readFileSync('config/bannednames.txt', 'utf8').toLowerCase().split('\n');
	} catch (e) {
		Config.bannedNames = [];
	}
}
loadBannedNames();

Config.namefilter = function (name, user) {
	let badNames = Config.bannedNames, badHosts = Object.keys(Gold.lockedHosts), nameId = toId(name);
	for (let x in badNames) {
		if (nameId.indexOf(badNames[x]) > -1 && badNames[x] !== '') {
			Monitor.log('[NameFilter] should probably FR: ' + name);
		}
	}

	// Hostfilter stuff
	let conNum = Object.keys(user.connections).length - 1;
	let ip = user.connections[conNum].ip;
	let trusted = trustedHack(nameId);

	Dnsbl.reverse(ip).then(host => {
		if (!host) return;
		if (badHosts.length < 0) return; // there are no blacklisted hosts (yet)

		// handling "trusted" users...
		if (trusted) return;
		if (Gold.userData[toId(name)] && Gold.userData[toId(name)].proxywhitelist) return;
		if (proxyWhitelist && proxyWhitelist.includes(nameId)) return;

		badHosts.forEach(badHost => {
			if (host.includes(badHost)) {
				user.locked = '#hostfilter';
				user.updateIdentity();
				user.popup("|modal|You have been automatically locked due to being on a proxy known for spam and abuse.\n\nLog off PS! and try reconnecting without a proxy to be unlocked.");
				// Monitor.log("[ProxyMonitor] " + name + " (" + ip + ") has been automatically locked. (" + host + ")");
				return;
			}
		});
	});

	Gold.evadeMonitor(user, name);

	return name;
};

// deal with global ranked user's manually...
function trustedHack(name) {
	let nameId = toId(name);
	let userSymbol = (Users.usergroups[nameId] ? Users.usergroups[nameId].substr(0, 1) : ' ');
	let rankIndex = (Config.groupsranking.includes(userSymbol) ? Config.groupsranking.indexOf(userSymbol) : false);
	if (rankIndex && rankIndex > 0) return true;
	return false;
}

/*********************
 * Hostfilter Magic *
 * ******************/
Gold.lockedHosts = Object.create(null);

function loadHostBlacklist() {
	fs.readFile('config/lockedhosts.json', 'utf8', function (err, file) {
		if (err) return;
		Gold.lockedHosts = JSON.parse(file);
	});
}
loadHostBlacklist();

function saveHost() {
	fs.writeFileSync('config/lockedhosts.json', JSON.stringify(Gold.lockedHosts));
}

Gold.evadeMonitor = function (user, name, punished) {
	if (punished && punished.alts) { // handles when user is unlocked
		punished.alts.forEach(alt => {
			if (Gold.punishments[toId(alt)]) delete Gold.punishments[toId(alt)];
		});
		Gold.savePunishments();
		return;
	}
	let points = 0;
	let matched = false;
	let userAgent = user.useragent;
	let ip = user.latestIp;

	if (punished) {
		let tarId = toId(name); // since user.userid can be a guest number here...
		Object.keys(Gold.punishments).forEach(punished => {
			if (Gold.punishments[punished].ip === ip) matched = true;
		});
		if (!matched && !Gold.punishments[tarId]) {
			Gold.punishments[tarId] = {
				'useragent': userAgent,
				'ip': ip,
				'iprange': Gold.getIpRange(ip)[0],
				'ipclass': Gold.getIpRange(ip)[1],
				'type': punished.type,
				'exires': punished.expires,
			};
			Gold.savePunishments();
		}
	} else {
		if (user.locked || Users.ShadowBan.checkBanned(user) || trustedHack(name)) return;

		let reasons = [];
		let evader = '', offender = '', reason = '';
		let alertStaff = false;
		let defaultAvatars = [1, 2, 101, 102, 169, 170, 265, 266];
		let punishedUsers = Object.keys(Gold.punishments);

		for (let i = 0; i < punishedUsers.length; i++) {
			offender = Gold.punishments[punishedUsers[i]];
			if (offender.ip === ip) break;
			if (reasons.length >= 3) break; // this should never happen
			if (offender.exires < Date.now()) {
				delete Gold.punishments[punishedUsers[i]];
				Gold.savePunishments();
			}
			if (offender.useragent && offender.useragent === userAgent) {
				reason = `have the same user agent`;
				if (!reasons.includes(reason)) {
					points++;
					reasons.push(reason);
					evader = `${offender.type} user: ${punishedUsers[i]}`;
					alertStaff = true;
				}
			}
			if (offender.iprange && ip.startsWith(offender.iprange)) {
				reason = `have the IPv4 class ${offender.ipclass} range (${offender.iprange}.*)`;
				if (!reasons.includes(reason)) {
					points++;
					reasons.push(reason);
					evader = `${punishments[offender].type} user: ${punishedUsers[i]}`;
				}
			}
			// this does not count AS a reason (points), but merely to add to the list of reasons
			if (defaultAvatars.includes(user.avatar)) {
				reason = `have a default avatar`;
				if (!reasons.includes(reason)) {
					reasons.push(reason);
					points = points + 0.5;
				}
			}
		}
		let staff = Rooms('staff');
		if (staff) {
			if (points >= 2) {
				Users.ShadowBan.addUser(name);
				staff.add(`[EvadeMonitor] SHADOWBANNED: ${name}, evading alt of ${evader} because they ${reasons.join(' and ')}`).update();
			} else if (points === 1.5) {
				staff.add(`[EvadeMonitor] SUSPECTED EVADER: ${name} is possibly an evading alt of ${evader} because they ${reasons.join(' and ')}.`).update();
			}
		}
	}
};

exports.commands = {
	lockhost: function (target, room, user) {
		if (!this.can('pban')) return false;
		if (!target) return this.parse('/help lockhost');
		if (Gold.lockedHosts[target]) return this.errorReply("The host '" + target + "' is was already locked by " + Gold.lockedHosts[target].by + ".");

		Gold.lockedHosts[target] = {
			by: user.name,
			on: Date.now(),
		};
		saveHost();

		this.privateModCommand("(" + user.name + " has blacklisted host: " + target + ")");
	},
	lockhosthelp: ["/lockhost [host] - Adds host to server blacklist.  Users connecting with these hosts will be automatically locked from connection, so use this carefully! Requires & ~"],

	unlockhost: function (target, room, user) {
		if (!this.can('pban')) return false;
		if (!target) return this.parse('/help unlockhost');
		if (!Gold.lockedHosts[target]) return this.errorReply("The host '" + target + "' is not currently blacklisted.");

		delete Gold.lockedHosts[target];
		saveHost();

		this.privateModCommand("(" + user.name + " has unblacklisted host: " + target + ")");
	},
	unlockhosthelp: ["/unlockhost [host] - Removes a host from the server's blacklist.  Requires & ~"],

	proxylist: function (target, room, user) {
		if (!this.can('pban')) return false;
		let badHosts = Object.keys(Gold.lockedHosts);
		if (badHosts.length < 0) return this.errorReply("Weird, no proxies have been blacklisted (yet).");

		let buff = '

Proxy:	Blacklisted By:	Blacklisted:
';
		badHosts.forEach(proxy => {
			buff += '
' + proxy + '	' + Gold.nameColor(Gold.lockedHosts[proxy].by, false) + '	' + Chat.toDurationString(Date.now() - Gold.lockedHosts[proxy].on) + ' ago
';
		});
		buff += '
';

		return this.sendReplyBox(buff);
	},
};
<|endoftext|>


<commit_before>function httpGet(theUrl)
{
    var xmlHttp = null;

    xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", theUrl, false );
    xmlHttp.send( null );
    return xmlHttp.responseText;
}

function checkform(){
	var str = window.location.pathname;
	var isbaha = httpGet(window.location.origin + str.replace("/use.php", "") + "/API/isbaha.php?name=" + document.getElementById("Name").value);
	if(isbaha == "1"){
      	return true;
	}else{
		flash('#Name',8,10,100);
		return false;
	}
}

function isEmail() {
	if (document.getElementById("email").value.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/)!= -1){
		return true;
	}else{
		flash('#email',8,10,100);
		return false;
	}
}

function sub(){
document.getElementById('verify').value="傳送中...";
document.getElementById('verify').disabled="disabled";
var name = document.getElementById('Name').value;
$.ajax({
  type: 'POST',
  url: "sendverify.php",
  data: { Name: name },
  success: function(data) {
                      $("#msg").html(data);
                  },
  async:false
});
$(".f1").stop(true,false).animate({left:'-=500px',opacity: 0});
$(".f2").stop(true,false).animate({right:'0px',opacity: 1});
}

function sub2(){
document.getElementById('verify').value="傳送中...";
document.getElementById('verify').disabled="disabled";
var name = document.getElementById('name').value;
var hash = document.getElementById('hash').value;
var email = document.getElementById('email').value;
$.ajax({
  type: 'POST',
  url: "sendmailverify.php",
  data: { name: name , hash: hash , email: email},
  success: function(data) {
                      $("#msg").html(data);
                  },
  async:false
});
$(".f1").stop(true,false).animate({left:'-=500px',opacity: 0});
$(".f2").stop(true,false).animate({right:'0px',opacity: 1});
}

<commit_msg>Fix issue #26<commit_after>function httpGet(theUrl)
{
    var xmlHttp = null;

    xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", theUrl, false );
    xmlHttp.send( null );
    return xmlHttp.responseText;
}

function checkform(){
	var str = window.location.pathname;
	var isbaha = httpGet(window.location.origin + str.replace("/use.php", "") + "/API/isbaha.php?name=" + document.getElementById("Name").value);
	if(isbaha == "1"){
      	return true;
	}else{
		flash('#Name',8,10,100);
		return false;
	}
}

function isEmail() {
	if (document.getElementById("email").value.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]+$/)!= -1){
		return true;
	}else{
		flash('#email',8,10,100);
		return false;
	}
}

function sub(){
document.getElementById('verify').value="傳送中...";
document.getElementById('verify').disabled="disabled";
var name = document.getElementById('Name').value;
document.getElementById('verify').value="傳送中......";
$.ajax({
  type: 'POST',
  url: "sendverify.php",
  data: { Name: name },
  success: function(data) {
                      $("#msg").html(data);
                  },
  async:false
});
$(".f1").stop(true,false).animate({left:'-=500px',opacity: 0});
$(".f2").stop(true,false).animate({right:'0px',opacity: 1});
}

function sub2(){
document.getElementById('verify').value="傳送中...";
document.getElementById('verify').disabled="disabled";
var name = document.getElementById('name').value;
var hash = document.getElementById('hash').value;
var email = document.getElementById('email').value;
document.getElementById('verify').value="傳送中......";
$.ajax({
  type: 'POST',
  url: "sendmailverify.php",
  data: { name: name , hash: hash , email: email},
  success: function(data) {
                      $("#msg").html(data);
                  },
  async:false
});
$(".f1").stop(true,false).animate({left:'-=500px',opacity: 0});
$(".f2").stop(true,false).animate({right:'0px',opacity: 1});
}

<|endoftext|>


<commit_before>// A number of mathematical helper functions that have nothing to do with eweda itself, but might be used in
// conjunction with some eweda exapmles.

// Simple, tail-recursive version of Fibonacci. Should run in nearly O(n).
var fibonacci = (function() {
    var fib = function(curr, next, n) {
        return  (n === 0) ? curr : fib(next, curr + next, n - 1);
    };
    return function(n) {
        return fib(0, 1, n);
    }
}());

// Sieve of Eratosthenes to find primes up to `max`.
var primeSieve = function(max) {
    var D = [], primes = [];
    for (var q = 2; q < max; q++) {
        if (D[q]) {
            for (var i = 0; i < D[q].length; i++) {
                 var p = D[q][i];
                 if (D[p + q]) {
                     D[p + q].push(p);
                 } else {
                     D[p + q] = [p];
                 }
            }
            delete D[q];
        } else {
            primes.push(q);
            if (q * q < max) D[q * q] = [q];
        }
    }
    return primes;
};

// Variation of Sieve of Eratosthenes to find nth prime
var nthPrime = function(n) {
    var D = [];
    var q = 2, count = 0;
    while (count < n) {
        if (D[q]) {
            for (var i = 0; i < D[q].length; i++) {
                 var p = D[q][i];
                 if (D[p + q]) D[p + q].push(p);
                 else D[p + q] = [p];
            }
            delete D[q];
        } else {
            count++;
            D[q * q] = [q];
        }
        q++;
    }
    return q - 1;
};

// Another variation to list the prime factors of all numbers up to `max`.
var allPrimeFactors = function(max) {
    var D = {0: [], 1: []};
    for (var q = 2; q < max; q++) {
        if (D[q]) {
            for (var i = 0; i < D[q].length; i++) {
                 var p = D[q][i];
                 if (D[p + q]) {
                     D[p + q].push(p);
                 } else {
                     D[p + q] = [p];
                 }
            }
        } else {
            D[q] = [q];
            if (2 * q < max) D[2 * q] = [q];
        }
    }
    return D;
};

// Another variation, which repeatedly iterates through the (memoized) primes, with `next`, and `reset`
var primes =  (function () {
    var cache = [];
    var ctr = 0;
    var nthPrime = function(n) {
        var D = [];
        var q = 2, count = 0;
        while (count < n) {
            if (D[q]) {
                for (var i = 0; i < D[q].length; i++) {
                     var p = D[q][i];
                     if (D[p + q]) D[p + q].push(p);
                     else D[p + q] = [p];
                }
                delete D[q];
            } else {
                count++;
                D[q * q] = [q];
            }
            q++;
        }
        return q - 1;
    };

    return {
        next: function() {
            while (cache.length <= ctr) {
                cache[cache.length] = nthPrime(cache.length + 1);
            }
            return cache[ctr++];
        },
        reset: function() {ctr = 0;}
    }
}());

// brain-dead implementation of BigInteger, just like you did in grade school.
// BigInteger represents, e.g. 152, as ['2', '5', '1'], a reversed list of String digits.  If a String representation is
// needed, call `bigInt.join('').reverse()`.

var bigint = function(n) {return ('' + n).split('').reverse();};
var bi2s = function(bi) {return bi.join(",").split(",").reverse().join('');}; // need a better clone than .join(",").split(","), but I'm tired...

// brain-dead BigInteger implementation of add function.
var add = function(a, b) {
    while (a.length < b.length) a[a.length] = 0;
    while (a.length > b.length) b[b.length] = 0;
    var carry = 0, total = [];
    for (var i = 0; i < a.length; i++) {
        var sum = a[i] + b[i] + carry;
        if (sum >= 10) {
            sum = sum - 10;
            carry = 1;
        } else {
            carry = 0;
        }
        total[total.length] = sum;
    }
    if (carry) {
        total[total.length] = carry;
    }
    return total;
};

// brain-dead BigInteger implementation of add function.
var mult = function(a, b) {
    var total = [0];
    for (var i = 0; i < a.length; i++) {
        for (var j = 0; j < b.length; j++) {
            var digit = a[i] * b[j];
            digit = (digit > 9) ? [digit % 10, (digit - (digit % 10)) / 10] : [digit];
            total = add(total, Array(i + 1).join("0").split("").map(Number).concat(Array(j + 1).join("0").split("").map(Number)).concat(digit));
        }
    }
    return total;
};

// Greatest Common Divisor
var gcd = function (m, n) {
    return m === 0 ? n : gcd(n % m, m);
};

// Least Common Multiple
var lcm = function (m, n) {
    return m * n / gcd(m , n);
};

//  / n \  n choose k
//  \ k /  i.e. ways to choose k elements (without replacement) from a set of n elements.
var choose = (function() {
    var _choose = function(n, k, i, acc) {
        return (i == k) ? (acc * (n - k + 1)) / k : _choose(n, k, i + 1, (acc * (n - i + 1)) / i);
    };
    return function(n, k) {
        return n < 0 || k < 0 || n < k ? 0 : _choose(n, k, 1, 1);
    };
}());

// Horribly inefficient, even if clean
//   var choose = memoize(function choose(n, r) {
//       return result = n < r ? 0 : (r == 0 || r == n) ? 1 : choose(n - 1, r - 1) + choose(n -1, r);
//   });

// Returns an array containing all the factors of n;
var divisors = function(n) {
    var factors = [];
    for (var i = 1; i <= Math.sqrt(n); i++) {
        if (!(n % i)) {
            factors.push(i);
            if (i * i < n) factors.push(n / i);
        }
    }
    factors.sort(function(a, b) {return a - b;});
    return factors;
};

// Returns an array containing all the proper factors of n;
var properDivisors = function(n) {
    var factors = [1];
    for (var i = 2; i <= Math.sqrt(n); i++) {
        if (!(n % i)) {
            factors.push(i);
            if (i * i < n) factors.push(n / i);
        }
    }
    factors.sort(function(a, b) {return a - b;});
    return factors;
};

var factorial = memoize(function fact(n) {
    return n < 2 ? 1: n * fact(n - 1);
});

var max = foldl(Math.max, Number.NEGATIVE_INFINITY);
var maxOver = function(fn, list) {return foldl1(fn, list); };

var min = foldl(Math.max, Number.POSITIVE_INFINITY);
var minOver = function(fn, list) {return foldl1(fn, list); };

var split = curry(function(chr, str) {
   return str.split(chr);
});<commit_msg>Adding `digits` to math exsmple script -- useful for Euler problems.<commit_after>// A number of mathematical helper functions that have nothing to do with eweda itself, but might be used in
// conjunction with some eweda exapmles.

// Simple, tail-recursive version of Fibonacci. Should run in nearly O(n).
var fibonacci = (function() {
    var fib = function(curr, next, n) {
        return  (n === 0) ? curr : fib(next, curr + next, n - 1);
    };
    return function(n) {
        return fib(0, 1, n);
    }
}());

// Sieve of Eratosthenes to find primes up to `max`.
var primeSieve = function(max) {
    var D = [], primes = [];
    for (var q = 2; q < max; q++) {
        if (D[q]) {
            for (var i = 0; i < D[q].length; i++) {
                 var p = D[q][i];
                 if (D[p + q]) {
                     D[p + q].push(p);
                 } else {
                     D[p + q] = [p];
                 }
            }
            delete D[q];
        } else {
            primes.push(q);
            if (q * q < max) D[q * q] = [q];
        }
    }
    return primes;
};

// Variation of Sieve of Eratosthenes to find nth prime
var nthPrime = function(n) {
    var D = [];
    var q = 2, count = 0;
    while (count < n) {
        if (D[q]) {
            for (var i = 0; i < D[q].length; i++) {
                 var p = D[q][i];
                 if (D[p + q]) D[p + q].push(p);
                 else D[p + q] = [p];
            }
            delete D[q];
        } else {
            count++;
            D[q * q] = [q];
        }
        q++;
    }
    return q - 1;
};

// Another variation to list the prime factors of all numbers up to `max`.
var allPrimeFactors = function(max) {
    var D = {0: [], 1: []};
    for (var q = 2; q < max; q++) {
        if (D[q]) {
            for (var i = 0; i < D[q].length; i++) {
                 var p = D[q][i];
                 if (D[p + q]) {
                     D[p + q].push(p);
                 } else {
                     D[p + q] = [p];
                 }
            }
        } else {
            D[q] = [q];
            if (2 * q < max) D[2 * q] = [q];
        }
    }
    return D;
};

// Another variation, which repeatedly iterates through the (memoized) primes, with `next`, and `reset`
var primes =  (function () {
    var cache = [];
    var ctr = 0;
    var nthPrime = function(n) {
        var D = [];
        var q = 2, count = 0;
        while (count < n) {
            if (D[q]) {
                for (var i = 0; i < D[q].length; i++) {
                     var p = D[q][i];
                     if (D[p + q]) D[p + q].push(p);
                     else D[p + q] = [p];
                }
                delete D[q];
            } else {
                count++;
                D[q * q] = [q];
            }
            q++;
        }
        return q - 1;
    };

    return {
        next: function() {
            while (cache.length <= ctr) {
                cache[cache.length] = nthPrime(cache.length + 1);
            }
            return cache[ctr++];
        },
        reset: function() {ctr = 0;}
    }
}());

// brain-dead implementation of BigInteger, just like you did in grade school.
// BigInteger represents, e.g. 152, as ['2', '5', '1'], a reversed list of String digits.  If a String representation is
// needed, call `bigInt.join('').reverse()`.

var bigint = function(n) {return ('' + n).split('').reverse();};
var bi2s = function(bi) {return bi.join(",").split(",").reverse().join('');}; // need a better clone than .join(",").split(","), but I'm tired...

// brain-dead BigInteger implementation of add function.
var add = function(a, b) {
    while (a.length < b.length) a[a.length] = 0;
    while (a.length > b.length) b[b.length] = 0;
    var carry = 0, total = [];
    for (var i = 0; i < a.length; i++) {
        var sum = a[i] + b[i] + carry;
        if (sum >= 10) {
            sum = sum - 10;
            carry = 1;
        } else {
            carry = 0;
        }
        total[total.length] = sum;
    }
    if (carry) {
        total[total.length] = carry;
    }
    return total;
};

// brain-dead BigInteger implementation of add function.
var mult = function(a, b) {
    var total = [0];
    for (var i = 0; i < a.length; i++) {
        for (var j = 0; j < b.length; j++) {
            var digit = a[i] * b[j];
            digit = (digit > 9) ? [digit % 10, (digit - (digit % 10)) / 10] : [digit];
            total = add(total, Array(i + 1).join("0").split("").map(Number).concat(Array(j + 1).join("0").split("").map(Number)).concat(digit));
        }
    }
    return total;
};

// Greatest Common Divisor
var gcd = function (m, n) {
    return m === 0 ? n : gcd(n % m, m);
};

// Least Common Multiple
var lcm = function (m, n) {
    return m * n / gcd(m , n);
};

//  / n \  n choose k
//  \ k /  i.e. ways to choose k elements (without replacement) from a set of n elements.
var choose = (function() {
    var _choose = function(n, k, i, acc) {
        return (i == k) ? (acc * (n - k + 1)) / k : _choose(n, k, i + 1, (acc * (n - i + 1)) / i);
    };
    return function(n, k) {
        return n < 0 || k < 0 || n < k ? 0 : _choose(n, k, 1, 1);
    };
}());

// Horribly inefficient, even if clean
//   var choose = memoize(function choose(n, r) {
//       return result = n < r ? 0 : (r == 0 || r == n) ? 1 : choose(n - 1, r - 1) + choose(n -1, r);
//   });

// Returns an array containing all the factors of n;
var divisors = function(n) {
    var factors = [];
    for (var i = 1; i <= Math.sqrt(n); i++) {
        if (!(n % i)) {
            factors.push(i);
            if (i * i < n) factors.push(n / i);
        }
    }
    factors.sort(function(a, b) {return a - b;});
    return factors;
};

// Returns an array containing all the proper factors of n;
var properDivisors = function(n) {
    var factors = [1];
    for (var i = 2; i <= Math.sqrt(n); i++) {
        if (!(n % i)) {
            factors.push(i);
            if (i * i < n) factors.push(n / i);
        }
    }
    factors.sort(function(a, b) {return a - b;});
    return factors;
};

var factorial = memoize(function fact(n) {
    return n < 2 ? 1: n * fact(n - 1);
});

var max = foldl(Math.max, Number.NEGATIVE_INFINITY);
var maxOver = function(fn, list) {return foldl1(fn, list); };

var min = foldl(Math.max, Number.POSITIVE_INFINITY);
var minOver = function(fn, list) {return foldl1(fn, list); };

var split = curry(function(chr, str) {
   return str.split(chr);
});

var digits = function(number) {
	return ('' + number).split('');
};

var eq = curry(function(a, b) {
	return a === b;
});<|endoftext|>


<commit_before>// Js_of_ocaml runtime support
// http://www.ocsigen.org/js_of_ocaml/
// Copyright (C) 2010 Jérôme Vouillon
// Laboratoire PPS - CNRS Université Paris Diderot
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, with linking exception;
// either version 2.1 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

//Provides: jsoo_floor_log2
var log2_ok = Math.log2 && Math.log2(1.1235582092889474E+307) == 1020
function jsoo_floor_log2(x) {
    if(log2_ok) return Math.floor(Math.log2(x))
    var i = 0;
    if (x == 0) return -Infinity;
    if(x>=1) {while (x>=2) {x/=2; i++} }
    else {while (x < 1) {x*=2; i--} };
    return i;
}

//Provides: caml_int64_bits_of_float const
//Requires: jsoo_floor_log2
function caml_int64_bits_of_float (x) {
  if (!isFinite(x)) {
    if (isNaN(x)) return [255, 1, 0, 0xfff0];
    return (x > 0)?[255,0,0,0x7ff0]:[255,0,0,0xfff0];
  }
  var sign = (x==0 && 1/x == -Infinity)?0x8000:(x>=0)?0:0x8000;
  if (sign) x = -x;
  // Int64.bits_of_float 1.1235582092889474E+307 = 0x7fb0000000000000L
  // using Math.LOG2E*Math.log(x) in place of Math.log2 result in precision lost
  var exp = jsoo_floor_log2(x) + 1023;
  if (exp <= 0) {
    exp = 0;
    x /= Math.pow(2,-1026);
  } else {
    x /= Math.pow(2,exp-1027);
    if (x < 16) {
      x *= 2; exp -=1; }
    if (exp == 0) {
      x /= 2; }
  }
  var k = Math.pow(2,24);
  var r3 = x|0;
  x = (x - r3) * k;
  var r2 = x|0;
  x = (x - r2) * k;
  var r1 = x|0;
  r3 = (r3 &0xf) | sign | exp << 4;
  return [255, r1, r2, r3];
}

//FP literals can be written using the hexadecimal
//notation 0x<mantissa in hex>p<exponent> from ISO C99.
//https://github.com/dankogai/js-hexfloat/blob/master/hexfloat.js
//Provides: caml_hexstring_of_float const
//Requires: caml_js_to_string, caml_str_repeat
function caml_hexstring_of_float (x, prec, style) {
  if (!isFinite(x)) {
    if (isNaN(x)) return caml_js_to_string("nan");
    return caml_js_to_string ((x > 0)?"infinity":"-infinity");
  }
  var sign = (x==0 && 1/x == -Infinity)?1:(x>=0)?0:1;
  if(sign) x = -x;
  var exp = 0;
  if (x == 0) { }
  else if (x < 1) {
    while (x < 1)  { x *= 2; exp-- }
  } else {
    while (x >= 2) { x /= 2; exp++ }
  }
  var exp_sign = exp < 0 ? '' : '+';
  var sign_str = '';
  if (sign) sign_str = '-'
  else {
    switch(style){
    case 43 /* '+' */: sign_str = '+'; break;
    case 32 /* ' ' */: sign_str = ' '; break;
    default: break;
    }
  }
  if (prec >= 0 && prec < 13) {
    /* If a precision is given, and is small, round mantissa accordingly */
      var cst = Math.pow(2,prec * 4);
      x = Math.round(x * cst) / cst;
  }
  var x_str = x.toString(16);
  if(prec >= 0){
      var idx = x_str.indexOf('.');
    if(idx<0) {
      x_str += '.' + caml_str_repeat(prec, '0');
    }
    else {
      var size = idx+1+prec;
      if(x_str.length < size)
        x_str += caml_str_repeat(size - x_str.length, '0');
      else
        x_str = x_str.substr(0,size);
    }
  }
  return caml_js_to_string (sign_str + '0x' + x_str + 'p' + exp_sign + exp.toString(10));
}

//Provides: caml_int64_float_of_bits const
function caml_int64_float_of_bits (x) {
  var exp = (x[3] & 0x7fff) >> 4;
  if (exp == 2047) {
      if ((x[1]|x[2]|(x[3]&0xf)) == 0)
        return (x[3] & 0x8000)?(-Infinity):Infinity;
      else
        return NaN;
  }
  var k = Math.pow(2,-24);
  var res = (x[1]*k+x[2])*k+(x[3]&0xf);
  if (exp > 0) {
    res += 16;
    res *= Math.pow(2,exp-1027);
  } else
    res *= Math.pow(2,-1026);
  if (x[3] & 0x8000) res = - res;
  return res;
}
//Provides: caml_classify_float const
function caml_classify_float (x) {
  if (isFinite (x)) {
    if (Math.abs(x) >= 2.2250738585072014e-308) return 0;
    if (x != 0) return 1;
    return 2;
  }
  return isNaN(x)?4:3;
}
//Provides: caml_modf_float const
function caml_modf_float (x) {
  if (isFinite (x)) {
    var neg = (1/x) < 0;
    x = Math.abs(x);
    var i = Math.floor (x);
    var f = x - i;
    if (neg) { i = -i; f = -f; }
    return [0, f, i];
  }
  if (isNaN (x)) return [0, NaN, NaN];
  return [0, 1/x, x];
}
//Provides: caml_ldexp_float const
function caml_ldexp_float (x,exp) {
  exp |= 0;
  if (exp > 1023) {
    exp -= 1023;
    x *= Math.pow(2, 1023);
    if (exp > 1023) {  // in case x is subnormal
      exp -= 1023;
      x *= Math.pow(2, 1023);
    }
  }
  if (exp < -1023) {
    exp += 1023;
    x *= Math.pow(2, -1023);
  }
  x *= Math.pow(2, exp);
  return x;
}
//Provides: caml_frexp_float const
//Requires: jsoo_floor_log2
function caml_frexp_float (x) {
  if ((x == 0) || !isFinite(x)) return [0, x, 0];
  var neg = x < 0;
  if (neg) x = - x;
  var exp = jsoo_floor_log2(x) + 1;
  x *= Math.pow(2,-exp);
  if (x < 0.5) { x *= 2; exp -= 1; }
  if (neg) x = - x;
  return [0, x, exp];
}

//Provides: caml_float_compare const
function caml_float_compare (x, y) {
  if (x === y) return 0;
  if (x < y) return -1;
  if (x > y) return 1;
  if (x === x) return 1;
  if (y === y) return -1;
  return 0;
}

//Provides: caml_copysign_float const
function caml_copysign_float (x, y) {
  if (y == 0) y = 1 / y;
  x = Math.abs(x);
  return (y < 0)?(-x):x;
}

//Provides: caml_expm1_float const
function caml_expm1_float (x) {
  var y = Math.exp(x), z = y - 1;
  return (Math.abs(x)>1?z:(z==0?x:x*z/Math.log(y)));
}

//Provides: caml_log1p_float const
function caml_log1p_float (x) {
  var y = 1 + x, z = y - 1;
  return (z==0?x:x*Math.log(y)/z);
}

//Provides: caml_hypot_float const
function caml_hypot_float (x, y) {
  var x = Math.abs(x), y = Math.abs(y);
  var a = Math.max(x, y), b = Math.min(x,y) / (a?a:1);
  return (a * Math.sqrt(1 + b*b));
}

// FIX: these five functions only give approximate results.
//Provides: caml_log10_float const
function caml_log10_float (x) { return Math.LOG10E * Math.log(x); }
//Provides: caml_cosh_float const
function caml_cosh_float (x) { return (Math.exp(x) + Math.exp(-x)) / 2; }
//Provides: caml_sinh_float const
function caml_sinh_float (x) { return (Math.exp(x) - Math.exp(-x)) / 2; }
//Provides: caml_tanh_float const
function caml_tanh_float (x) {
  var y = Math.exp(x), z = Math.exp(-x);
  return (y + z) / (y - z);
}
<commit_msg>Runtime: caml_hexstring_of_float - part 4<commit_after>// Js_of_ocaml runtime support
// http://www.ocsigen.org/js_of_ocaml/
// Copyright (C) 2010 Jérôme Vouillon
// Laboratoire PPS - CNRS Université Paris Diderot
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, with linking exception;
// either version 2.1 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

//Provides: jsoo_floor_log2
var log2_ok = Math.log2 && Math.log2(1.1235582092889474E+307) == 1020
function jsoo_floor_log2(x) {
    if(log2_ok) return Math.floor(Math.log2(x))
    var i = 0;
    if (x == 0) return -Infinity;
    if(x>=1) {while (x>=2) {x/=2; i++} }
    else {while (x < 1) {x*=2; i--} };
    return i;
}

//Provides: caml_int64_bits_of_float const
//Requires: jsoo_floor_log2
function caml_int64_bits_of_float (x) {
  if (!isFinite(x)) {
    if (isNaN(x)) return [255, 1, 0, 0xfff0];
    return (x > 0)?[255,0,0,0x7ff0]:[255,0,0,0xfff0];
  }
  var sign = (x==0 && 1/x == -Infinity)?0x8000:(x>=0)?0:0x8000;
  if (sign) x = -x;
  // Int64.bits_of_float 1.1235582092889474E+307 = 0x7fb0000000000000L
  // using Math.LOG2E*Math.log(x) in place of Math.log2 result in precision lost
  var exp = jsoo_floor_log2(x) + 1023;
  if (exp <= 0) {
    exp = 0;
    x /= Math.pow(2,-1026);
  } else {
    x /= Math.pow(2,exp-1027);
    if (x < 16) {
      x *= 2; exp -=1; }
    if (exp == 0) {
      x /= 2; }
  }
  var k = Math.pow(2,24);
  var r3 = x|0;
  x = (x - r3) * k;
  var r2 = x|0;
  x = (x - r2) * k;
  var r1 = x|0;
  r3 = (r3 &0xf) | sign | exp << 4;
  return [255, r1, r2, r3];
}

//FP literals can be written using the hexadecimal
//notation 0x<mantissa in hex>p<exponent> from ISO C99.
//https://github.com/dankogai/js-hexfloat/blob/master/hexfloat.js
//Provides: caml_hexstring_of_float const
//Requires: caml_js_to_string, caml_str_repeat
function caml_hexstring_of_float (x, prec, style) {
  if (!isFinite(x)) {
    if (isNaN(x)) return caml_js_to_string("nan");
    return caml_js_to_string ((x > 0)?"infinity":"-infinity");
  }
  var sign = (x==0 && 1/x == -Infinity)?1:(x>=0)?0:1;
  if(sign) x = -x;
  var exp = 0;
  if (x == 0) { }
  else if (x < 1) {
    while (x < 1 && exp > -1022)  { x *= 2; exp-- }
  } else {
    while (x >= 2) { x /= 2; exp++ }
  }
  var exp_sign = exp < 0 ? '' : '+';
  var sign_str = '';
  if (sign) sign_str = '-'
  else {
    switch(style){
    case 43 /* '+' */: sign_str = '+'; break;
    case 32 /* ' ' */: sign_str = ' '; break;
    default: break;
    }
  }
  if (prec >= 0 && prec < 13) {
    /* If a precision is given, and is small, round mantissa accordingly */
      var cst = Math.pow(2,prec * 4);
      x = Math.round(x * cst) / cst;
  }
  var x_str = x.toString(16);
  if(prec >= 0){
      var idx = x_str.indexOf('.');
    if(idx<0) {
      x_str += '.' + caml_str_repeat(prec, '0');
    }
    else {
      var size = idx+1+prec;
      if(x_str.length < size)
        x_str += caml_str_repeat(size - x_str.length, '0');
      else
        x_str = x_str.substr(0,size);
    }
  }
  return caml_js_to_string (sign_str + '0x' + x_str + 'p' + exp_sign + exp.toString(10));
}

//Provides: caml_int64_float_of_bits const
function caml_int64_float_of_bits (x) {
  var exp = (x[3] & 0x7fff) >> 4;
  if (exp == 2047) {
      if ((x[1]|x[2]|(x[3]&0xf)) == 0)
        return (x[3] & 0x8000)?(-Infinity):Infinity;
      else
        return NaN;
  }
  var k = Math.pow(2,-24);
  var res = (x[1]*k+x[2])*k+(x[3]&0xf);
  if (exp > 0) {
    res += 16;
    res *= Math.pow(2,exp-1027);
  } else
    res *= Math.pow(2,-1026);
  if (x[3] & 0x8000) res = - res;
  return res;
}
//Provides: caml_classify_float const
function caml_classify_float (x) {
  if (isFinite (x)) {
    if (Math.abs(x) >= 2.2250738585072014e-308) return 0;
    if (x != 0) return 1;
    return 2;
  }
  return isNaN(x)?4:3;
}
//Provides: caml_modf_float const
function caml_modf_float (x) {
  if (isFinite (x)) {
    var neg = (1/x) < 0;
    x = Math.abs(x);
    var i = Math.floor (x);
    var f = x - i;
    if (neg) { i = -i; f = -f; }
    return [0, f, i];
  }
  if (isNaN (x)) return [0, NaN, NaN];
  return [0, 1/x, x];
}
//Provides: caml_ldexp_float const
function caml_ldexp_float (x,exp) {
  exp |= 0;
  if (exp > 1023) {
    exp -= 1023;
    x *= Math.pow(2, 1023);
    if (exp > 1023) {  // in case x is subnormal
      exp -= 1023;
      x *= Math.pow(2, 1023);
    }
  }
  if (exp < -1023) {
    exp += 1023;
    x *= Math.pow(2, -1023);
  }
  x *= Math.pow(2, exp);
  return x;
}
//Provides: caml_frexp_float const
//Requires: jsoo_floor_log2
function caml_frexp_float (x) {
  if ((x == 0) || !isFinite(x)) return [0, x, 0];
  var neg = x < 0;
  if (neg) x = - x;
  var exp = jsoo_floor_log2(x) + 1;
  x *= Math.pow(2,-exp);
  if (x < 0.5) { x *= 2; exp -= 1; }
  if (neg) x = - x;
  return [0, x, exp];
}

//Provides: caml_float_compare const
function caml_float_compare (x, y) {
  if (x === y) return 0;
  if (x < y) return -1;
  if (x > y) return 1;
  if (x === x) return 1;
  if (y === y) return -1;
  return 0;
}

//Provides: caml_copysign_float const
function caml_copysign_float (x, y) {
  if (y == 0) y = 1 / y;
  x = Math.abs(x);
  return (y < 0)?(-x):x;
}

//Provides: caml_expm1_float const
function caml_expm1_float (x) {
  var y = Math.exp(x), z = y - 1;
  return (Math.abs(x)>1?z:(z==0?x:x*z/Math.log(y)));
}

//Provides: caml_log1p_float const
function caml_log1p_float (x) {
  var y = 1 + x, z = y - 1;
  return (z==0?x:x*Math.log(y)/z);
}

//Provides: caml_hypot_float const
function caml_hypot_float (x, y) {
  var x = Math.abs(x), y = Math.abs(y);
  var a = Math.max(x, y), b = Math.min(x,y) / (a?a:1);
  return (a * Math.sqrt(1 + b*b));
}

// FIX: these five functions only give approximate results.
//Provides: caml_log10_float const
function caml_log10_float (x) { return Math.LOG10E * Math.log(x); }
//Provides: caml_cosh_float const
function caml_cosh_float (x) { return (Math.exp(x) + Math.exp(-x)) / 2; }
//Provides: caml_sinh_float const
function caml_sinh_float (x) { return (Math.exp(x) - Math.exp(-x)) / 2; }
//Provides: caml_tanh_float const
function caml_tanh_float (x) {
  var y = Math.exp(x), z = Math.exp(-x);
  return (y + z) / (y - z);
}
<|endoftext|>


<commit_before>// configuration

var USE_SWFOBJECT = true, //!!window.swfobject; // ... to embed youtube flash player
	PLAY_TIMEOUT = 10000;

window.$ = window.$ || function(){return window.$};
$.html = $.html || function(){return $};
$.remove = $.remove || function(){return $};

// utility functions

if (undefined == window.console)
	window.console = {log:function(){}};

loader = new (function Loader() {
	var FINAL_STATES = {"loaded": true, "complete": true, 4: true},
		head = document.getElementsByTagName("head")[0],
		pending = {};
	return {
		includeJS: function(src, cb){
			if (pending[src]) return;
			pending[src] = true;
			var inc = document.createElement("script");
			inc.onload = inc.onreadystatechange = function() {
				if (pending[src] && (!inc.readyState || FINAL_STATES[inc.readyState])) {
					cb && cb();
					delete pending[src];
				}
			};
			inc.src = src;
			head.appendChild(inc);
		}
	};
});

// EventEmitter

function EventEmitter() {
	this._eventListeners = {};
}

EventEmitter.prototype.on = function(eventName, handler){
	this._eventListeners[eventName] = (this._eventListeners[eventName] || []).concat(handler);
}

EventEmitter.prototype.emit = function(eventName){
	var i, args = Array.prototype.slice.call(arguments, 1), // remove eventName from arguments, and make it an array
		listeners = this._eventListeners[eventName];
	for (i in listeners)
		listeners[i].apply(null, args);
}

/**
 * Inherit the prototype methods from one constructor into another. (from Node.js)
 *
 * The Function.prototype.inherits from lang.js rewritten as a standalone
 * function (not on Function.prototype). NOTE: If this file is to be loaded
 * during bootstrapping this function needs to be rewritten using some native
 * functions as prototype setup using normal JavaScript does not work as
 * expected during bootstrapping (see mirror.js in r114903).
 *
 * @param {function} ctor Constructor function which needs to inherit the
 *     prototype.
 * @param {function} superCtor Constructor function to inherit prototype from.
 */
function inherits(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
};

/**
 * Plays a sequence of streamed audio/video tracks by embedding the corresponding players
 *
 * Events:
 * - "onError", {code,source}
 * - "onReady"
 * - "onPlay"
 * - "onPause"
 * - "onEnd"
 * - "onTrackInfo", track{}
 * - "onTrackChange", track{}
 * - "loadMore"
 */

function Playem(playemPrefs) {

	function Playem(playemPrefs) {

		EventEmitter.call(this);

		playemPrefs = playemPrefs || {};
		playemPrefs.loop = playemPrefs.hasOwnProperty("loop") ? playemPrefs.loop : true;

		var players = [], // instanciated Player classes, added by client
			i,
			exportedMethods,
			currentTrack = null,
			trackList = [],
			whenReady = null,
			playersToLoad = 0,
			progress = null,
			that = this,
			playTimeout = null,
			volume = 1;

		this.setPref = function(key, val){
			playemPrefs[key] = val;
		}

		function doWhenReady(player, fct) {
			var interval = null;
			function poll(){
				if (player.isReady && interval) {
					clearInterval(interval);
					fct();
				}
				else
					console.warn("PLAYEM waiting for", player.label, "...");
			}
			if (player.isReady)
				setTimeout(fct);
			else
				interval = setInterval(poll, 1000);
		}

		function addTrackById(id, player, metadata) {
			if (id) {
				var track = {
					index: trackList.length,
					trackId: id,
					//img: img,
					player: player,
					playerName: player.label.replace(/ /g, "_"),
					metadata: metadata || {}
				};
				trackList.push(track);
				return track;
				//console.log("added:", player.label, "track", id, track/*, metadata*/);
			}
			else
				throw new Error("no id provided");
		}

		function setVolume(vol) {
			volume = vol;
			if (currentTrack && currentTrack.player.setVolume)
				currentTrack.player.setVolume(vol);
		}

		function playTrack(track) {
			//console.log("playTrack", track);
			doWhenReady(track.player, function() {
				if (currentTrack) {
					currentTrack.player.stop && currentTrack.player.stop();
					// TODO: delete elements in players instead ?
					//$("#genericholder iframe").attr("src", ""); // to make sure that IE really destroys the iframe embed
					var iframe, holder = document.getElementById("genericholder");
					if (holder) {
						iframe = holder.getElementsByTagName("iframe")[0];
						if (iframe)
							iframe.setAttribute("src", "");
						//$("#genericholder").html("").remove();
						holder.innerHTML = "";
						holder.parentNode.removeChild(holder);
					}
					if (progress)
						clearInterval(progress);
				}
				currentTrack = track;
				delete currentTrack.trackPosition; // = null;
				delete currentTrack.trackDuration; // = null;
				that.emit("onTrackChange", track);
				//console.log("playTrack #" + track.index + " (" + track.playerName+ ")", track);
				track.player.play(track.trackId);
				setVolume(volume);
				if (currentTrack.index == trackList.length-1)
					that.emit("loadMore");
				// if the track does not start playing within 7 seconds, skip to next track
				setPlayTimeout(function() {
					console.warn("PLAYEM TIMEOUT"); // => skipping to next song
					that.emit("onError", {code:"timeout", source:"Playem"});
					//exportedMethods.next();
				});
			});
		}

		function setPlayTimeout(handler) {
			if (playTimeout)
				clearTimeout(playTimeout);
			playTimeout = !handler ? null : setTimeout(handler, PLAY_TIMEOUT);
		}

		// functions that are called by players => to propagate to client
		function createEventHandlers (playemFunctions) {
			var eventHandlers = {
				onApiReady: function(player){
					//console.log(player.label + " api ready");
					if (whenReady && player == whenReady.player)
						whenReady.fct();
					if (0 == --playersToLoad)
						that.emit("onReady");
				},
				onEmbedReady: function(player) {
					//console.log("embed ready");
					setVolume(volume);
				},
				onBuffering: function(player) {
					setTimeout(function() {
						setPlayTimeout();
						that.emit("onBuffering");
					});
				},
				onPlaying: function(player) {
					//console.log(player.label + ".onPlaying");
					//setPlayTimeout(); // removed because soundcloud sends a "onPlaying" event, even for not authorized tracks
					setVolume(volume);
					setTimeout(function() {
						that.emit("onPlay");
					}, 1);
					if (player.trackInfo && player.trackInfo.duration)
						eventHandlers.onTrackInfo({
							position: player.trackInfo.position || 0,
							duration: player.trackInfo.duration
						});

					if (progress)
						clearInterval(progress);

					if (player.getTrackPosition) {
						//var that = eventHandlers; //this;
						progress = setInterval(function(){
							player.getTrackPosition(function(trackPos) {
								eventHandlers.onTrackInfo({
									position: trackPos,
									duration: player.trackInfo.duration || currentTrack.trackDuration
								});
							});
						}, 1000);
					}
				},
				onTrackInfo: function(trackInfo) {
					//console.log("ontrackinfo", trackInfo, currentTrack);
					if (currentTrack && trackInfo) {
						if (trackInfo.duration) {
							currentTrack.trackDuration = trackInfo.duration;
							setPlayTimeout();
						}
						if (trackInfo.position)
							currentTrack.trackPosition = trackInfo.position;
					}
					that.emit("onTrackInfo", currentTrack);
				},
				onPaused: function(player) {
					//console.log(player.label + ".onPaused");
					setPlayTimeout();
					if (progress)
						clearInterval(progress);
					progress = null;
					//if (!avoidPauseEventPropagation)
					//	that.emit("onPause");
					//avoidPauseEventPropagation = false;
				},
				onEnded: function(player) {
					//console.log(player.label + ".onEnded");
					currentTrack.player.stop && currentTrack.player.stop();
					that.emit("onEnd");
					playemFunctions.next();
				},
				onError: function(player, error) {
					console.error(player.label + " error:", ((error || {}).exception || error || {}).stack || error);
					setPlayTimeout();
					that.emit("onError", error);
				}
			};
			// handlers will only be triggered is their associated player is currently active
			["onEmbedReady", "onBuffering", "onPlaying", "onPaused", "onEnded", "onError"].map(function (evt){
				var fct = eventHandlers[evt];
				eventHandlers[evt] = function(player, x){
					if (player == currentTrack.player)
						return fct(player, x);
					else
						console.warn("ignore event:", evt, "from", player, "instead of:", currentTrack.player);
				};
			});
			return eventHandlers;
		}

		// exported methods, mostly wrappers to Players' methods
		exportedMethods = {
			addPlayer: function (playerClass, vars) {
				playersToLoad++;
				players.push(new playerClass(createEventHandlers(this), vars));
			},
			getQueue: function() {
				return trackList;
			},
			clearQueue: function() {
				trackList = [];
			},
			addTrackByUrl: function(url, metadata, cb) {
				var p, remaining = players.length;
				for (p=0; p<players.length; ++p)
					players[p].getEid(url, function(eid, player){
						//console.log("test ", player.label, eid);
						if (eid) {
							var track = addTrackById(eid, player, metadata);
							//console.log("added track", track);
							cb && cb(track);
						}
						else if (--remaining == 0) {
							metadata && $(metadata.post).addClass("disabled");
							throw new Error("unrecognized track: " + url);
						}
					});
			},
			play: function(i) {
				playTrack(i != undefined ? trackList[i] : currentTrack || trackList[0]);
			},
			pause: function() {
				currentTrack.player.pause();
				that.emit("onPause");
			},
			stop: function() {
				currentTrack.player.stop && currentTrack.player.stop();
				//that.emit("onStop");
			},
			resume: function() {
				currentTrack.player.resume();
			},
			next: function() {
				if (playemPrefs.loop || currentTrack.index + 1 < trackList.length)
					playTrack(trackList[(currentTrack.index + 1) % trackList.length]);
			},
			prev: function() {
				playTrack(trackList[(trackList.length + currentTrack.index - 1) % trackList.length]);
			},
			seekTo: function(pos) {
				if (currentTrack && currentTrack.trackDuration)
					currentTrack.player.setTrackPosition(pos * currentTrack.trackDuration);
			},
			setVolume: setVolume
		};
		//return exportedMethods;
		for (i in exportedMethods)
			this[i] = exportedMethods[i];
	}

	inherits(Playem, EventEmitter);

	return new Playem();
};

<commit_msg>safer and simpler calls to player functions<commit_after>// configuration

var USE_SWFOBJECT = true, //!!window.swfobject; // ... to embed youtube flash player
	PLAY_TIMEOUT = 10000;

window.$ = window.$ || function(){return window.$};
$.html = $.html || function(){return $};
$.remove = $.remove || function(){return $};

// utility functions

if (undefined == window.console)
	window.console = {log:function(){}};

loader = new (function Loader() {
	var FINAL_STATES = {"loaded": true, "complete": true, 4: true},
		head = document.getElementsByTagName("head")[0],
		pending = {};
	return {
		includeJS: function(src, cb){
			if (pending[src]) return;
			pending[src] = true;
			var inc = document.createElement("script");
			inc.onload = inc.onreadystatechange = function() {
				if (pending[src] && (!inc.readyState || FINAL_STATES[inc.readyState])) {
					cb && cb();
					delete pending[src];
				}
			};
			inc.src = src;
			head.appendChild(inc);
		}
	};
});

// EventEmitter

function EventEmitter() {
	this._eventListeners = {};
}

EventEmitter.prototype.on = function(eventName, handler){
	this._eventListeners[eventName] = (this._eventListeners[eventName] || []).concat(handler);
}

EventEmitter.prototype.emit = function(eventName){
	var i, args = Array.prototype.slice.call(arguments, 1), // remove eventName from arguments, and make it an array
		listeners = this._eventListeners[eventName];
	for (i in listeners)
		listeners[i].apply(null, args);
}

/**
 * Inherit the prototype methods from one constructor into another. (from Node.js)
 *
 * The Function.prototype.inherits from lang.js rewritten as a standalone
 * function (not on Function.prototype). NOTE: If this file is to be loaded
 * during bootstrapping this function needs to be rewritten using some native
 * functions as prototype setup using normal JavaScript does not work as
 * expected during bootstrapping (see mirror.js in r114903).
 *
 * @param {function} ctor Constructor function which needs to inherit the
 *     prototype.
 * @param {function} superCtor Constructor function to inherit prototype from.
 */
function inherits(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
};

/**
 * Plays a sequence of streamed audio/video tracks by embedding the corresponding players
 *
 * Events:
 * - "onError", {code,source}
 * - "onReady"
 * - "onPlay"
 * - "onPause"
 * - "onEnd"
 * - "onTrackInfo", track{}
 * - "onTrackChange", track{}
 * - "loadMore"
 */

function Playem(playemPrefs) {

	function Playem(playemPrefs) {

		EventEmitter.call(this);

		playemPrefs = playemPrefs || {};
		playemPrefs.loop = playemPrefs.hasOwnProperty("loop") ? playemPrefs.loop : true;

		var players = [], // instanciated Player classes, added by client
			i,
			exportedMethods,
			currentTrack = null,
			trackList = [],
			whenReady = null,
			playersToLoad = 0,
			progress = null,
			that = this,
			playTimeout = null,
			volume = 1;

		this.setPref = function(key, val){
			playemPrefs[key] = val;
		}

		function doWhenReady(player, fct) {
			var interval = null;
			function poll(){
				if (player.isReady && interval) {
					clearInterval(interval);
					fct();
				}
				else
					console.warn("PLAYEM waiting for", player.label, "...");
			}
			if (player.isReady)
				setTimeout(fct);
			else
				interval = setInterval(poll, 1000);
		}

		function addTrackById(id, player, metadata) {
			if (id) {
				var track = {
					index: trackList.length,
					trackId: id,
					//img: img,
					player: player,
					playerName: player.label.replace(/ /g, "_"),
					metadata: metadata || {}
				};
				trackList.push(track);
				return track;
				//console.log("added:", player.label, "track", id, track/*, metadata*/);
			}
			else
				throw new Error("no id provided");
		}

		function setVolume(vol) {
			volume = vol;
			callPlayerFct("setVolume", vol);
		}

		function playTrack(track) {
			//console.log("playTrack", track);
			doWhenReady(track.player, function() {
				if (currentTrack) {
					callPlayerFct("stop");
					// TODO: delete elements in players instead ?
					//$("#genericholder iframe").attr("src", ""); // to make sure that IE really destroys the iframe embed
					var iframe, holder = document.getElementById("genericholder");
					if (holder) {
						iframe = holder.getElementsByTagName("iframe")[0];
						if (iframe)
							iframe.setAttribute("src", "");
						//$("#genericholder").html("").remove();
						holder.innerHTML = "";
						holder.parentNode.removeChild(holder);
					}
					if (progress)
						clearInterval(progress);
				}
				currentTrack = track;
				delete currentTrack.trackPosition; // = null;
				delete currentTrack.trackDuration; // = null;
				that.emit("onTrackChange", track);
				//console.log("playTrack #" + track.index + " (" + track.playerName+ ")", track);
				callPlayerFct("play", track.trackId);
				setVolume(volume);
				if (currentTrack.index == trackList.length-1)
					that.emit("loadMore");
				// if the track does not start playing within 7 seconds, skip to next track
				setPlayTimeout(function() {
					console.warn("PLAYEM TIMEOUT"); // => skipping to next song
					that.emit("onError", {code:"timeout", source:"Playem"});
					//exportedMethods.next();
				});
			});
		}

		function setPlayTimeout(handler) {
			if (playTimeout)
				clearTimeout(playTimeout);
			playTimeout = !handler ? null : setTimeout(handler, PLAY_TIMEOUT);
		}

		function callPlayerFct(fctName, param){
			try {
				return currentTrack.player[fctName](param);
			}
			catch(e) {
				console.warn(e.stack);
			}
		}

		// functions that are called by players => to propagate to client
		function createEventHandlers (playemFunctions) {
			var eventHandlers = {
				onApiReady: function(player){
					//console.log(player.label + " api ready");
					if (whenReady && player == whenReady.player)
						whenReady.fct();
					if (0 == --playersToLoad)
						that.emit("onReady");
				},
				onEmbedReady: function(player) {
					//console.log("embed ready");
					setVolume(volume);
				},
				onBuffering: function(player) {
					setTimeout(function() {
						setPlayTimeout();
						that.emit("onBuffering");
					});
				},
				onPlaying: function(player) {
					//console.log(player.label + ".onPlaying");
					//setPlayTimeout(); // removed because soundcloud sends a "onPlaying" event, even for not authorized tracks
					setVolume(volume);
					setTimeout(function() {
						that.emit("onPlay");
					}, 1);
					if (player.trackInfo && player.trackInfo.duration)
						eventHandlers.onTrackInfo({
							position: player.trackInfo.position || 0,
							duration: player.trackInfo.duration
						});

					if (progress)
						clearInterval(progress);

					if (player.getTrackPosition) {
						//var that = eventHandlers; //this;
						progress = setInterval(function(){
							player.getTrackPosition(function(trackPos) {
								eventHandlers.onTrackInfo({
									position: trackPos,
									duration: player.trackInfo.duration || currentTrack.trackDuration
								});
							});
						}, 1000);
					}
				},
				onTrackInfo: function(trackInfo) {
					//console.log("ontrackinfo", trackInfo, currentTrack);
					if (currentTrack && trackInfo) {
						if (trackInfo.duration) {
							currentTrack.trackDuration = trackInfo.duration;
							setPlayTimeout();
						}
						if (trackInfo.position)
							currentTrack.trackPosition = trackInfo.position;
					}
					that.emit("onTrackInfo", currentTrack);
				},
				onPaused: function(player) {
					//console.log(player.label + ".onPaused");
					setPlayTimeout();
					if (progress)
						clearInterval(progress);
					progress = null;
					//if (!avoidPauseEventPropagation)
					//	that.emit("onPause");
					//avoidPauseEventPropagation = false;
				},
				onEnded: function(player) {
					//console.log(player.label + ".onEnded");
					callPlayerFct("stop");
					that.emit("onEnd");
					playemFunctions.next();
				},
				onError: function(player, error) {
					console.error(player.label + " error:", ((error || {}).exception || error || {}).stack || error);
					setPlayTimeout();
					that.emit("onError", error);
				}
			};
			// handlers will only be triggered is their associated player is currently active
			["onEmbedReady", "onBuffering", "onPlaying", "onPaused", "onEnded", "onError"].map(function (evt){
				var fct = eventHandlers[evt];
				eventHandlers[evt] = function(player, x){
					if (player == currentTrack.player)
						return fct(player, x);
					else
						console.warn("ignore event:", evt, "from", player, "instead of:", currentTrack.player);
				};
			});
			return eventHandlers;
		}

		// exported methods, mostly wrappers to Players' methods
		exportedMethods = {
			addPlayer: function (playerClass, vars) {
				playersToLoad++;
				players.push(new playerClass(createEventHandlers(this), vars));
			},
			getQueue: function() {
				return trackList;
			},
			clearQueue: function() {
				trackList = [];
			},
			addTrackByUrl: function(url, metadata, cb) {
				var p, remaining = players.length;
				for (p=0; p<players.length; ++p)
					players[p].getEid(url, function(eid, player){
						//console.log("test ", player.label, eid);
						if (eid) {
							var track = addTrackById(eid, player, metadata);
							//console.log("added track", track);
							cb && cb(track);
						}
						else if (--remaining == 0) {
							metadata && $(metadata.post).addClass("disabled");
							throw new Error("unrecognized track: " + url);
						}
					});
			},
			play: function(i) {
				playTrack(i != undefined ? trackList[i] : currentTrack || trackList[0]);
			},
			pause: function() {
				callPlayerFct("pause");
				that.emit("onPause");
			},
			stop: function() {
				callPlayerFct("stop");
				//that.emit("onStop");
			},
			resume: function() {
				callPlayerFct("resume");
			},
			next: function() {
				if (playemPrefs.loop || currentTrack.index + 1 < trackList.length)
					playTrack(trackList[(currentTrack.index + 1) % trackList.length]);
			},
			prev: function() {
				playTrack(trackList[(trackList.length + currentTrack.index - 1) % trackList.length]);
			},
			seekTo: function(pos) {
				if ((currentTrack || {}).trackDuration)
					callPlayerFct("setTrackPosition", pos * currentTrack.trackDuration);
			},
			setVolume: setVolume
		};
		//return exportedMethods;
		for (i in exportedMethods)
			this[i] = exportedMethods[i];
	}

	inherits(Playem, EventEmitter);

	return new Playem();
};

<|endoftext|>


<commit_before>var Player_actions = require("./player_actions");
var ranking = require("./ranking.js");
var conf = require("./player_config");

module.exports = {

  VERSION: "Default JavaScript folding player",

  bet_request: function(game_state, bet) {
    var action = new Player_actions(game_state);
    var handRank = ranking.getHandValue(game_state.players[game_state.in_action]["hole_cards"]);
    var minimumToCall = conf.getConf('min_call');
    var minimumToRaise = conf.getConf('min_raise');

    if (handRank < minimumToCall) {
      bet(action.doFold());
    } else if (handRank >= minimumToCall && handRank < minimumToRaise) {
      bet(action.doCall());
    } else {
      bet(action.doAllIn());
    }
  },

  showdown: function(game_state) {

  }
};
<commit_msg>extend cards array<commit_after>var Player_actions = require("./player_actions");
var ranking = require("./ranking.js");
var conf = require("./player_config");

module.exports = {

  VERSION: "Default JavaScript folding player",

  bet_request: function(game_state, bet) {
    var action = new Player_actions(game_state);
    var handRank = ranking.getHandValue(game_state.players[game_state.in_action]["hole_cards"].concat(game_state.community_cards));
    var minimumToCall = conf.getConf('min_call');
    var minimumToRaise = conf.getConf('min_raise');

    if (handRank < minimumToCall) {
      bet(action.doFold());
    } else if (handRank >= minimumToCall && handRank < minimumToRaise) {
      bet(action.doCall());
    } else {
      bet(action.doAllIn());
    }
  },

  showdown: function(game_state) {

  }
};
<|endoftext|>