<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

/**
 * Provide the database endpoints handling.
 *
 * @module models
 * @submodule models.endpoints
 */

YUI.add('juju-endpoints', function(Y) {

  const models = Y.namespace('juju.models');
  const relationUtils = window.juju.utils.RelationUtils;

  /**
    Get the series for a service. Pending subordinates should return all the
    available series from the charm.

    @method _getSeries
    @param {Object} db A reference to the application database.
    @param {Object} app An application object.
    @return {Array} A list of available series.
  */
  models._getSeries = function(db, app) {
    let series = app.get('series');
    // Pending subordinates should be checked against all their available
    // series.
    if (app.get('subordinate') && app.get('pending')) {
      series = db.charms.getById(app.get('charm')).get('series');
    }
    if (!Array.isArray(series)) {
      series = [series];
    }
    return series;
  },

  /**
   * Find available relation targets for a service.
   *
   * @method getEndpoints
   * @param {Object} application A service object.
   * @param {Object} controller The endpoints controller.
   *
   * @return {Object} A mapping with keys of valid relation service targets
   *   and values consisting of a list of valid endpoints for each.
   */
  models.getEndpoints = function(application, controller) {
    const targets = {},
        requires = [],
        provides = [],
        appId = application.get('id'),
        db = controller.get('db'),
        endpointsMap = controller.endpointsMap;
    const appIsSubordinate = application.get('subordinate');
    // Bail out if the map doesn't yet exist for this service.  The charm may
    // not be loaded yet.
    if (!endpointsMap[appId]) {
      return targets;
    }
    /**
     * Convert a service name and its relation endpoint info into a
     * valid relation target endpoint, ie. including service name.
     *
     * @method getEndpoints.convert
     */
    function convert(applicationName, relInfo) {
      return {
        service: applicationName,
        name: relInfo.name,
        type: relInfo['interface']
      };
    }

    /**
     * Store endpoints for a relation to target the given service.
     *
     * @method getEndpoints.add
     * @param {Object} targetEndpoint Target endpoint.
     * @param {Object} originEndpoint Origin endpoint.
     */
    function add(applicationName, originEndpoint, targetEndpoint) {
      if (!targets.hasOwnProperty(applicationName)) {
        targets[applicationName] = [];
      }
      targets[applicationName].push([originEndpoint, targetEndpoint]);
    }

    // First we process all the endpoints of the origin service.
    //
    // For required interfaces, we consider them valid for new relations
    // only if they are not already satisfied by an existing relation.
    endpointsMap[appId].requires.forEach(rdata => {
      const endpoint = convert(appId, rdata);
      // Subordinate relations are slightly different:
      // a subordinate typically acts as a client to many services,
      // against the implicitly provided juju-info interface.
      if (application.get('subordinate') &&
        relationUtils.isSubordinateRelation(rdata)) {
        return requires.push(endpoint);
      }
      if (db.relations.has_relation_for_endpoint(endpoint)) {
        return;
      }
      requires.push(endpoint);
    });

    // Process origin provides endpoints, a bit simpler, as they are
    // always one to many.
    endpointsMap[appId].provides.forEach(pdata => {
      provides.push(convert(appId, pdata));
    });

    // Every non subordinate service implicitly provides this.
    if (!appIsSubordinate) {
      provides.push(convert(
          appId, {'interface': 'juju-info', 'name': 'juju-info'}));
    }

    // Now check every other service to see if it can be a valid target.
    db.services.each(target => {
      const targetId = target.get('id'),
          targetProvides = endpointsMap[targetId].provides.concat();
      const targetIsSubordinate = target.get('subordinate');
      // Ignore ourselves, peer relations are automatically
      // established when a service is deployed. The GUI only needs to
      // concern itself with client/server relations.
      if (targetId === appId) {
        return;
      }
      // Process each of the service's required endpoints. It is only
      // considered a valid target if it is not satisfied by an existing
      // relation.
      endpointsMap[targetId].requires.forEach(rdata => {
        const endpoint = convert(targetId, rdata);
        // Subordinates are excendpointtions again as they are a client
        // to many services. We check if a subordinate relation
        // exists between this subordinate endpoint and the origin
        // service.
        if (targetIsSubordinate &&
          relationUtils.isSubordinateRelation(rdata)) {
          if (db.relations.has_relation_for_endpoint(endpoint, appId)) {
            return;
          }
        } else if (db.relations.has_relation_for_endpoint(endpoint)) {
          return;
        }
        // If the origin provides it then it is a valid target.
        provides.filter(originEndpoint => {
          if (originEndpoint.type === endpoint.type) {
            add(targetId, originEndpoint, endpoint);
          }
        });
      });

      // Check against the implicit interface juju-info, but not for
      // subordinates.
      if (!target.get('subordinate')) {
        targetProvides.push({'interface': 'juju-info', 'name': 'juju-info'});
      }
      targetProvides.forEach(pdata => {
        const endpoint = convert(targetId, pdata);
        requires.forEach(originEndpoint => {
          if (originEndpoint.type !== endpoint.type ||
              db.relations.has_relation_for_endpoint(endpoint, appId)) {
            return;
          }
          add(targetId, originEndpoint, endpoint);
        });
      });
    });
    return targets;
  };

}, '', {
  requires: [
    'relation-utils'
  ]
});
<commit_msg>Extensively modify the getEndpoints method to correctly return valid relation endpoints for Juju 2.<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

/**
 * Provide the database endpoints handling.
 *
 * @module models
 * @submodule models.endpoints
 */

YUI.add('juju-endpoints', function(Y) {

  const models = Y.namespace('juju.models');
  const relationUtils = window.juju.utils.RelationUtils;

  /**
    Get the series for a service. Pending subordinates should return all the
    available series from the charm.

    @method _getSeries
    @param {Object} db A reference to the application database.
    @param {Object} app An application object.
    @return {Array} A list of available series.
  */
  models._getSeries = function(db, app) {
    let series = app.get('series');
    // Pending subordinates should be checked against all their available
    // series.
    if (app.get('subordinate') && app.get('pending')) {
      series = db.charms.getById(app.get('charm')).get('series');
    }
    if (!Array.isArray(series)) {
      series = [series];
    }
    return series;
  },

  /**
    Find available relation targets for an application.
    @param {Object} application An application object.
    @param {Object} controller The endpoints controller.
    @return {Object} A mapping with keys of valid relation application targets
      and values consisting of a list of valid endpoints for each.
  */
  models.getEndpoints = function(application, controller) {
    const targets = {};
    const appId = application.get('id');
    const db = controller.get('db');
    const endpointsMap = controller.endpointsMap;
    const appEndpoints = endpointsMap[appId];
    const appIsSubordinate = application.get('subordinate');
    const appSeries = models._getSeries(db, application);
    // Bail out if the map doesn't yet exist for this application. The charm may
    // not be loaded yet.
    if (!appEndpoints) {
      return {};
    }
    /**
      Convert an application name and its relation endpoint info into a
      valid relation target endpoint, ie. including application name.
    */
    function convert(applicationName, relInfo) {
      return {
        service: applicationName,
        name: relInfo.name,
        type: relInfo['interface']
      };
    }
    /**
      Store endpoints for a relation to target the given application.
      @param {Object} targetEndpoint Target endpoint.
      @param {Object} originEndpoint Origin endpoint.
    */
    function add(applicationName, originEndpoint, targetEndpoint) {
      if (!targets.hasOwnProperty(applicationName)) {
        targets[applicationName] = [];
      }
      targets[applicationName].push([originEndpoint, targetEndpoint]);
    }
    // First we process all the endpoints of the origin application to use a
    // legacy format because this is what other legacy utils require.
    const requires = appEndpoints.requires.map(rdata => convert(appId, rdata));
    const provides = appEndpoints.provides.map(pdata => convert(appId, pdata));
    // Every non subordinate service implicitly provides this.
    if (!appIsSubordinate) {
      provides.push(convert(
          appId, {'interface': 'juju-info', 'name': 'juju-info'}));
    }
    // Now check every other application to see if it can be a valid target.
    db.services.each(target => {
      const targetId = target.get('id');
      const targetProvides = endpointsMap[targetId].provides.concat();
      const targetIsSubordinate = target.get('subordinate');
      // Ignore ourselves, peer relations are automatically established when an
      // application is deployed. The GUI only needs to concern itself with
      // client/server relations.
      if (targetId === appId) { return; }
      // Process each of the application's required endpoints.
      endpointsMap[targetId].requires.forEach(rdata => {
        const endpoint = convert(targetId, rdata);
        // Subordinate relations are handled differently because they can be
        // installed on the target machine depending on the defined scope.
        if (targetIsSubordinate && relationUtils.isSubordinateRelation(rdata)) {
          // In addition to checking if the relation is of type `subordinate`
          // The `isSubordinateRelation` function also checks that the
          // subordinate relation is of scope 'container' which means that
          // the series must match between the target and source.
          const targetSeries = models._getSeries(db, target);
          if (!appSeries.some(series => targetSeries.indexOf(series) > -1)) {
            return;
          }
        }
        // A relation between two applications can only be completed once on
        // the same interface.
        if (db.relations.has_relation_for_endpoint(endpoint, appId)) {
          return;
        }
        // If the origin provides it then it is a valid target.
        provides.filter(originEndpoint => {
          if (originEndpoint.type === endpoint.type) {
            add(targetId, originEndpoint, endpoint);
          }
        });
      });

      // Check against the implicit interface juju-info, but not for
      // subordinates.
      if (!target.get('subordinate')) {
        targetProvides.push({'interface': 'juju-info', 'name': 'juju-info'});
      }
      targetProvides.forEach(pdata => {
        const endpoint = convert(targetId, pdata);
        requires.forEach(originEndpoint => {
          if (originEndpoint.type !== endpoint.type ||
              db.relations.has_relation_for_endpoint(endpoint, appId)) {
            return;
          }
          add(targetId, originEndpoint, endpoint);
        });
      });
    });
    return targets;
  };

}, '', {
  requires: [
    'relation-utils'
  ]
});
<|endoftext|>


<commit_before>
function cardValue(card) {
  return 2 + ('234567891JQKA'.indexOf(card.rank.charAt(0)));
}

module.exports = {

  VERSION: "Goku JS - it's over 9004",

  bet_request: function(game_state) {
    var player = game_state.players[game_state.in_action];
    var cards = player.hole_cards

    var all_in = player.stack;

    if ('AK'.indexOf(cards[0].rank) != -1 && 'AK'.indexOf(cards[1].rank) != -1) {
      return all_in;
    }

    if (cards[0].rank == cards[1].rank) {
      return all_in;
    }

    if (cards[0].suit == cards[1].suit &&
        Math.abs(cardValue(cards[0]) - cardValue(cards[1])) == 1)
    {
      return all_in;
    }

    if ((player.in_action + 2) % 4 == player.dealer &&
        (game_state.pot < 8 * game_state.small_blind || game_state.pot < 300))
    {
      return all_in;
    }

    if (Math.random() < 0.1) {
      return all_in;
    }

    return 0;
  },

  showdown: function(game_state) {

  }
};
<commit_msg>Pretty good logic<commit_after>
function cardValue(card) {
  return 2 + ('234567891JQKA'.indexOf(card.rank.charAt(0)));
}

function cardIndex(card) {
  return ('AKQJ198765432'.indexOf(card.rank.charAt(0)));
}

module.exports = {

  VERSION: "Goku JS - it's over 9004",

  bet_request: function(game_state) {
    var player = game_state.players[game_state.in_action];
    var cards = player.hole_cards
    var new_strategy = false;

    var all_in = player.stack;

    if (new_strategy) {
      var suited = cards[0].suit == cards[1].suit;
      var same_rank = cards[0].rank == cards[1].rank;
      var min_rank = Math.min(cardIndex(cards[0].rank), cardIndex(cards[1].rank));
      var max_rank = Math.min(cardIndex(cards[0].rank), cardIndex(cards[1].rank));
      var data = [
          [20, 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  ],
          [20, 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 19.9, 19.3],
          [20, 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 16.3, 13.5, 12.7],
          [20, 20  , 20  , 20  , 20  , 20  , 20  , 20  , 18.6, 14.7, 13.5, 10.6, 8.5 ],
          [20, 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 11.9, 10.5, 7.7 , 6.5 ],
          [20, 20  , 20  , 20  , 20  , 20  , 20  , 20  , 20  , 14.4, 6.9 , 4.9 , 3.7 ],
          [20, 18.0, 13.0, 13.3, 17.5, 20  , 20  , 20  , 20  , 18.8, 10.1, 2.7 , 2.5 ],
          [20, 16.1, 10.3, 8.5 , 9.0 , 10.8, 14.7, 20  , 20  , 20  , 13.9, 2.5 , 2.1 ],
          [20, 15.1, 9.6 , 6.5 , 5.7 , 5.2 , 7.0 , 10.7, 20  , 20  , 16.3, 2.3 , 2.0 ],
          [20, 14.2, 8.9 , 6.0 , 4.1 , 3.5 , 3.0 , 2.6 , 2.4 , 20  , 20  , 2.4 , 2.0,],
          [20, 13.1, 7.9 , 5.4 , 3.8 , 2.7 , 2.3 , 2.1 , 2.0 , 2.1 , 20  , 2.2 , 1.8 ],
          [20, 12.2, 7.5 , 5.0 , 3.4 , 2.5 , 1.9 , 1.8 , 1.7 , 1.8 , 1.6 , 20  , 1.7 ]
          [20, 11.6, 7.0 , 4.6 , 2.9 , 2.2 , 1.8 , 1.6 , 1.5 , 1.5 , 1.4 , 1.4 ,20   ]
      ];

      var mult = 0;

      if (suited) {
        mult = data[max_rank][min_rank];
      } else {
        mult = data[min_rank][max_rank];
      }

      return Math.floor(mult * 2 * game_state.small_blind);

    } else {
      if ('AK'.indexOf(cards[0].rank) != -1 && 'AK'.indexOf(cards[1].rank) != -1) {
        return all_in;
      }

      if (cards[0].rank == cards[1].rank) {
        return all_in;
      }

      if (cards[0].suit == cards[1].suit &&
          Math.abs(cardValue(cards[0]) - cardValue(cards[1])) == 1)
      {
        return all_in;
      }

      if ((player.in_action + 2) % 4 == player.dealer &&
          (game_state.pot < 8 * game_state.small_blind || game_state.pot < 300))
      {
        return all_in;
      }

      if (Math.random() < 0.1) {
        return all_in;
      }
    }

    return 0;
  },

  showdown: function(game_state) {

  }
};
<|endoftext|>


<commit_before>/*
 * 文本滚动组件/marquee
 * http://xhyo.com/
 * version: 1.1
 * Copyright (c) 2015 Bill Chen(chenguibiao@yy.com/48838096@qq.com)
 * Released under the MIT license - http://opensource.org/licenses/MIT
 */
(function(window){
    var animationFrame = null;
    var supportHtml5 = false;
    var marqueeList = {};
    //定义动画执行函数
    if(window.requestAnimationFrame){
        supportHtml5 = true; //只支持标准模式
        animationFrame = window.requestAnimationFrame;
    } else {
        var prefix = ['webkit','moz','ms','o'];
        for(var i = 0; i < prefix.length;i++) {
            if(window[prefix[i]+'RequestAnimationFrame']) {
                animationFrame = window[prefix[i]+'RequestAnimationFrame'];
                break;
            }
        }
        if(!animationFrame) {
            animationFrame = function(callback) {window.setTimeout(callback,1000/60)}
        }
    }
    //移动对象
    function Moves(option) {
        if(!option)
            return;

        this.nextSibling = null; //下一个移动对象
        this.element = option.element; //当前dom元素
        this.width = option.width;
        this.height = option.height;
        this.left = option.left; //初始水平位置
        this.top = option.top; //初始垂直位置
        this.distance = option.distance; //移动距离
        this.duration = option.duration; //移动时间
        this.direction = option.direction; //移动方向
        this.useHtml5 = option.useHtml5; //使用html5

        this.element.style.width = option.width +'px';
        this.element.style.height = option.height +'px';
        this.reset();
    }
    //重置元素
    Moves.prototype.reset = function() {
        //恢复初始位置
        this.element.style.left = this.left +'px';
        this.element.style.top = this.top +'px';
        if(this.useHtml5) {
            this.element.style.transition = '';
            switch(this.direction) {
                case 1: {}
                case 3: {
                    this.element.style.transform = 'translateY(0)';
                }
                    break;
                case 2: {}
                default:{
                    this.element.style.transform = 'translateX(0)';
                }
            }
        } else {
            this.x = this.left; //水平坐标
            this.y = this.top; //垂直坐标
        }

        //重置时间
        this.startTime = 0; //开始时间
        this.reachTime = 0; //到达边缘时间
        this.usedTime = 0; //移动时间
    }
    //销毁元素
    Moves.prototype.destroy = function(){
        this.element.parentNode.removeChild(this.element);
        this.element = null;
        this.nextSibling = null;
    }
    //移动容器对象
    function Marquee(element, option) {
        var nodes, i,length;
        this.list = []; //移动对象列表
        this.container = element; //移动容器
        this.width = element.clientWidth; //容器宽度
        this.height = element.clientHeight; //容器高度
        this.prevMoves = null; //上一个移动对象
        this.fistMoves = null; //第一个移动对象
        this.lastTime = 0; //队列上一次执行时间
        this.loopCounter = 0; //执行次数
        //参数配置
        this.useHtml5 = !!(supportHtml5 && option.useHtml5); //使用html5
        this.loop = typeof option.loop != 'undefined' ? Math.abs(parseInt(option.loop,10)) : 1; //循环次数,0:无限循环;>0:按次数循环
        this.duration = typeof option.duration != 'undefined' ? Math.abs(parseInt(option.duration,10)) : element.clientWidth*10; //移动持续时间
        this.direction = parseInt(option.direction,10) || 0; //0:从右往左；1:从下往上；2:从左往右；3:从上往下
        this.startEvent = option.startEvent || null; //移动元素开始事件
        this.endEvent = option.endEvent || null; //移动结束事件
        this.reachEvent = option.reachEvent || null; //移动元素到达边缘事件,return true的时候到达边缘后暂停
        this.hoverEvent = option.hoverEvent || null; //移动元素鼠标悬停事件

        this.container.style.overflow = 'hidden';
        nodes = this.container.childNodes;
        for(i = 0,length = nodes.length; length && i<length; i++)
            this.push(nodes[i]);
    }
    //添加移动对象
    Marquee.prototype.push = function(element) {
        if(typeof element != 'object' || element.nodeType != 1)
            return null;

        var scroller,time,option={direction : this.direction,useHtml5:this.useHtml5};

        //添加元素
        element.style.position = 'absolute';
        if(element.parentNode !== this.container) {
            this.container.appendChild(element);
        }
        option.element = element;
        //记录初始信息
        option.width = element.offsetWidth;
        option.height = element.offsetHeight;
        option.left = element.offsetLeft;
        option.top = element.offsetTop;
        //确定初始位置
        switch(this.direction) {
            case 1: {
                option.top = this.height;
                option.distance = this.height+option.height;
                option.duration = this.duration/this.height*option.distance;
            }
                break;
            case 2: {
                option.left = -option.width;
                option.distance = this.width+option.width;
                option.duration = this.duration/this.width*option.distance;
            }
                break;
            case 3: {
                option.top = -option.height;
                option.distance = this.height+option.height;
                option.duration = this.duration/this.height*option.distance;
            }
                break;
            default: {
                option.left = this.width;
                option.distance = this.width+option.width;
                option.duration = this.duration/this.width*option.distance;
            }
        }
        //生成一个移动对象
        scroller = new Moves(option);
        if(!this.prevMoves) {
            this.lastTime = time = new Date().getTime();
            this.fistMoves = this.prevMoves = scroller;
            this.loopCounter = 1;
            //启动第一个移动对象
            this.list.push(scroller);
            if(!this.useHtml5)
                scroller.startTime = time;
            if(this.startEvent)
                this.startEvent(scroller, time);
            this.animate();
        } else {
            this.prevMoves.nextSibling = scroller;
            this.prevMoves = scroller;
        }
        this.prevMoves = scroller;

        scroller = null;
        element = null;
    }
    //执行动画
    Marquee.prototype.animate = function() {
        var _this = this, //保存执行环境
            time = new Date().getTime(), //当前执行时间,
            scroller = null,
            position = 0, //移动位置
            isNextStart = false,
            interval = time-this.lastTime, //和上一次的执行间隔
            i = 0,
            length = this.list.length;

        if(length) {
            //启动下一个对象
            scroller = this.list[length-1];

            if(scroller.nextSibling && !scroller.nextSibling.startTime) {
                switch(this.direction) {
                    case 1: {
                        if(this.useHtml5) {
                            if(scroller.usedTime >= scroller.duration*scroller.height/scroller.distance){
                                isNextStart = true;
                            }
                        } else {
                            if((scroller.y+scroller.height) <= this.height)
                                isNextStart = true;
                        }
                    }
                        break;
                    case 3: {
                        if(this.useHtml5) {
                            if(scroller.usedTime >= scroller.duration*scroller.height/scroller.distance){
                                isNextStart = true;
                            }
                        } else {
                            if(scroller.y >= 0)
                                isNextStart = true;
                        }
                    }
                        break;
                    case 2: {
                        if(this.useHtml5) {
                            if(scroller.usedTime >= scroller.duration*scroller.width/scroller.distance){
                                isNextStart = true;
                            }
                        } else {
                            if(scroller.x >= 0)
                                isNextStart = true;
                        }
                    }
                        break;
                    default: {
                        if(this.useHtml5) {
                            if(scroller.usedTime >= scroller.duration*scroller.width/scroller.distance){
                                isNextStart = true;
                            }
                        } else {
                            if((scroller.x+scroller.width) <= this.width)
                                isNextStart = true;
                        }
                    }
                }
                if(isNextStart) {
                    scroller = scroller.nextSibling;
                    this.list.push(scroller);
                    if(!this.useHtml5)
                        scroller.startTime = time;
                    //执行开始事件
                    if(this.startEvent)
                        this.startEvent(scroller, time);
                    length +=1;
                }
            }

            for(i=0; i < length; i++){
                scroller = this.list[i];
                if(scroller.usedTime > scroller.duration) {
                    //到达终点，清理元素
                    if(this.endEvent) {
                        this.endEvent(scroller, time);
                    }
                    if(this.loop === 0 || this.loopCounter<this.loop) {
                        //重置元素
                        scroller.reset();
                    } else {
                        //清理元素
                        scroller.destroy();
                    }

                    this.list[i] = null;
                } else if(scroller.reachTime && !this.useHtml5 && this.reachEvent && this.reachEvent(scroller, time)) {
                    //到达边缘暂停
                } else {
                    //正常流程
                    switch(this.direction) {
                        case 1: {
                            if(this.useHtml5) {
                                if(!scroller.startTime) {
                                    scroller.element.style.transition = 'transform '+scroller.duration/1000+'s linear';
                                    scroller.element.style.transform = 'translateY(-' + scroller.distance + 'px)';
                                    scroller.startTime = time;
                                }
                                if(i < 2 && !scroller.reachTime && scroller.usedTime >= this.duration){
                                    scroller.reachTime = time;
                                }
                                scroller.usedTime += interval;
                            } else {
                                position = scroller.top-(scroller.distance * (scroller.usedTime+interval)/scroller.duration);
                                if(i > 0  && this.list[i-1] && (this.list[i-1].y+this.list[i-1].height)>position) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !scroller.reachTime && position<=0) {
                                        //到达边缘
                                        scroller.reachTime = time;
                                        position = 0;
                                    }
                                    scroller.y = position;
                                    scroller.element.style.top = position+'px';
                                    scroller.usedTime += interval;
                                }
                            }
                        }
                            break;
                        case 3: {
                            if(this.useHtml5) {
                                if(!scroller.startTime) {
                                    scroller.element.style.transition = 'transform '+scroller.duration/1000+'s linear';
                                    scroller.element.style.transform = 'translateY(' + scroller.distance + 'px)';
                                    scroller.startTime = time;
                                }
                                if(i < 2 && !scroller.reachTime && scroller.usedTime >= this.duration){
                                    scroller.reachTime = time;
                                }
                                scroller.usedTime += interval;
                            } else {
                                position = scroller.top+(scroller.distance * (scroller.usedTime+interval)/scroller.duration);
                                if(i > 0  && this.list[i-1] && (position+scroller.height)>this.list[i-1].y) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !scroller.reachTime && position>=(this.height-scroller.height)) {
                                        //到达边缘
                                        scroller.reachTime = time;
                                        position = this.height-scroller.height;
                                    }
                                    scroller.y = position;
                                    scroller.element.style.top = position+'px';
                                    scroller.usedTime += interval;
                                }
                            }
                        }
                            break;
                        case 2: {
                            if(this.useHtml5) {
                                if(!scroller.startTime) {
                                    scroller.element.style.transition = 'transform '+scroller.duration/1000+'s linear';
                                    scroller.element.style.transform = 'translateX(' + scroller.distance + 'px)';
                                    scroller.startTime = time;
                                }
                                if(i < 2 && !scroller.reachTime && scroller.usedTime >= this.duration){
                                    scroller.reachTime = time;
                                }
                                scroller.usedTime += interval;
                            } else {
                                position = scroller.left+(scroller.distance * (scroller.usedTime+interval)/scroller.duration);
                                if(i > 0  && this.list[i-1] && (position+scroller.width)>this.list[i-1].x) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !scroller.reachTime && position>=(this.width-scroller.width)) {
                                        //到达边缘
                                        scroller.reachTime = time;
                                        position = this.width-scroller.width;
                                    }
                                    scroller.x = position;
                                    scroller.element.style.left = position+'px';
                                    scroller.usedTime += interval;
                                }
                            }
                        }
                            break;
                        default: {
                            if(this.useHtml5) {
                                if(!scroller.startTime) {
                                    scroller.element.style.transition = 'transform '+scroller.duration/1000+'s linear';
                                    scroller.element.style.transform = 'translateX(-' + scroller.distance + 'px)';
                                    scroller.startTime = time;
                                }
                                if(i < 2 && !scroller.reachTime && scroller.usedTime >= this.duration){
                                    scroller.reachTime = time;
                                }
                                scroller.usedTime += interval;
                            } else {
                                position = scroller.left-(scroller.distance * (scroller.usedTime+interval)/scroller.duration);
                                if(i > 0  && this.list[i-1] && (this.list[i-1].x+this.list[i-1].width)>position) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !scroller.reachTime && position<=0) {
                                        //到达边缘
                                        scroller.reachTime = time;
                                        position = 0;
                                    }
                                    scroller.x = position;
                                    scroller.element.style.left = position+'px';
                                    scroller.usedTime += interval;
                                }
                            }
                        }
                    }
                }
            }
            scroller = null;
            //清理无效元素
            while(this.list.length && !this.list[0]) {
                this.list.shift();
            }
            if(this.list.length){
                animationFrame(function(){_this.animate();});
            } else if(this.loop === 0 || this.loopCounter++<this.loop) {
                //重新启动
                scroller = this.fistMoves;
                this.list.push(scroller);
                if(!this.useHtml5)
                    scroller.startTime = time;
                if(this.startEvent)
                    this.startEvent(scroller, time);
                animationFrame(function(){_this.animate();});
            } else {
                //todo: 空队列，动画结束，执行回调函数
                this.prevMoves = null;
                this.fistMoves = null;
            }
        } else {
            //空队列，动画结束，执行回调函数
            this.prevMoves = null;
        }
        this.lastTime = time;
    }
    window.marquee = function(element,option) {
        if(typeof element == 'string') {
            if(marqueeList[element])
                return marqueeList[element];

            element = window.document.getElementById(element);
            if(element) {
                marqueeList[element.id] = new Marquee(element,option);
                return marqueeList[element.id];
            }
        } else
            return new Marquee(element,option);}
})(window)<commit_msg>scroll改为moves<commit_after>/*
 * 文本滚动组件/marquee
 * http://xhyo.com/
 * version: 1.1
 * Copyright (c) 2015 Bill Chen(chenguibiao@yy.com/48838096@qq.com)
 * Released under the MIT license - http://opensource.org/licenses/MIT
 */
(function(window){
    var animationFrame = null;
    var supportHtml5 = false;
    var marqueeList = {};
    //定义动画执行函数
    if(window.requestAnimationFrame){
        supportHtml5 = true; //只支持标准模式
        animationFrame = window.requestAnimationFrame;
    } else {
        var prefix = ['webkit','moz','ms','o'];
        for(var i = 0; i < prefix.length;i++) {
            if(window[prefix[i]+'RequestAnimationFrame']) {
                animationFrame = window[prefix[i]+'RequestAnimationFrame'];
                break;
            }
        }
        if(!animationFrame) {
            animationFrame = function(callback) {window.setTimeout(callback,1000/60)}
        }
    }
    //移动对象
    function Moves(option) {
        if(!option)
            return;

        this.nextSibling = null; //下一个移动对象
        this.element = option.element; //当前dom元素
        this.width = option.width;
        this.height = option.height;
        this.left = option.left; //初始水平位置
        this.top = option.top; //初始垂直位置
        this.distance = option.distance; //移动距离
        this.duration = option.duration; //移动时间
        this.direction = option.direction; //移动方向
        this.useHtml5 = option.useHtml5; //使用html5

        this.element.style.width = option.width +'px';
        this.element.style.height = option.height +'px';
        this.reset();
    }
    //重置元素
    Moves.prototype.reset = function() {
        //恢复初始位置
        this.element.style.left = this.left +'px';
        this.element.style.top = this.top +'px';
        if(this.useHtml5) {
            this.element.style.transition = '';
            switch(this.direction) {
                case 1: {}
                case 3: {
                    this.element.style.transform = 'translateY(0)';
                }
                    break;
                case 2: {}
                default:{
                    this.element.style.transform = 'translateX(0)';
                }
            }
        } else {
            this.x = this.left; //水平坐标
            this.y = this.top; //垂直坐标
        }

        //重置时间
        this.startTime = 0; //开始时间
        this.reachTime = 0; //到达边缘时间
        this.usedTime = 0; //移动时间
    }
    //销毁元素
    Moves.prototype.destroy = function(){
        this.element.parentNode.removeChild(this.element);
        this.element = null;
        this.nextSibling = null;
    }
    //移动容器对象
    function Marquee(element, option) {
        var nodes, i,length;
        this.list = []; //移动对象列表
        this.container = element; //移动容器
        this.width = element.clientWidth; //容器宽度
        this.height = element.clientHeight; //容器高度
        this.prevMoves = null; //上一个移动对象
        this.fistMoves = null; //第一个移动对象
        this.lastTime = 0; //队列上一次执行时间
        this.loopCounter = 0; //执行次数
        //参数配置
        this.useHtml5 = !!(supportHtml5 && option.useHtml5); //使用html5
        this.loop = typeof option.loop != 'undefined' ? Math.abs(parseInt(option.loop,10)) : 1; //循环次数,0:无限循环;>0:按次数循环
        this.duration = typeof option.duration != 'undefined' ? Math.abs(parseInt(option.duration,10)) : element.clientWidth*10; //移动持续时间
        this.direction = parseInt(option.direction,10) || 0; //0:从右往左；1:从下往上；2:从左往右；3:从上往下
        this.startEvent = option.startEvent || null; //移动元素开始事件
        this.endEvent = option.endEvent || null; //移动结束事件
        this.reachEvent = option.reachEvent || null; //移动元素到达边缘事件,return true的时候到达边缘后暂停
        this.hoverEvent = option.hoverEvent || null; //移动元素鼠标悬停事件

        this.container.style.overflow = 'hidden';
        nodes = this.container.childNodes;
        for(i = 0,length = nodes.length; length && i<length; i++)
            this.push(nodes[i]);
    }
    //添加移动对象
    Marquee.prototype.push = function(element) {
        if(typeof element != 'object' || element.nodeType != 1)
            return null;

        var moves,time,option={direction : this.direction,useHtml5:this.useHtml5};

        //添加元素
        element.style.position = 'absolute';
        if(element.parentNode !== this.container) {
            this.container.appendChild(element);
        }
        option.element = element;
        //记录初始信息
        option.width = element.offsetWidth;
        option.height = element.offsetHeight;
        option.left = element.offsetLeft;
        option.top = element.offsetTop;
        //确定初始位置
        switch(this.direction) {
            case 1: {
                option.top = this.height;
                option.distance = this.height+option.height;
                option.duration = this.duration/this.height*option.distance;
            }
                break;
            case 2: {
                option.left = -option.width;
                option.distance = this.width+option.width;
                option.duration = this.duration/this.width*option.distance;
            }
                break;
            case 3: {
                option.top = -option.height;
                option.distance = this.height+option.height;
                option.duration = this.duration/this.height*option.distance;
            }
                break;
            default: {
                option.left = this.width;
                option.distance = this.width+option.width;
                option.duration = this.duration/this.width*option.distance;
            }
        }
        //生成一个移动对象
        moves = new Moves(option);
        if(!this.prevMoves) {
            this.lastTime = time = new Date().getTime();
            this.fistMoves = this.prevMoves = moves;
            this.loopCounter = 1;
            //启动第一个移动对象
            this.list.push(moves);
            if(!this.useHtml5)
                moves.startTime = time;
            if(this.startEvent)
                this.startEvent(moves, time);
            this.animate();
        } else {
            this.prevMoves.nextSibling = moves;
            this.prevMoves = moves;
        }
        this.prevMoves = moves;

        moves = null;
        element = null;
    }
    //执行动画
    Marquee.prototype.animate = function() {
        var _this = this, //保存执行环境
            time = new Date().getTime(), //当前执行时间,
            moves = null,
            position = 0, //移动位置
            isNextStart = false,
            interval = time-this.lastTime, //和上一次的执行间隔
            i = 0,
            length = this.list.length;

        if(length) {
            //启动下一个对象
            moves = this.list[length-1];

            if(moves.nextSibling && !moves.nextSibling.startTime) {
                switch(this.direction) {
                    case 1: {
                        if(this.useHtml5) {
                            if(moves.usedTime >= moves.duration*moves.height/moves.distance){
                                isNextStart = true;
                            }
                        } else {
                            if((moves.y+moves.height) <= this.height)
                                isNextStart = true;
                        }
                    }
                        break;
                    case 3: {
                        if(this.useHtml5) {
                            if(moves.usedTime >= moves.duration*moves.height/moves.distance){
                                isNextStart = true;
                            }
                        } else {
                            if(moves.y >= 0)
                                isNextStart = true;
                        }
                    }
                        break;
                    case 2: {
                        if(this.useHtml5) {
                            if(moves.usedTime >= moves.duration*moves.width/moves.distance){
                                isNextStart = true;
                            }
                        } else {
                            if(moves.x >= 0)
                                isNextStart = true;
                        }
                    }
                        break;
                    default: {
                        if(this.useHtml5) {
                            if(moves.usedTime >= moves.duration*moves.width/moves.distance){
                                isNextStart = true;
                            }
                        } else {
                            if((moves.x+moves.width) <= this.width)
                                isNextStart = true;
                        }
                    }
                }
                if(isNextStart) {
                    moves = moves.nextSibling;
                    this.list.push(moves);
                    if(!this.useHtml5)
                        moves.startTime = time;
                    //执行开始事件
                    if(this.startEvent)
                        this.startEvent(moves, time);
                    length +=1;
                }
            }

            for(i=0; i < length; i++){
                moves = this.list[i];
                if(moves.usedTime > moves.duration) {
                    //到达终点，清理元素
                    if(this.endEvent) {
                        this.endEvent(moves, time);
                    }
                    if(this.loop === 0 || this.loopCounter<this.loop) {
                        //重置元素
                        moves.reset();
                    } else {
                        //清理元素
                        moves.destroy();
                    }

                    this.list[i] = null;
                } else if(moves.reachTime && !this.useHtml5 && this.reachEvent && this.reachEvent(moves, time)) {
                    //到达边缘暂停
                } else {
                    //正常流程
                    switch(this.direction) {
                        case 1: {
                            if(this.useHtml5) {
                                if(!moves.startTime) {
                                    moves.element.style.transition = 'transform '+moves.duration/1000+'s linear';
                                    moves.element.style.transform = 'translateY(-' + moves.distance + 'px)';
                                    moves.startTime = time;
                                }
                                if(i < 2 && !moves.reachTime && moves.usedTime >= this.duration){
                                    moves.reachTime = time;
                                }
                                moves.usedTime += interval;
                            } else {
                                position = moves.top-(moves.distance * (moves.usedTime+interval)/moves.duration);
                                if(i > 0  && this.list[i-1] && (this.list[i-1].y+this.list[i-1].height)>position) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !moves.reachTime && position<=0) {
                                        //到达边缘
                                        moves.reachTime = time;
                                        position = 0;
                                    }
                                    moves.y = position;
                                    moves.element.style.top = position+'px';
                                    moves.usedTime += interval;
                                }
                            }
                        }
                            break;
                        case 3: {
                            if(this.useHtml5) {
                                if(!moves.startTime) {
                                    moves.element.style.transition = 'transform '+moves.duration/1000+'s linear';
                                    moves.element.style.transform = 'translateY(' + moves.distance + 'px)';
                                    moves.startTime = time;
                                }
                                if(i < 2 && !moves.reachTime && moves.usedTime >= this.duration){
                                    moves.reachTime = time;
                                }
                                moves.usedTime += interval;
                            } else {
                                position = moves.top+(moves.distance * (moves.usedTime+interval)/moves.duration);
                                if(i > 0  && this.list[i-1] && (position+moves.height)>this.list[i-1].y) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !moves.reachTime && position>=(this.height-moves.height)) {
                                        //到达边缘
                                        moves.reachTime = time;
                                        position = this.height-moves.height;
                                    }
                                    moves.y = position;
                                    moves.element.style.top = position+'px';
                                    moves.usedTime += interval;
                                }
                            }
                        }
                            break;
                        case 2: {
                            if(this.useHtml5) {
                                if(!moves.startTime) {
                                    moves.element.style.transition = 'transform '+moves.duration/1000+'s linear';
                                    moves.element.style.transform = 'translateX(' + moves.distance + 'px)';
                                    moves.startTime = time;
                                }
                                if(i < 2 && !moves.reachTime && moves.usedTime >= this.duration){
                                    moves.reachTime = time;
                                }
                                moves.usedTime += interval;
                            } else {
                                position = moves.left+(moves.distance * (moves.usedTime+interval)/moves.duration);
                                if(i > 0  && this.list[i-1] && (position+moves.width)>this.list[i-1].x) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !moves.reachTime && position>=(this.width-moves.width)) {
                                        //到达边缘
                                        moves.reachTime = time;
                                        position = this.width-moves.width;
                                    }
                                    moves.x = position;
                                    moves.element.style.left = position+'px';
                                    moves.usedTime += interval;
                                }
                            }
                        }
                            break;
                        default: {
                            if(this.useHtml5) {
                                if(!moves.startTime) {
                                    moves.element.style.transition = 'transform '+moves.duration/1000+'s linear';
                                    moves.element.style.transform = 'translateX(-' + moves.distance + 'px)';
                                    moves.startTime = time;
                                }
                                if(i < 2 && !moves.reachTime && moves.usedTime >= this.duration){
                                    moves.reachTime = time;
                                }
                                moves.usedTime += interval;
                            } else {
                                position = moves.left-(moves.distance * (moves.usedTime+interval)/moves.duration);
                                if(i > 0  && this.list[i-1] && (this.list[i-1].x+this.list[i-1].width)>position) {
                                    //和前一个元素重叠，暂停
                                } else {
                                    if(i < 2 && !moves.reachTime && position<=0) {
                                        //到达边缘
                                        moves.reachTime = time;
                                        position = 0;
                                    }
                                    moves.x = position;
                                    moves.element.style.left = position+'px';
                                    moves.usedTime += interval;
                                }
                            }
                        }
                    }
                }
            }
            //清理无效元素
            while(this.list.length && !this.list[0]) {
                this.list.shift();
            }
            if(this.list.length){
                animationFrame(function(){_this.animate();});
            } else if(this.loop === 0 || this.loopCounter++<this.loop) {
                //重新启动
                moves = this.fistMoves;
                this.list.push(moves);
                if(!this.useHtml5)
                    moves.startTime = time;
                if(this.startEvent)
                    this.startEvent(moves, time);
                animationFrame(function(){_this.animate();});
            } else {
                //todo: 空队列，动画结束，执行回调函数
                this.prevMoves = null;
                this.fistMoves = null;
            }
            moves = null;
        } else {
            //空队列，动画结束，执行回调函数
            this.prevMoves = null;
        }
        this.lastTime = time;
    }
    window.marquee = function(element,option) {
        if(typeof element == 'string') {
            if(marqueeList[element])
                return marqueeList[element];

            element = window.document.getElementById(element);
            if(element) {
                marqueeList[element.id] = new Marquee(element,option);
                return marqueeList[element.id];
            }
        } else
            return new Marquee(element,option);}
})(window)<|endoftext|>


<commit_before>module.exports = '2018-02-01';
<commit_msg>bump version<commit_after>module.exports = '2018-02-02';
<|endoftext|>


<commit_before>describe("Voice().nextNoteStartMin(fraction)", function() {
  xit("calls min on _startTime with fraction and returns the result",
  function() {
    var voice = Voice();
    spyOn(voice._startTime, "min").and.returnValue("start time min");

    expect(voice.nextNoteStartMin("fraction")).toEqual("start time min");

    expect(voice._startTime.min).toHaveBeenCalledWith("fraction");
  });
});<commit_msg>Reintroduced test after implementation change.<commit_after>describe("Voice().nextNoteStartMin(fraction)", function() {
  it("calls min on _startTime with fraction and returns the result",
  function() {
    var voice = Voice([]);
    spyOn(voice._nextNoteStart, "min").and.returnValue("next note start min");

    expect(voice.nextNoteStartMin("fraction")).toEqual("next note start min");

    expect(voice._nextNoteStart.min).toHaveBeenCalledWith("fraction");
  });
});<|endoftext|>


<commit_before>function load_songs(textarea) {
    var encoded_uri = textarea.value;
    var decoded = decodeURIComponent(encoded_uri);
    var without_protocol = decoded.replace("irealb://", "");
    var unsplitted = without_protocol.split("==0=0===");
    for(i in unsplitted) {
        song = unsplitted[i].split("=");
        title = song[0];
        author = song[1];
        localStorage[title + " (" + author + ")"] = unsplitted[i]
    }
}
function swap(splitted, i, j) {
    tmp = splitted[i];
    splitted[i] = splitted[j];
    splitted[j] = tmp;
}
function mirror_swap(str, start, size) {
    var splitted = str.split('');
    var count = Math.floor(size / 2);
    for(var i = 0; i < count; i++) {
        swap(splitted, start + i, size + start - i);
    }
    return splitted.join("");
}
function unwarble(warbled) {
    var unwarbled = warbled.replace('1r34LbKcu7', '');
    for(var i = 0; i + 51 < unwarbled.length; i += 50) {
        unwarbled = mirror_swap(mirror_swap(mirror_swap(unwarbled, i + 10, 29), i + 5, 39), i, 49)
    }
    return unwarbled.replace(/XyQ/g, "   ").replace(/Kcl/g, "| x").replace(/LZ/g, "|");
}
function get_sheet(unwarbled) {
    unwarbled = unwarbled.replace(/\*([ABC])/g, "$1");
    unwarbled = unwarbled.replace(/\[/g, " ");
    unwarbled = unwarbled.replace(/T(.)(.)/g, "$1$1");
    unwarbled = unwarbled.replace(/\^/g, "Δ");
    var splitted = unwarbled.split('');
    var open_div = "
";
    var close_div = "
";
    var open_span = "";
    var close_span = "";
    var out = open_div + open_span;
    var bars = 0;
    for(i = 0; i < splitted.length; i++) {
        var c = splitted[i];
        var add = "";
        if(c == "|") {
            c = close_span;
            bars += 1;
            if(bars < 4)
            {
                c += open_span
            }
        }
        else { if(c == "x") { c = "%"; } }
        if(bars == 4 || c == '}' || c == ']') {
            bars = 0;
            add = close_div + open_div + open_span;
        }
        out += c + add;
    }
    return out + close_span + close_div;
}
function line_to_mma_chords(line) {
    var chords = line.split(" ");
    if(chords.length == 2) {
        chords = [chords[0], "/", chords[1]];
    }
    return chords.join(" ");
}
var worker = new Worker("//rawgit.com/yazgoo/pypyjs-mma/25edf7359913691af75129e0f0ab05f264fdf20c/worker.js");
// preload mma by running it once with an empty file
worker.postMessage(["Groove Swing\n0 A7"]);
worker.onmessage = function(e) {
  console.log('Message received from worker');
  console.log(btoa(e.data));
  var data = e.data;
  console.log("playing " + data);
  play(data);
}
function play_mma(mma) {
  worker.postMessage([mma]);
  console.log('Message posted to worker');
}
function play_song(unwarbled) {
    var previous = "";
    unwarbled = unwarbled.replace(/T../, '?Groove Swing\n')
        .replace(/\{/g, "\n?Repeat\n").replace(/}/g, "\n?RepeatEnd\n")
        .replace(/\*./g, "").replace(/N1/g, "\n?RepeatEnding\\2\n").replace("][", "")
        .replace("[", "\n")
        .replace(/N2/g, "").replace("Z", "").replace(/s/g, " ").replace(/,/g, " ")
        .replace(/-/g, "m").replace(/\^/g, "M").replace(/h/g, "dim")
        .replace(/\|/g, "\n").replace(/\]\[/g, "\n").replace(/\[/, "\n")
        .replace(/l/g, "\n").replace(/x/g, "").replace(/\([^\)]*\)/g, "")/* lets ignore stuff under () for now*/
    splitted = unwarbled.split("\n");
    var previous = "";
    k = 0;
    for(var i = 0; i < splitted.length; i++) {
        var line = splitted[i];
        if(line.length == 0 || line[0] == '?') previous += line.replace(/\?/g, "")
        else {
            previous += "" + k + " " + line_to_mma_chords(line);
            k += 1;
        }
        previous += "\n";
    }
    console.log(previous);
    play_mma(previous);
}
function show_song(title) {
    var song = localStorage[title];
    localStorage["last_song"] = song;
    var splitted = song.split("=");
    var title = splitted[0];
    var author = splitted[1];
    var unwarbled = unwarble(splitted[6]);
    set_content(""+title+" ("+author+")"
            + "<input type=button value='>' onclick=\"play_song('"+unwarbled+"')\"/>

"
            + get_sheet(unwarbled));
}
var songs_list_written;
var songs_list_div;
function add_songs_list() {
  var i;
  s = ""
    for(i = songs_list_written; i < (songs_list_written + 100) && i < localStorage.length; i++) {
        var title = localStorage.key(i);
        s += "" + title  + "
";
    }
  songs_list_div.innerHTML += s;
    songs_list_written += 100;
    if(i < localStorage.length) setTimeout(add_songs_list(), 500);
}
function show_songs_list(div) {
    songs_list_div = div;
    div.innerHTML = "";
    songs_list_written = 0;
    add_songs_list();
}
function set_content(str) {
    var content = document.getElementById("content");
    content.innerHTML = str;
}
function show_imports() {
    set_content("<input type=text onchange='load_songs(this)'/>");
}
function show_about() {
    set_content('Mooche is free software (as in freedom).
'
            +'This means it guarantees 4 fundamentals rights:
'
            +'
'
            +'
Freedom 0: The freedom to run the program for any purpose.
'
            +'
Freedom 1: The freedom to study how the program works, and change it to make it do what you wish.
'
            +'
Freedom 2: The freedom to redistribute and make copies so you can help your neighbor.
'
            +'
Freedom 3: The freedom to improve the program, and release your improvements (and modified versions in general) to the public, so that the whole community benefits.
'
            +'
'
            +'')
}
function show_songs() {
    show_songs_list(document.getElementById('content'));
}
function show_songs_or_last_song() {
    if(localStorage["last_song"] != null) {
        show_song("last_song");
    }
    else {
        show_songs();
    }
}

<commit_msg>adding commit fetch for mma<commit_after>function load_songs(textarea) {
    var encoded_uri = textarea.value;
    var decoded = decodeURIComponent(encoded_uri);
    var without_protocol = decoded.replace("irealb://", "");
    var unsplitted = without_protocol.split("==0=0===");
    for(i in unsplitted) {
        song = unsplitted[i].split("=");
        title = song[0];
        author = song[1];
        localStorage[title + " (" + author + ")"] = unsplitted[i]
    }
}
function swap(splitted, i, j) {
    tmp = splitted[i];
    splitted[i] = splitted[j];
    splitted[j] = tmp;
}
function mirror_swap(str, start, size) {
    var splitted = str.split('');
    var count = Math.floor(size / 2);
    for(var i = 0; i < count; i++) {
        swap(splitted, start + i, size + start - i);
    }
    return splitted.join("");
}
function unwarble(warbled) {
    var unwarbled = warbled.replace('1r34LbKcu7', '');
    for(var i = 0; i + 51 < unwarbled.length; i += 50) {
        unwarbled = mirror_swap(mirror_swap(mirror_swap(unwarbled, i + 10, 29), i + 5, 39), i, 49)
    }
    return unwarbled.replace(/XyQ/g, "   ").replace(/Kcl/g, "| x").replace(/LZ/g, "|");
}
function get_sheet(unwarbled) {
    unwarbled = unwarbled.replace(/\*([ABC])/g, "$1");
    unwarbled = unwarbled.replace(/\[/g, " ");
    unwarbled = unwarbled.replace(/T(.)(.)/g, "$1$1");
    unwarbled = unwarbled.replace(/\^/g, "Δ");
    var splitted = unwarbled.split('');
    var open_div = "
";
    var close_div = "
";
    var open_span = "";
    var close_span = "";
    var out = open_div + open_span;
    var bars = 0;
    for(i = 0; i < splitted.length; i++) {
        var c = splitted[i];
        var add = "";
        if(c == "|") {
            c = close_span;
            bars += 1;
            if(bars < 4)
            {
                c += open_span
            }
        }
        else { if(c == "x") { c = "%"; } }
        if(bars == 4 || c == '}' || c == ']') {
            bars = 0;
            add = close_div + open_div + open_span;
        }
        out += c + add;
    }
    return out + close_span + close_div;
}
function line_to_mma_chords(line) {
    var chords = line.split(" ");
    if(chords.length == 2) {
        chords = [chords[0], "/", chords[1]];
    }
    return chords.join(" ");
}
var worker = new Worker("//rawgit.com/yazgoo/pypyjs-mma/f9fefa9f9c49b020ef9aa1f03d771e6cddc80b8f/worker.js");
// preload mma by running it once with an empty file
worker.postMessage(["Groove Swing\n0 A7"]);
worker.onmessage = function(e) {
  console.log('Message received from worker');
  console.log(btoa(e.data));
  var data = e.data;
  console.log("playing " + data);
  play(data);
}
function play_mma(mma) {
  worker.postMessage([mma]);
  console.log('Message posted to worker');
}
function play_song(unwarbled) {
    var previous = "";
    unwarbled = unwarbled.replace(/T../, '?Groove Swing\n')
        .replace(/\{/g, "\n?Repeat\n").replace(/}/g, "\n?RepeatEnd\n")
        .replace(/\*./g, "").replace(/N1/g, "\n?RepeatEnding\\2\n").replace("][", "")
        .replace("[", "\n")
        .replace(/N2/g, "").replace("Z", "").replace(/s/g, " ").replace(/,/g, " ")
        .replace(/-/g, "m").replace(/\^/g, "M").replace(/h/g, "dim")
        .replace(/\|/g, "\n").replace(/\]\[/g, "\n").replace(/\[/, "\n")
        .replace(/l/g, "\n").replace(/x/g, "").replace(/\([^\)]*\)/g, "")/* lets ignore stuff under () for now*/
    splitted = unwarbled.split("\n");
    var previous = "";
    k = 0;
    for(var i = 0; i < splitted.length; i++) {
        var line = splitted[i];
        if(line.length == 0 || line[0] == '?') previous += line.replace(/\?/g, "")
        else {
            previous += "" + k + " " + line_to_mma_chords(line);
            k += 1;
        }
        previous += "\n";
    }
    console.log(previous);
    play_mma(previous);
}
function show_song(title) {
    var song = localStorage[title];
    localStorage["last_song"] = song;
    var splitted = song.split("=");
    var title = splitted[0];
    var author = splitted[1];
    var unwarbled = unwarble(splitted[6]);
    set_content(""+title+" ("+author+")"
            + "<input type=button value='>' onclick=\"play_song('"+unwarbled+"')\"/>

"
            + get_sheet(unwarbled));
}
var songs_list_written;
var songs_list_div;
function add_songs_list() {
  var i;
  s = ""
    for(i = songs_list_written; i < (songs_list_written + 100) && i < localStorage.length; i++) {
        var title = localStorage.key(i);
        s += "" + title  + "
";
    }
  songs_list_div.innerHTML += s;
    songs_list_written += 100;
    if(i < localStorage.length) setTimeout(add_songs_list(), 500);
}
function show_songs_list(div) {
    songs_list_div = div;
    div.innerHTML = "";
    songs_list_written = 0;
    add_songs_list();
}
function set_content(str) {
    var content = document.getElementById("content");
    content.innerHTML = str;
}
function show_imports() {
    set_content("<input type=text onchange='load_songs(this)'/>");
}
function show_about() {
    set_content('Mooche is free software (as in freedom).
'
            +'This means it guarantees 4 fundamentals rights:
'
            +'
'
            +'
Freedom 0: The freedom to run the program for any purpose.
'
            +'
Freedom 1: The freedom to study how the program works, and change it to make it do what you wish.
'
            +'
Freedom 2: The freedom to redistribute and make copies so you can help your neighbor.
'
            +'
Freedom 3: The freedom to improve the program, and release your improvements (and modified versions in general) to the public, so that the whole community benefits.
'
            +'
'
            +'')
}
function show_songs() {
    show_songs_list(document.getElementById('content'));
}
function show_songs_or_last_song() {
    if(localStorage["last_song"] != null) {
        show_song("last_song");
    }
    else {
        show_songs();
    }
}

<|endoftext|>


<commit_before>var log = console.log.bind(console);
var MIN_SUM = 20;

var bot = {

  VERSION: "Default JavaScript folding player",

  bet_request: function(gs, makeBet) {
    this.GS = gs;

    try {
      bet = this.getBet();
    }
    catch(err) {
      log('ERRORe', err);
    }

    makeBet(makeBet);
  },

  showdown: function(gs) {

  },

  getBet: function() {
    var bet = 0;
    var gs = this.GS;
    var min_raise = gs.minimum_raise + 2 * gs.small_blind;

    if (this.isPreFlop()) {
      // PRE FLOP
      if (this.isHandPair()) {
        bet = min_raise * 2;
      } else if (this.getOurCardSum() > MIN_SUM) {
        bet = min_raise;
      }
    } else {
      // POST FLOP
      if (this.isHandPair() || this.isTablePairOrMore()) {
        if (this.isSet() || this.isFlush()){
          bet = this.getOurPlayer().stack;
        } else {
          bet = min_raise * 2;
        }
      } else if (this.getOurCardSum() > 20) {
        bet = min_raise;
      }
    }

    return bet;
  },

  getOurPlayer: function() {
    var players = this.GS.players;

    for (var i = 0; i < players.length; i++) {
      if (players[i].hole_cards) {
        return players[i];
      }
    }
  },

  getOurCards: function() {
    return this.getOurPlayer().hole_cards;
  },

  getTableCards: function() {
    return this.GS.community_cards;
  },

  getOurCardSum: function() {
    var cards = this.getOurCards();

    return cards.reduce(function(memo, card) {
      return memo + this.getCardValue(card);
    }.bind(this), 0);
  },

  getCardValue: function(card) {
    var high = {
      'J': 11,
      'Q': 12,
      'K': 13,
      'A': 14
    };

    return card.rank in high
      ? high[card.rank]
      : +card.rank;
  },

  isHandPair: function() {
    var cards = this.getOurCards();

    return cards[0].rank === cards[1].rank;
  },

  isTablePairOrMore: function() {
    var hash = this.getCardsHash();
    for (var key in hash) {
      if (hash[key] > 1) {
        return true;
      }
    }

    return false;
  },
  isSet: function() {
    var hash = this.getCardsHash();
    for (var key in hash) {
      if (hash[key] == 3) {
        return true;
      }
      return false;
    }

  },

  isFlush: function() {
    var hash = this.getSuitsHash();
    for (var key in hash) {
      if (hash[key] === 5) {
        return true;
      }
    }
    return false;
  },

  isPreFlop: function() {
    return this.GS.community_cards.length === 0;
  },

  isFlop: function() {
    return this.GS.community_cards.length === 3;
  },

  getSuitsHash: function() {
    var table = this.getTableCards();
    var our = this.getOurCards();
    var allcards = table.concat(our);
    var hash = {};
    var suit;

    for (var i = 0; i < allcards.length; i++) {
      suit = allcards[i].suit;

      hash[suit] = hash[suit] ? hash[suit] + 1  : 1;
    }

    return hash;
  },

  getCardsHash: function() {
    var table = this.getTableCards();
    var our = this.getOurCards();
    var allcards = table.concat(our);
    var hash = {};
    var rank;

    for (var i = 0; i < allcards.length; i++) {
      rank = allcards[i].rank;

      hash[rank] = hash[rank] ? hash[rank] + 1  : 1;
    }

    return hash;
  }
};

module.exports = bot;
<commit_msg>added pair check<commit_after>var log = console.log.bind(console);
var MIN_SUM = 20;

var bot = {

  VERSION: "Default JavaScript folding player",

  bet_request: function(gs, makeBet) {
    this.GS = gs;

    try {
      bet = this.getBet();
    }
    catch(err) {
      log('ERRORe', err);
    }

    makeBet(makeBet);
  },

  high_card_value: 11,

  showdown: function(gs) {

  },

  getBet: function() {
    var bet = 0;
    var gs = this.GS;
    var min_raise = gs.minimum_raise + 2 * gs.small_blind;

    if (this.isPreFlop()) {
      // PRE FLOP
      if (this.isHandPair()) {
        bet = min_raise * 2;
      } else if (this.getOurCardSum() > MIN_SUM) {
        bet = min_raise;
      }
    } else {
      // POST FLOP
      if (this.isHandPair() || this.isTablePairOrMore()) {
        if (this.isSet() || this.isFlush()){
          bet = this.getOurPlayer().stack;
        } else {
          bet = min_raise * 2;
        }
      } else if (this.getOurCardSum() > 20) {
        bet = min_raise;
      }
    }

    return bet;
  },

  getOurPlayer: function() {
    var players = this.GS.players;

    for (var i = 0; i < players.length; i++) {
      if (players[i].hole_cards) {
        return players[i];
      }
    }
  },

  getOurCards: function() {
    return this.getOurPlayer().hole_cards;
  },

  getTableCards: function() {
    return this.GS.community_cards;
  },

  getOurCardSum: function() {
    var cards = this.getOurCards();

    return cards.reduce(function(memo, card) {
      return memo + this.getCardValue(card);
    }.bind(this), 0);
  },

  getCardValue: function(card) {
    var high = {
      'J': 11,
      'Q': 12,
      'K': 13,
      'A': 14
    };

    return card.rank in high
      ? high[card.rank]
      : +card.rank;
  },

  isHandPair: function() {
    var cards = this.getOurCards();

    return cards[0].rank === cards[1].rank;
  },

  isTablePairOrMore: function() {
    var hash = this.getCardsHash();
    for (var key in hash) {
      if (hash[key] > 1) {
        return true;
      }
    }

    return false;
  },
  isPairWorthPlaying: function() {
    var hash = this.gerCardsHash(),
        pairedCards = [],
        countOfStrongerCards = 0;
    for (var key in hash) {
      if (hash[key] == 2) {
        pairedCards.push(this.getCardValue(hash[key]));
      }
    }
    if (pairedCards.length > 1) {
      //two pairs worth playing
      return true;
    }
    if (pairedCards[0] >= this.high_card_value){
      //is a high pair
      return true;
    } else {
      for (var key in hash) {
        if (pairedCards.indexOf(this.getCardValue(key)) == -1) {
          if (this.getCardValue(key) > pairedCards[0]){
            countOfStrongerCards++;
          }
        }
      }
      return !(countOfStrongerCards > 1);
    }
  },
  isSet: function() {
    var hash = this.getCardsHash();
    for (var key in hash) {
      if (hash[key] == 3) {
        return true;
      }
      return false;
    }

  },

  isFlush: function() {
    var hash = this.getSuitsHash();
    for (var key in hash) {
      if (hash[key] === 5) {
        return true;
      }
    }
    return false;
  },

  isPreFlop: function() {
    return this.GS.community_cards.length === 0;
  },

  isFlop: function() {
    return this.GS.community_cards.length === 3;
  },

  getSuitsHash: function() {
    var table = this.getTableCards();
    var our = this.getOurCards();
    var allcards = table.concat(our);
    var hash = {};
    var suit;

    for (var i = 0; i < allcards.length; i++) {
      suit = allcards[i].suit;

      hash[suit] = hash[suit] ? hash[suit] + 1  : 1;
    }

    return hash;
  },

  getCardsHash: function() {
    var table = this.getTableCards();
    var our = this.getOurCards();
    var allcards = table.concat(our);
    var hash = {};
    var rank;

    for (var i = 0; i < allcards.length; i++) {
      rank = allcards[i].rank;

      hash[rank] = hash[rank] ? hash[rank] + 1  : 1;
    }

    return hash;
  }
};

module.exports = bot;
<|endoftext|>


<commit_before>var t0 = performance.now();
function mooche_status(text) {
  console.log(text)
  var current = document.getElementById("mooche_status").innerHTML;
  current = current.split("
");
  current = [text].concat(current);
  var text = "";
  for(var i = 0; i < 5 && i < current.length; i++) {
    text += current[i] + "
"
  }
  document.getElementById("mooche_status").innerHTML = text;
}
setInterval(function(){ mooche_status(""); }, 5000);
var songLoader = new Worker("song_loader.js");
// preload mma by running it once with an empty file
songLoader.onmessage = function(e) {
  mooche_status("songs loaded")
}
function load_songs(textarea) {
  mooche_status("loading songs...")
  songLoader.postMessage(textarea.value);
}
function swap(splitted, i, j) {
    tmp = splitted[i];
    splitted[i] = splitted[j];
    splitted[j] = tmp;
}
function mirror_swap(str, start, size) {
    var splitted = str.split('');
    var count = Math.floor(size / 2);
    for(var i = 0; i < count; i++) {
        swap(splitted, start + i, size + start - i);
    }
    return splitted.join("");
}
function unwarble(warbled) {
    var unwarbled = warbled.replace('1r34LbKcu7', '');
    for(var i = 0; i + 51 < unwarbled.length; i += 50) {
        unwarbled = mirror_swap(mirror_swap(mirror_swap(unwarbled, i + 10, 29), i + 5, 39), i, 49) } return unwarbled.replace(/XyQ/g, "   ").replace(/Kcl/g, "| x").replace(/LZ/g, "|"); } function get_sheet(unwarbled) {
  console.log(unwarbled)
    unwarbled = unwarbled.replace(/\*([ABC])/g, "$1");
    unwarbled = unwarbled.replace(/\[/g, " ");
    unwarbled = unwarbled.replace(/\{/g, " ");
    unwarbled = unwarbled.replace(/T(.)(.)/g, "$1$1");
    unwarbled = unwarbled.replace(/\^/g, "Δ");
    var splitted = unwarbled.split('');
    var open_div = "
";
    var close_div = "
";
    var open_span = "";
    var close_span = "";
    var second_bar = " "
    var double_close_span = close_span + second_bar;
    var out = open_div + open_span;
    var bars = 0;
    for(i = 0; i < splitted.length; i++) {
        var c = splitted[i];
        var add = "";
        if(c == "|") {
            c = close_span;
          bars += 1;
          if(bars < 4)
          {
            c += open_span
          }
        } else { if(c == "x") { c = "%"; } }
        if(bars == 4 || c == '}' || c == ']') {
            bars = 0;
            if(c == "]") {
                c = double_close_span;
            }
            else {
              c = ""
            }
            addup = ""
            add = close_div + open_div + open_span;
        }
        out += c + add;
    }
    return out + close_span + close_div;
}
function line_to_mma_chords(line) {
    var chords = line.split(" ");
    if(chords.length == 2) {
        chords = [chords[0], "/", chords[1]];
    }
    return chords.join(" ");
}
var play_song_class_name = "play_song_not_ready";
var worker = new Worker("/yazgoo/mma.js/29e5bba60c48da982e587a6a798719568af68a6b/worker.js");
// preload mma by running it once with an empty file
worker.postMessage(["Groove Swing\n0 A7"]);
mooche_status("loading MMA...")
worker.onmessage = function(e) {
  var data = e.data;
  mooche_status("loading MMA done")
  var play_song = document.getElementById("play_song");
  play_song_class_name = "play_song";
  document.getElementById("stop").value = "■"
  var t1 = performance.now();
  console.log("playing a song took " + (t1 - t0) + " milliseconds.")
  if(play_song != null && play_song.className == "play_song_not_ready")
  {
    play_song.className = play_song_class_name;
  }
  if(data == undefined) {
    mooche_status("MMA conversion failed");
  }
  else {
    mooche_status("playing song...");
    play(data);
  }
}
function play_mma(mma) {
  worker.postMessage([mma]);
}
function to_mma(unwarbled) {
    unwarbled = "?Groove Swing\n" + unwarbled.replace(/T../, '')/* todo actually use this tempo stuff */
        .replace(/\{/g, "\n?Repeat\n").replace(/} +/, "\n?RepeatEnding\n")
        .replace(/}/g, "\n?RepeatEnd\n")
        .replace(/\*./g, "").replace(/N1/g, "\n?RepeatEnding\n").replace(/\]\[/g, "?RepeatEnd\n")
        .replace(/<.*>/, "")
        .replace("[", "\n")
        .replace(/N2/g, "\n?RepeatEnding\n").replace("Z", "").replace(/s/g, " ").replace(/,/g, " ")
        .replace(/-/g, "m").replace(/\^/g, "M").replace(/h/g, "").replace(/o7/g, "m7b5").replace(/alt/g, "#5b7b9b13")/*temporary alt replacement*/
        .replace(/\|/g, "\n").replace(/\]\[/g, "\n").replace(/\[/, "\n")
        .replace(/l/g, "\n").replace(/x/g, "").replace(/\([^\)]*\)/g, "")/* lets ignore stuff under () for now*/
    splitted = unwarbled.split("\n");
    var previous = "";
    k = 0;
    for(var i = 0; i < splitted.length; i++) {
        var line = splitted[i];
        if(line.length == 0 || line[0] == '?') previous += line.replace(/\?/g, "")
        else {
            previous += "" + k + " " + line_to_mma_chords(line);
            k += 1;
        }
        previous += "\n";
    }
    return previous
}
function to_mma_opal(unwarbled) {
  return Opal.MMAParser.$new(unwarbled).$run();
}
function play_song(unwarbled) {
  var previous = to_mma_opal(unwarbled)
  play_mma(previous);
}
function get_song(songname, f, error_handler) {
  var openRequest = indexedDB.open("mooche",2);
  openRequest.onupgradeneeded = function(e) {
    var thisDB = e.target.result;
    if(!thisDB.objectStoreNames.contains("songs")) {
      thisDB.createObjectStore("songs", {keyPath: "key"});
    }
  }
  openRequest.onsuccess = function(e) {
    db = e.target.result;
    var transaction = db.transaction(["songs"], "readonly");
    var objectStore = transaction.objectStore("songs");
    var request = objectStore.get(songname);
    request.onsuccess = function(e) {
      f(e.target.result.content);
    }
    request.onerror = function(e) {
      error_handler(e);
    }
  }
  openRequest.onerror = function(e) {
    error_handler(e);
  }
}
function save_song(songname, song) {
  var openRequest = indexedDB.open("mooche",2);
  openRequest.onupgradeneeded = function(e) {
    var thisDB = e.target.result;
    if(!thisDB.objectStoreNames.contains("songs")) {
      thisDB.createObjectStore("songs", {keyPath: "key"});
    }
  }
	openRequest.onsuccess = function(e) {
    db = e.target.result;
		var transaction = db.transaction(["songs"],"readwrite");
		var store = transaction.objectStore("songs");
    store.put({key: songname, content: song})
  }
}
function show_song(songname, error_handler) {
  get_song(songname, function(song) {
    save_song("last_song", song)
    var splitted = song.split("=");
    var title = splitted[0];
    var author = splitted[1].split(" ").reverse().join(" ");
    var unwarbled = unwarble(splitted[6]);
    set_content(
        "<input type=button id=play_song class="+play_song_class_name
        + " value='▶' onclick=\"play_song('"+unwarbled+"')\"/>"
				+ ""+title+""
        + ""+author+"

"
        + get_sheet(unwarbled));
  }, error_handler);
}
var songs_list_written;
var songs_list_div;
function show_songs_list(div) {
  songs_list_div = div;
  mooche_status("showing songs...");
  var openRequest = indexedDB.open("mooche",2);
  openRequest.onupgradeneeded = function(e) {
    var thisDB = e.target.result;
    if(!thisDB.objectStoreNames.contains("songs")) {
      thisDB.createObjectStore("songs", {keyPath: "key"});
    }
  }
  openRequest.onsuccess = function(e) {
    db = e.target.result;
    var transaction = db.transaction(["songs"],"readonly");
    var store = transaction.objectStore("songs");
    var cursor = store.openCursor();
    var s = ""
    var i = 0;
    songs_list_div.innerHTML = ""
    cursor.onsuccess = function(e) {
      var res = e.target.result;
      if(res) {
        s += "
" + res.key  + "
";
        i += 1;
        if(i > 100) {
          songs_list_div.innerHTML += s;
          s = "";
          i = 0;
        }
        res.continue();
      } else {
          songs_list_div.innerHTML += s;
      }
    }
  }
}
function set_content(str) {
    var content = document.getElementById("content");
    content.innerHTML = str;
}
function show_imports() {
    set_content("
Right click and copy link location on song links below,"
        + "then paste it in this text field below
"
        + "<textarea type=text class=import onchange='load_songs(this)'></textarea>"
        + "");
}
function show_about() {
    set_content('Mooche is free software (as in freedom).
'
            +'This means it guarantees 4 fundamentals rights:
'
            +'
'
            +'
Freedom 0: The freedom to run the program for any purpose.
'
            +'
Freedom 1: The freedom to study how the program works, and change it to make it do what you wish.
'
            +'
Freedom 2: The freedom to redistribute and make copies so you can help your neighbor.
'
            +'
Freedom 3: The freedom to improve the program, and release your improvements (and modified versions in general) to the public, so that the whole community benefits.
'
            +'
'
            + "source available here.")
}
function show_songs() {
    show_songs_list(document.getElementById('content'));
}
function show_songs_or_last_song() {
  show_song("last_song", show_songs);
}

<commit_msg>stopping song in case of tab change<commit_after>var t0 = performance.now();
function mooche_status(text) {
  console.log(text)
  var current = document.getElementById("mooche_status").innerHTML;
  current = current.split("
");
  current = [text].concat(current);
  var text = "";
  for(var i = 0; i < 5 && i < current.length; i++) {
    text += current[i] + "
"
  }
  document.getElementById("mooche_status").innerHTML = text;
}
document.addEventListener("visibilitychange", function(event) {
  if(document.hidden)
  {
    mooche_status("stopping because changing tab")
    stop();
  }
})
setInterval(function(){ mooche_status(""); }, 5000);
var songLoader = new Worker("song_loader.js");
// preload mma by running it once with an empty file
songLoader.onmessage = function(e) {
  mooche_status("songs loaded")
}
function load_songs(textarea) {
  mooche_status("loading songs...")
  songLoader.postMessage(textarea.value);
}
function swap(splitted, i, j) {
    tmp = splitted[i];
    splitted[i] = splitted[j];
    splitted[j] = tmp;
}
function mirror_swap(str, start, size) {
    var splitted = str.split('');
    var count = Math.floor(size / 2);
    for(var i = 0; i < count; i++) {
        swap(splitted, start + i, size + start - i);
    }
    return splitted.join("");
}
function unwarble(warbled) {
    var unwarbled = warbled.replace('1r34LbKcu7', '');
    for(var i = 0; i + 51 < unwarbled.length; i += 50) {
        unwarbled = mirror_swap(mirror_swap(mirror_swap(unwarbled, i + 10, 29), i + 5, 39), i, 49) } return unwarbled.replace(/XyQ/g, "   ").replace(/Kcl/g, "| x").replace(/LZ/g, "|"); } function get_sheet(unwarbled) {
  console.log(unwarbled)
    unwarbled = unwarbled.replace(/\*([ABC])/g, "$1");
    unwarbled = unwarbled.replace(/\[/g, " ");
    unwarbled = unwarbled.replace(/\{/g, " ");
    unwarbled = unwarbled.replace(/T(.)(.)/g, "$1$1");
    unwarbled = unwarbled.replace(/\^/g, "Δ");
    var splitted = unwarbled.split('');
    var open_div = "
";
    var close_div = "
";
    var open_span = "";
    var close_span = "";
    var second_bar = " "
    var double_close_span = close_span + second_bar;
    var out = open_div + open_span;
    var bars = 0;
    for(i = 0; i < splitted.length; i++) {
        var c = splitted[i];
        var add = "";
        if(c == "|") {
            c = close_span;
          bars += 1;
          if(bars < 4)
          {
            c += open_span
          }
        } else { if(c == "x") { c = "%"; } }
        if(bars == 4 || c == '}' || c == ']') {
            bars = 0;
            if(c == "]") {
                c = double_close_span;
            }
            else {
              c = ""
            }
            addup = ""
            add = close_div + open_div + open_span;
        }
        out += c + add;
    }
    return out + close_span + close_div;
}
function line_to_mma_chords(line) {
    var chords = line.split(" ");
    if(chords.length == 2) {
        chords = [chords[0], "/", chords[1]];
    }
    return chords.join(" ");
}
var play_song_class_name = "play_song_not_ready";
var mmaWorker = new Worker("/yazgoo/mma.js/29e5bba60c48da982e587a6a798719568af68a6b/worker.js");
// preload mma by running it once with an empty file
mmaWorker.postMessage(["Groove Swing\n0 A7"]);
mooche_status("loading MMA...")
mmaWorker.onmessage = function(e) {
  var data = e.data;
  mooche_status("loading MMA done")
  var play_song = document.getElementById("play_song");
  play_song_class_name = "play_song";
  document.getElementById("stop").value = "■"
  var t1 = performance.now();
  console.log("playing a song took " + (t1 - t0) + " milliseconds.")
  if(play_song != null && play_song.className == "play_song_not_ready")
  {
    play_song.className = play_song_class_name;
  }
  if(data == undefined) {
    mooche_status("MMA conversion failed");
  }
  else {
    mooche_status("playing song...");
    play(data);
  }
}
function play_mma(mma) {
  mmaWorker.postMessage([mma]);
}
function to_mma(unwarbled) {
    unwarbled = "?Groove Swing\n" + unwarbled.replace(/T../, '')/* todo actually use this tempo stuff */
        .replace(/\{/g, "\n?Repeat\n").replace(/} +/, "\n?RepeatEnding\n")
        .replace(/}/g, "\n?RepeatEnd\n")
        .replace(/\*./g, "").replace(/N1/g, "\n?RepeatEnding\n").replace(/\]\[/g, "?RepeatEnd\n")
        .replace(/<.*>/, "")
        .replace("[", "\n")
        .replace(/N2/g, "\n?RepeatEnding\n").replace("Z", "").replace(/s/g, " ").replace(/,/g, " ")
        .replace(/-/g, "m").replace(/\^/g, "M").replace(/h/g, "").replace(/o7/g, "m7b5").replace(/alt/g, "#5b7b9b13")/*temporary alt replacement*/
        .replace(/\|/g, "\n").replace(/\]\[/g, "\n").replace(/\[/, "\n")
        .replace(/l/g, "\n").replace(/x/g, "").replace(/\([^\)]*\)/g, "")/* lets ignore stuff under () for now*/
    splitted = unwarbled.split("\n");
    var previous = "";
    k = 0;
    for(var i = 0; i < splitted.length; i++) {
        var line = splitted[i];
        if(line.length == 0 || line[0] == '?') previous += line.replace(/\?/g, "")
        else {
            previous += "" + k + " " + line_to_mma_chords(line);
            k += 1;
        }
        previous += "\n";
    }
    return previous
}
function to_mma_opal(unwarbled) {
  return Opal.MMAParser.$new(unwarbled).$run();
}
function play_song(unwarbled) {
  var previous = to_mma_opal(unwarbled)
  play_mma(previous);
}
function get_song(songname, f, error_handler) {
  var openRequest = indexedDB.open("mooche",2);
  openRequest.onupgradeneeded = function(e) {
    var thisDB = e.target.result;
    if(!thisDB.objectStoreNames.contains("songs")) {
      thisDB.createObjectStore("songs", {keyPath: "key"});
    }
  }
  openRequest.onsuccess = function(e) {
    db = e.target.result;
    var transaction = db.transaction(["songs"], "readonly");
    var objectStore = transaction.objectStore("songs");
    var request = objectStore.get(songname);
    request.onsuccess = function(e) {
      f(e.target.result.content);
    }
    request.onerror = function(e) {
      error_handler(e);
    }
  }
  openRequest.onerror = function(e) {
    error_handler(e);
  }
}
function save_song(songname, song) {
  var openRequest = indexedDB.open("mooche",2);
  openRequest.onupgradeneeded = function(e) {
    var thisDB = e.target.result;
    if(!thisDB.objectStoreNames.contains("songs")) {
      thisDB.createObjectStore("songs", {keyPath: "key"});
    }
  }
	openRequest.onsuccess = function(e) {
    db = e.target.result;
		var transaction = db.transaction(["songs"],"readwrite");
		var store = transaction.objectStore("songs");
    store.put({key: songname, content: song})
  }
}
function show_song(songname, error_handler) {
  get_song(songname, function(song) {
    save_song("last_song", song)
    var splitted = song.split("=");
    var title = splitted[0];
    var author = splitted[1].split(" ").reverse().join(" ");
    var unwarbled = unwarble(splitted[6]);
    set_content(
        "<input type=button id=play_song class="+play_song_class_name
        + " value='▶' onclick=\"play_song('"+unwarbled+"')\"/>"
				+ ""+title+""
        + ""+author+"

"
        + get_sheet(unwarbled));
  }, error_handler);
}
var songs_list_written;
var songs_list_div;
function show_songs_list(div) {
  songs_list_div = div;
  mooche_status("showing songs...");
  var openRequest = indexedDB.open("mooche",2);
  openRequest.onupgradeneeded = function(e) {
    var thisDB = e.target.result;
    if(!thisDB.objectStoreNames.contains("songs")) {
      thisDB.createObjectStore("songs", {keyPath: "key"});
    }
  }
  openRequest.onsuccess = function(e) {
    db = e.target.result;
    var transaction = db.transaction(["songs"],"readonly");
    var store = transaction.objectStore("songs");
    var cursor = store.openCursor();
    var s = ""
    var i = 0;
    songs_list_div.innerHTML = ""
    cursor.onsuccess = function(e) {
      var res = e.target.result;
      if(res) {
        s += "
" + res.key  + "
";
        i += 1;
        if(i > 100) {
          songs_list_div.innerHTML += s;
          s = "";
          i = 0;
        }
        res.continue();
      } else {
          songs_list_div.innerHTML += s;
      }
    }
  }
}
function set_content(str) {
    var content = document.getElementById("content");
    content.innerHTML = str;
}
function show_imports() {
    set_content("
Right click and copy link location on song links below,"
        + "then paste it in this text field below
"
        + "<textarea type=text class=import onchange='load_songs(this)'></textarea>"
        + "");
}
function show_about() {
    set_content('Mooche is free software (as in freedom).
'
            +'This means it guarantees 4 fundamentals rights:
'
            +'
'
            +'
Freedom 0: The freedom to run the program for any purpose.
'
            +'
Freedom 1: The freedom to study how the program works, and change it to make it do what you wish.
'
            +'
Freedom 2: The freedom to redistribute and make copies so you can help your neighbor.
'
            +'
Freedom 3: The freedom to improve the program, and release your improvements (and modified versions in general) to the public, so that the whole community benefits.
'
            +'
'
            + "source available here.")
}
function show_songs() {
    show_songs_list(document.getElementById('content'));
}
function show_songs_or_last_song() {
  show_song("last_song", show_songs);
}

<|endoftext|>