<commit_before>/** @format */
import statemachine from "@/statemachine"
import * as treeUtil from "./util"

export const corpusChooserComponent = {
    template: `

                {{ $ctrl.selectCount }}
                {{ 'corpselector_of' | loc:$root.lang }}
                {{ $ctrl.totalCount }}
                {{'corpselector_selectedmultiple' | loc:$root.lang }}

                {{ $ctrl.firstCorpus | locObj:$root.lang}}
                {{ 'corpselector_selectedone' | loc:$root.lang }}

                    — {{ $ctrl.suffixedNumbers($ctrl.selectedNumberOfTokens, $root.lang) }} {{ 'corpselector_of' | loc:$root.lang }} {{ $ctrl.suffixedNumbers($ctrl.totalNumberOfTokens, $root.lang) }} {{ 'corpselector_tokens' | loc:$root.lang }}

                    <cc-time-graph></cc-time-graph>

                        <button ng-click="$ctrl.selectAll()" class="btn btn-default btn-sm w-full mb-2">

                            {{'corpselector_buttonselectall' | loc:$root.lang }}
                        </button>
                        <button ng-click="$ctrl.selectNone()" class="btn btn-default btn-sm w-full">

                            {{ 'corpselector_buttonselectnone' | loc:$root.lang }}
                        </button>

                <cc-tree node="$ctrl.root" on-select="$ctrl.onSelect()" on-select-only="$ctrl.selectOnly(corporaIds)" on-show-info="$ctrl.onShowInfo(node)"></cc-tree>

                    {{ $ctrl.selectedNumberOfSentences | prettyNumber }} {{'corpselector_sentences_long' | loc:$root.lang}}

            <cc-info-box ng-if="$ctrl.showInfoBox" class="sticky top-0" style="width: 480px" object="$ctrl.infoNode"></cc-info>

    `,
    bindings: {},
    controller: [
        "$rootScope",
        "$location",
        function ($rootScope, $location) {
            let $ctrl = this

            statemachine.listen("login", function () {
                $ctrl.credentials = authenticationProxy.loginObj.credentials
                // recalculate folder status and repaint it all
                $ctrl.updateLimitedAccess()
            })

            statemachine.listen("logout", function () {
                $ctrl.credentials = []
                let newCorpora = []
                for (let corpus of settings.corpusListing.getSelectedCorpora()) {
                    if (!settings.corpora[corpus]["limited_access"]) {
                        newCorpora.push(corpus)
                    } else {
                        settings.corpora[corpus].selected = false
                    }
                }

                if (_.isEmpty(newCorpora)) {
                    newCorpora = settings["preselected_corpora"]
                }
                settings.corpusListing.select(newCorpora)
                $ctrl.updateSelectedCount(newCorpora)
                $ctrl.updateLimitedAccess()
            })

            $ctrl.initialized = false
            $ctrl.showChooser = false

            $ctrl.onShowChooser = () => {
                // don't open the chooser unless the info-call is done
                if ($ctrl.initialized) {
                    $ctrl.showChooser = !$ctrl.showChooser
                }
            }

            // should be ON INFO-call done from statemachine
            $rootScope.$on("corpuschooserchange", (e, corpusIds) => {
                $ctrl.credentials = authenticationProxy.loginObj.credentials || []

                // change of corpora from outside the chooser
                // happens on initialzation when corpora is either decided by
                // settings.preselectedCorpora / URL query param
                if ($ctrl.initialized) {
                    return
                }

                $ctrl.initialized = true

                // remove the corpora with hide=true (linked corpora)
                const ccCorpora = Object.keys(settings.corpora).reduce((prev, current) => {
                    if (!settings.corpora[current].hide) {
                        prev[current] = settings.corpora[current]
                    }
                    return prev
                }, {})

                $ctrl.root = treeUtil.initCorpusStructure(ccCorpora, corpusIds)

                $ctrl.totalCount = Object.values(ccCorpora).length
                $ctrl.totalNumberOfTokens = $ctrl.root.tokens
                $ctrl.updateLimitedAccess()
                select(corpusIds)
            })

            $ctrl.updateSelectedCount = (selection) => {
                $ctrl.selectCount = selection.length
                $ctrl.selectedNumberOfTokens = 0
                $ctrl.selectedNumberOfSentences = 0
                for (const corpusId of selection) {
                    const corpus = settings.corpora[corpusId]
                    $ctrl.selectedNumberOfTokens += corpus.tokens
                    $ctrl.selectedNumberOfSentences += corpus.sentences
                }
            }

            $ctrl.suffixedNumbers = (num, lang) => {
                let out = ""
                if (num < 1000) {
                    // 232
                    out = num.toString()
                } else if (num >= 1000 && num < 1e6) {
                    // 232,21K
                    out = (num / 1000).toFixed(2).toString() + "K"
                } else if (num >= 1e6 && num < 1e9) {
                    // 232,21M
                    out = (num / 1e6).toFixed(2).toString() + "M"
                } else if (num >= 1e9 && num < 1e12) {
                    // 232,21G
                    out = (num / 1e9).toFixed(2).toString() + "G"
                } else if (num >= 1e12) {
                    // 232,21T
                    out = (num / 1e12).toFixed(2).toString() + "T"
                }
                return out.replace(".", util.getLocaleString("util_decimalseparator", lang))
            }

            $ctrl.onSelect = function () {
                const currentCorpora = treeUtil.getAllSelected($ctrl.root)
                select(currentCorpora)
            }

            $ctrl.selectAll = function () {
                select(_.map(Object.values(settings.corpora), (corpus) => corpus.id))
            }

            $ctrl.selectNone = function () {
                select([])
            }

            $ctrl.selectOnly = function (corporaIds) {
                select(corporaIds)
            }

            $ctrl.updateLimitedAccess = function () {
                treeUtil.updateLimitedAccess($ctrl.root, $ctrl.credentials)
            }

            function select(corporaIds) {
                const selection = treeUtil.filterCorporaOnCredentials(settings.corpora, corporaIds, $ctrl.credentials)
                treeUtil.recalcFolderStatus($ctrl.root)
                settings.corpusListing.select(selection)
                $ctrl.updateSelectedCount(selection)
                $rootScope.$broadcast("corpuschooserchange", selection)
                $location.search("corpus", selection.join(","))

                // used when there is only one corpus selected to show name
                // TODO this needs to be refactored to support titles in different languages
                if (selection.length == 1) {
                    const firstCorpus = settings.corpora[selection[0]].title
                    $ctrl.firstCorpus = firstCorpus.length > 39 ? firstCorpus.slice(0, 36) + "…" : firstCorpus
                }
            }

            $ctrl.onShowInfo = (node) => {
                $ctrl.showInfoBox = node.id != $ctrl.infoNode?.id
                $ctrl.infoNode = $ctrl.showInfoBox ? node : null
            }
        },
    ],
}
<commit_msg>fix corpus chooser background click<commit_after>/** @format */
import statemachine from "@/statemachine"
import * as treeUtil from "./util"

export const corpusChooserComponent = {
    template: `

                {{ $ctrl.selectCount }}
                {{ 'corpselector_of' | loc:$root.lang }}
                {{ $ctrl.totalCount }}
                {{'corpselector_selectedmultiple' | loc:$root.lang }}

                {{ $ctrl.firstCorpus | locObj:$root.lang}}
                {{ 'corpselector_selectedone' | loc:$root.lang }}

                    — {{ $ctrl.suffixedNumbers($ctrl.selectedNumberOfTokens, $root.lang) }} {{ 'corpselector_of' | loc:$root.lang }} {{ $ctrl.suffixedNumbers($ctrl.totalNumberOfTokens, $root.lang) }} {{ 'corpselector_tokens' | loc:$root.lang }}

                    <cc-time-graph></cc-time-graph>

                        <button ng-click="$ctrl.selectAll()" class="btn btn-default btn-sm w-full mb-2">

                            {{'corpselector_buttonselectall' | loc:$root.lang }}
                        </button>
                        <button ng-click="$ctrl.selectNone()" class="btn btn-default btn-sm w-full">

                            {{ 'corpselector_buttonselectnone' | loc:$root.lang }}
                        </button>

                <cc-tree node="$ctrl.root" on-select="$ctrl.onSelect()" on-select-only="$ctrl.selectOnly(corporaIds)" on-show-info="$ctrl.onShowInfo(node)"></cc-tree>

                    {{ $ctrl.selectedNumberOfSentences | prettyNumber }} {{'corpselector_sentences_long' | loc:$root.lang}}

            <cc-info-box ng-if="$ctrl.showInfoBox" class="sticky top-0" style="width: 480px" object="$ctrl.infoNode"></cc-info>

    `,
    bindings: {},
    controller: [
        "$rootScope",
        "$location",
        function ($rootScope, $location) {
            let $ctrl = this

            statemachine.listen("login", function () {
                $ctrl.credentials = authenticationProxy.loginObj.credentials
                // recalculate folder status and repaint it all
                $ctrl.updateLimitedAccess()
            })

            statemachine.listen("logout", function () {
                $ctrl.credentials = []
                let newCorpora = []
                for (let corpus of settings.corpusListing.getSelectedCorpora()) {
                    if (!settings.corpora[corpus]["limited_access"]) {
                        newCorpora.push(corpus)
                    } else {
                        settings.corpora[corpus].selected = false
                    }
                }

                if (_.isEmpty(newCorpora)) {
                    newCorpora = settings["preselected_corpora"]
                }
                settings.corpusListing.select(newCorpora)
                $ctrl.updateSelectedCount(newCorpora)
                $ctrl.updateLimitedAccess()
            })

            $ctrl.initialized = false
            $ctrl.showChooser = false

            $ctrl.onShowChooser = () => {
                // don't open the chooser unless the info-call is done
                if ($ctrl.initialized) {
                    $ctrl.showChooser = !$ctrl.showChooser
                }
            }

            // should be ON INFO-call done from statemachine
            $rootScope.$on("corpuschooserchange", (e, corpusIds) => {
                $ctrl.credentials = authenticationProxy.loginObj.credentials || []

                // change of corpora from outside the chooser
                // happens on initialzation when corpora is either decided by
                // settings.preselectedCorpora / URL query param
                if ($ctrl.initialized) {
                    return
                }

                $ctrl.initialized = true

                // remove the corpora with hide=true (linked corpora)
                const ccCorpora = Object.keys(settings.corpora).reduce((prev, current) => {
                    if (!settings.corpora[current].hide) {
                        prev[current] = settings.corpora[current]
                    }
                    return prev
                }, {})

                $ctrl.root = treeUtil.initCorpusStructure(ccCorpora, corpusIds)

                $ctrl.totalCount = Object.values(ccCorpora).length
                $ctrl.totalNumberOfTokens = $ctrl.root.tokens
                $ctrl.updateLimitedAccess()
                select(corpusIds)
            })

            $ctrl.updateSelectedCount = (selection) => {
                $ctrl.selectCount = selection.length
                $ctrl.selectedNumberOfTokens = 0
                $ctrl.selectedNumberOfSentences = 0
                for (const corpusId of selection) {
                    const corpus = settings.corpora[corpusId]
                    $ctrl.selectedNumberOfTokens += corpus.tokens
                    $ctrl.selectedNumberOfSentences += corpus.sentences
                }
            }

            $ctrl.suffixedNumbers = (num, lang) => {
                let out = ""
                if (num < 1000) {
                    // 232
                    out = num.toString()
                } else if (num >= 1000 && num < 1e6) {
                    // 232,21K
                    out = (num / 1000).toFixed(2).toString() + "K"
                } else if (num >= 1e6 && num < 1e9) {
                    // 232,21M
                    out = (num / 1e6).toFixed(2).toString() + "M"
                } else if (num >= 1e9 && num < 1e12) {
                    // 232,21G
                    out = (num / 1e9).toFixed(2).toString() + "G"
                } else if (num >= 1e12) {
                    // 232,21T
                    out = (num / 1e12).toFixed(2).toString() + "T"
                }
                return out.replace(".", util.getLocaleString("util_decimalseparator", lang))
            }

            $ctrl.onSelect = function () {
                const currentCorpora = treeUtil.getAllSelected($ctrl.root)
                select(currentCorpora)
            }

            $ctrl.selectAll = function () {
                select(_.map(Object.values(settings.corpora), (corpus) => corpus.id))
            }

            $ctrl.selectNone = function () {
                select([])
            }

            $ctrl.selectOnly = function (corporaIds) {
                select(corporaIds)
            }

            $ctrl.updateLimitedAccess = function () {
                treeUtil.updateLimitedAccess($ctrl.root, $ctrl.credentials)
            }

            function select(corporaIds) {
                const selection = treeUtil.filterCorporaOnCredentials(settings.corpora, corporaIds, $ctrl.credentials)
                treeUtil.recalcFolderStatus($ctrl.root)
                settings.corpusListing.select(selection)
                $ctrl.updateSelectedCount(selection)
                $rootScope.$broadcast("corpuschooserchange", selection)
                $location.search("corpus", selection.join(","))

                // used when there is only one corpus selected to show name
                // TODO this needs to be refactored to support titles in different languages
                if (selection.length == 1) {
                    const firstCorpus = settings.corpora[selection[0]].title
                    $ctrl.firstCorpus = firstCorpus.length > 39 ? firstCorpus.slice(0, 36) + "…" : firstCorpus
                }
            }

            $ctrl.onShowInfo = (node) => {
                $ctrl.showInfoBox = node.id != $ctrl.infoNode?.id
                $ctrl.infoNode = $ctrl.showInfoBox ? node : null
            }
        },
    ],
}
<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return Math.floor(Math.random()*(max-min+1)+min);
}

function commit(t_offset, outFD, outFile, data, counter, length)
{
  if (counter < length)
  {
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    if (counter + step >= length) step = length - counter
    process.stdout.write("\033[2K Writing " + counter + "/" + length + " bytes: " + message + "\r");
    fs.writeSync(outFD, data.slice(counter, counter+step), 0, step)
    child_process.execFileSync('/Applications/Xcode.app/Contents/Developer/usr/bin/git', args)
    var timeout = randomIntFromInterval(0, max_sleep)
    counter = counte<commit_msg>Fixing punctuation<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
   return Math.floor(Math.random()*(max-min+1)+min);
}

function commit(t_offset, outFD, outFile, data, counter, length)
{
  if (counter < length)
  {
    var message = commit_messages[randomIntFromInterval(0, commit_messages.length - 1)]
    var args = ['commit', outFile, '-m', message]
    if (counter + step >= length) step = length - counter
    process.stdout.write("\033[2K Writing " + counter + "/" + length + " bytes: " + message + "\r");
    fs.writeSync(outFD, data.slice(counter, counter+step), 0, step)
    child_process.execFileSync('/Applications/Xcode.app/Contents/Developer/usr/bin/git', args)
    var timeout = randomIntFromInterval(0, max_sleep)
    counter = counter<|endoftext|>


<commit_before>L.Angkot.Route = L.LayerGroup.extend({
  options: {
    editable: false,
  },

  includes: L.Mixin.Events,

  initialize: function(layers, options) {
    L.LayerGroup.prototype.initialize.call(this, layers);
    L.Util.setOptions(this, options);

    this._polylines = [];
    this._active = null;
    this._guide = new L.Polyline.Color([], {
      color: 'blue',
      weight: 2,
      opacity: 0.5,
    });
    this._shiftKey = false;

    this._tooltip = new L.Tooltip();
    this._distance = 0;
  },

  onAdd: function(map) {
    L.LayerGroup.prototype.onAdd.apply(this, arguments);

    if (this.options.editable) {
      this._setupEvents();
      this._guide.addTo(map);
    }

    this._tooltip.addTo(map);
  },

  onRemove: function(map) {
    map.removeLayer(this._tooltip);
    L.LayerGroup.prototype.onRemove.apply(this, arguments);
  },

  setEditable: function(editable) {
    this.options.editable = editable;
    if (editable) this._setupEvents();
    else this._removeEvents();

    // FIXME restructure
    if (this._map) {
      if (editable) this._guide.addTo(this._map);
      else this._map.removeLayer(this._guide);
    }
  },

  getRoutes: function() {
    var routes = [];
    for (var i=0; i<this._polylines.length; i++) {
      routes.push(this._polylines[i].getLatLngs());
    }
    return routes;
  },

  setRoutes: function(routes) {
    this.clear();
    for (var i=0; i<routes.length; i++) {
      var route = routes[i];
      var p = this._addPolyline({color:'red'});
      p.addLatLngs(route);
    }
  },

  clear: function() {
    while (this._polylines.length > 0) {
      this._removePolyline(this._polylines[0]);
    }
  },

  _setupEvents: function() {
    if (!this._map) return;

    this._map.on('click', this._onMapClick, this);
    this._map.on('mousemove', this._onMapMouseMove, this);
    this._map.on('mouseover', this._onMapMouseOver, this);
    this._map.on('mouseout', this._onMapMouseOut, this);

    L.DomEvent.addListener(document, 'keydown', function(e) {
      this._shiftKey = e.shiftKey;
    }, this);
    L.DomEvent.addListener(document, 'keyup', function(e) {
      this._shiftKey = e.shiftKey;
    }, this);
  },

  _removeEvents: function() {
    if (!this._map) return;

    this._map.off('click', this._onMapClick, this);
    this._map.off('mouseout', this._onMapMouseOut, this);
    this._map.off('mousemove', this._onMapMouseMove, this);
    this._map.off('mouseover', this._onMapMouseOver, this);
  },

  _onMapClick: function(e) {
    if (this._active) {
      this._addNextPoint(e);
    }
    else {
      this._startRoute(e);
    }
  },

  _startRoute: function(e) {
    var p = this._addPolyline({color:'blue'});
    p.addLatLng(e.latlng);
    this._active = p;

    this._guide.spliceLatLngs(0, this._guide._latlngs.length);
    this._guide.addLatLng(e.latlng);
    this._guide.addLatLng(e.latlng);

    this._distance = 0;
    this._drawMode = 'new';

    if (this._polylines.length == 1) {
      this._tooltip.setContent('Lanjutkan dengan mengklik titik-titik di sepanjang rute');
    }
  },

  _addNextPoint: function(e) {
    this._active.addLatLng(e.latlng);
    this._guide.spliceLatLngs(0, 2, e.latlng, e.latlng);

    if (this._active._latlngs.length > 1) {
      var last = this._active._latlngs.length-1;
      this._distance += this._active._latlngs[last-1].distanceTo(this._active._latlngs[last]);
    }

    if (this._polylines.length == 1) {
      var len = this._polylines[0]._latlngs.length;
      if (len == 2) {
        this._tooltip.setContent('Klik titik terakhir untuk mengakhiri');
      }
      else if (len == 3) {
        this._tooltip.setContent(null);
      }
    }
  },

  _onMapMouseOver: function(e) {
    if (this._polylines.length == 0) {
      this._tooltip.setContent('Klik untuk membuat rute');
    }
  },

  _onMapMouseOut: function(e) {
    this._tooltip.clear();
  },

  _onMapMouseMove: function(e) {
    if (this._active) {
      this._guide.spliceLatLngs(1, 1, e.latlng);

      var last = this._active._latlngs.length-1;
      var distance = this._active._latlngs[last].distanceTo(e.latlng);
      distance += this._distance;
      this._showDistance(distance);
    }

    this._tooltip.setLatLng(e.latlng);
  },

  _showDistance: function(distance) {
    var text = (Math.round(distance/1000*100)/100) + ' km';
    if (distance < 1500) text = (Math.round(distance*100)/100) + ' m';
    this._tooltip.setTitle(text);
  },

  _createPolyline: function(options) {
    var opts = {
      editable: this.options.editable,
      color: 'red',
      weight: 3,
      opacity: 0.8,
    };
    for (k in options) {
      opts[k] = options[k];
    }

    var p = new L.Polyline.Editable([], opts);
    return p;
  },

  _addPolyline: function(options) {
    var p = this._createPolyline(options);
    p.addTo(this._map);
    p.on('handle:click', this._onHandleClick, this);
    p.on('handle:mouseover', this._onHandleMouseOver, this);
    p.on('handle:mouseout', this._onHandleMouseOut, this);
    p.on('handle:dragend', this._onHandleDragEnd, this);
    this._polylines.push(p);
    return p;
  },

  _removePolyline: function(p) {
    var index = this._polylines.indexOf(p);
    if (index >= 0) this._polylines.splice(index, 1);

    p.off('handle:mouseover', this._onHandleMouseOver, this);
    p.off('handle:mouseout', this._onHandleMouseOut, this);
    p.off('handle:click', this._onHandleClick, this);
    p.off('handle:dragend', this._onHandleDragEnd, this);
    if (this._map) this._map.removeLayer(p);
  },

  _stopDrawing: function() {
    var index = this._polylines.indexOf(this._active);

    this._active.setColor('red');
    this._active = null;
    this._guide.spliceLatLngs(0, this._guide._latlngs.length);

    this._distance = 0;

    this._tooltip.clear();

    if (index >= 0) {
      if (this._drawMode == 'new') {
        this.fire('route:add', {index:index});
      }
      else if (this._drawMode == 'continue') {
        this.fire('route:update', {index:index});
      }
    }

    this._drawMode = null;
  },

  _continueRoute: function(e) {
    var p = e.target;
    if (e.vertex === 0) {
      p.reverseLatLngs();
    }
    this._active = p;
    this._active.setColor('blue');
    this._guide.addLatLng(e.latlng);
    this._guide.addLatLng(e.latlng);

    var latlngs = this._active._latlngs;
    var distance = 0;
    for (var i=1; i<latlngs.length; i++) {
      distance += latlngs[i-1].distanceTo(latlngs[i]);
    }
    this._distance = distance;

    this._drawMode = 'continue';

    this._showDistance(distance);
    this._tooltip.setContent(null);
  },

  _mergeRoute: function(e) {
    var p = e.target;
    if (e.vertex !== 0) {
      p.reverseLatLngs();
    }
    this._active.addLatLngs(p._latlngs);

    var index = this._polylines.indexOf(p);
    this.fire('route:delete', {index:index});

    this._removePolyline(p);
  },

  _removeVertex: function(e) {
    var p = e.target;
    p.spliceLatLngs(e.vertex, 1);

    var index = this._polylines.indexOf(p);

    if (p._latlngs.length === 1) {
      this._removePolyline(p);
      this.fire('route:delete', {index:index});
    }
    else {
      this.fire('route:update', {index:index});
    }
  },

  _onHandleMouseOver: function(e) {
    var p = e.target;
    var length = p._latlngs.length;
    var head = e.vertex === 0;
    var tail = e.vertex === length - 1;
    var tip = head || tail;
    var onVertex = e.vertex !== undefined;

    if (!this._active) {
      if (tip) {
        this._tooltip.setContent('Klik untuk melanjutkan rute');
      }
      else if (onVertex) {
        this._tooltip.setContent('Untuk menghapus titik, tahan tombol shift lalu klik titik yang mau dihapus');
      }
    }
    else if (p !== this._active) {
      if (tip) {
        this._tooltip.setContent('Untuk menggabung rute, tahan tombol shift lalu klik titik tujuan');
      }
    }
  },

  _onHandleMouseOut: function(e) {
    if (!this._active || this._polylines.length > 1) {
      this._tooltip.setContent(null);
    }
  },

  _onHandleClick: function(e) {
    var p = e.target;
    var length = p._latlngs.length;
    var head = e.vertex === 0;
    var tail = e.vertex === length - 1;
    var tip = head || tail;

    if (e.target == this._active) {
      if (tail) {
        if (length === 1) {
          this._removePolyline(p);
        }
        this._stopDrawing();
      }
      else {
        this._addNextPoint(e);
      }
    }
    else if (!this._active && this._shiftKey && e.vertex !== undefined) {
      this._removeVertex(e);
    }
    else if (tip) {
      if (!this._active) {
        this._continueRoute(e);
      }
      else if (this._active && this._shiftKey) {
        this._mergeRoute(e);
        this._stopDrawing();
      }
      else if (this._active) {
        this._addNextPoint(e);
      }
    }
    else if (!this._active) {
      this._startRoute(e);
    }
    else {
      this._addNextPoint(e);
    }
  },

  _onHandleDragEnd: function(e) {
    var p = e.target;
    if (p == this._active) return;
    var index = this._polylines.indexOf(p);
    this.fire('route:update', {index:index});
  },

});

<commit_msg>Avoid duplicate event setups<commit_after>L.Angkot.Route = L.LayerGroup.extend({
  options: {
    editable: false,
  },

  includes: L.Mixin.Events,

  initialize: function(layers, options) {
    L.LayerGroup.prototype.initialize.call(this, layers);
    L.Util.setOptions(this, options);

    this._polylines = [];
    this._active = null;
    this._guide = new L.Polyline.Color([], {
      color: 'blue',
      weight: 2,
      opacity: 0.5,
    });
    this._shiftKey = false;

    this._tooltip = new L.Tooltip();
    this._distance = 0;
  },

  onAdd: function(map) {
    L.LayerGroup.prototype.onAdd.apply(this, arguments);

    if (this.options.editable) {
      this._removeEvents();
      this._setupEvents();
      this._guide.addTo(map);
    }

    this._tooltip.addTo(map);
  },

  onRemove: function(map) {
    map.removeLayer(this._tooltip);
    L.LayerGroup.prototype.onRemove.apply(this, arguments);
  },

  setEditable: function(editable) {
    this.options.editable = editable;
    this._removeEvents();
    if (editable) this._setupEvents();

    // FIXME restructure
    if (this._map) {
      if (editable) this._guide.addTo(this._map);
      else this._map.removeLayer(this._guide);
    }
  },

  getRoutes: function() {
    var routes = [];
    for (var i=0; i<this._polylines.length; i++) {
      routes.push(this._polylines[i].getLatLngs());
    }
    return routes;
  },

  setRoutes: function(routes) {
    this.clear();
    for (var i=0; i<routes.length; i++) {
      var route = routes[i];
      var p = this._addPolyline({color:'red'});
      p.addLatLngs(route);
    }
  },

  clear: function() {
    while (this._polylines.length > 0) {
      this._removePolyline(this._polylines[0]);
    }
  },

  _setupEvents: function() {
    if (!this._map) return;

    this._map.on('click', this._onMapClick, this);
    this._map.on('mousemove', this._onMapMouseMove, this);
    this._map.on('mouseover', this._onMapMouseOver, this);
    this._map.on('mouseout', this._onMapMouseOut, this);

    L.DomEvent.addListener(document, 'keydown', this._onKeyEvent, this);
    L.DomEvent.addListener(document, 'keyup', this._onKeyEvent, this);
  },

  _removeEvents: function() {
    if (!this._map) return;

    this._map.off('click', this._onMapClick, this);
    this._map.off('mouseout', this._onMapMouseOut, this);
    this._map.off('mousemove', this._onMapMouseMove, this);
    this._map.off('mouseover', this._onMapMouseOver, this);

    L.DomEvent.removeListener(document, 'keydown', this._onKeyEvent, this);
    L.DomEvent.removeListener(document, 'keyup', this._onKeyEvent, this);
  },

  _onKeyEvent: function(e) {
    this._shiftKey = e.shiftKey;
  },

  _onMapClick: function(e) {
    if (this._active) {
      this._addNextPoint(e);
    }
    else {
      this._startRoute(e);
    }
  },

  _startRoute: function(e) {
    var p = this._addPolyline({color:'blue'});
    p.addLatLng(e.latlng);
    this._active = p;

    this._guide.spliceLatLngs(0, this._guide._latlngs.length);
    this._guide.addLatLng(e.latlng);
    this._guide.addLatLng(e.latlng);

    this._distance = 0;
    this._drawMode = 'new';

    if (this._polylines.length == 1) {
      this._tooltip.setContent('Lanjutkan dengan mengklik titik-titik di sepanjang rute');
    }
  },

  _addNextPoint: function(e) {
    this._active.addLatLng(e.latlng);
    this._guide.spliceLatLngs(0, 2, e.latlng, e.latlng);

    if (this._active._latlngs.length > 1) {
      var last = this._active._latlngs.length-1;
      this._distance += this._active._latlngs[last-1].distanceTo(this._active._latlngs[last]);
    }

    if (this._polylines.length == 1) {
      var len = this._polylines[0]._latlngs.length;
      if (len == 2) {
        this._tooltip.setContent('Klik titik terakhir untuk mengakhiri');
      }
      else if (len == 3) {
        this._tooltip.setContent(null);
      }
    }
  },

  _onMapMouseOver: function(e) {
    if (this._polylines.length == 0) {
      this._tooltip.setContent('Klik untuk membuat rute');
    }
  },

  _onMapMouseOut: function(e) {
    this._tooltip.clear();
  },

  _onMapMouseMove: function(e) {
    if (this._active) {
      this._guide.spliceLatLngs(1, 1, e.latlng);

      var last = this._active._latlngs.length-1;
      var distance = this._active._latlngs[last].distanceTo(e.latlng);
      distance += this._distance;
      this._showDistance(distance);
    }

    this._tooltip.setLatLng(e.latlng);
  },

  _showDistance: function(distance) {
    var text = (Math.round(distance/1000*100)/100) + ' km';
    if (distance < 1500) text = (Math.round(distance*100)/100) + ' m';
    this._tooltip.setTitle(text);
  },

  _createPolyline: function(options) {
    var opts = {
      editable: this.options.editable,
      color: 'red',
      weight: 3,
      opacity: 0.8,
    };
    for (k in options) {
      opts[k] = options[k];
    }

    var p = new L.Polyline.Editable([], opts);
    return p;
  },

  _addPolyline: function(options) {
    var p = this._createPolyline(options);
    p.addTo(this._map);
    p.on('handle:click', this._onHandleClick, this);
    p.on('handle:mouseover', this._onHandleMouseOver, this);
    p.on('handle:mouseout', this._onHandleMouseOut, this);
    p.on('handle:dragend', this._onHandleDragEnd, this);
    this._polylines.push(p);
    return p;
  },

  _removePolyline: function(p) {
    var index = this._polylines.indexOf(p);
    if (index >= 0) this._polylines.splice(index, 1);

    p.off('handle:mouseover', this._onHandleMouseOver, this);
    p.off('handle:mouseout', this._onHandleMouseOut, this);
    p.off('handle:click', this._onHandleClick, this);
    p.off('handle:dragend', this._onHandleDragEnd, this);
    if (this._map) this._map.removeLayer(p);
  },

  _stopDrawing: function() {
    var index = this._polylines.indexOf(this._active);

    this._active.setColor('red');
    this._active = null;
    this._guide.spliceLatLngs(0, this._guide._latlngs.length);

    this._distance = 0;

    this._tooltip.clear();

    if (index >= 0) {
      if (this._drawMode == 'new') {
        this.fire('route:add', {index:index});
      }
      else if (this._drawMode == 'continue') {
        this.fire('route:update', {index:index});
      }
    }

    this._drawMode = null;
  },

  _continueRoute: function(e) {
    var p = e.target;
    if (e.vertex === 0) {
      p.reverseLatLngs();
    }
    this._active = p;
    this._active.setColor('blue');
    this._guide.addLatLng(e.latlng);
    this._guide.addLatLng(e.latlng);

    var latlngs = this._active._latlngs;
    var distance = 0;
    for (var i=1; i<latlngs.length; i++) {
      distance += latlngs[i-1].distanceTo(latlngs[i]);
    }
    this._distance = distance;

    this._drawMode = 'continue';

    this._showDistance(distance);
    this._tooltip.setContent(null);
  },

  _mergeRoute: function(e) {
    var p = e.target;
    if (e.vertex !== 0) {
      p.reverseLatLngs();
    }
    this._active.addLatLngs(p._latlngs);

    var index = this._polylines.indexOf(p);
    this.fire('route:delete', {index:index});

    this._removePolyline(p);
  },

  _removeVertex: function(e) {
    var p = e.target;
    p.spliceLatLngs(e.vertex, 1);

    var index = this._polylines.indexOf(p);

    if (p._latlngs.length === 1) {
      this._removePolyline(p);
      this.fire('route:delete', {index:index});
    }
    else {
      this.fire('route:update', {index:index});
    }
  },

  _onHandleMouseOver: function(e) {
    var p = e.target;
    var length = p._latlngs.length;
    var head = e.vertex === 0;
    var tail = e.vertex === length - 1;
    var tip = head || tail;
    var onVertex = e.vertex !== undefined;

    if (!this._active) {
      if (tip) {
        this._tooltip.setContent('Klik untuk melanjutkan rute');
      }
      else if (onVertex) {
        this._tooltip.setContent('Untuk menghapus titik, tahan tombol shift lalu klik titik yang mau dihapus');
      }
    }
    else if (p !== this._active) {
      if (tip) {
        this._tooltip.setContent('Untuk menggabung rute, tahan tombol shift lalu klik titik tujuan');
      }
    }
  },

  _onHandleMouseOut: function(e) {
    if (!this._active || this._polylines.length > 1) {
      this._tooltip.setContent(null);
    }
  },

  _onHandleClick: function(e) {
    var p = e.target;
    var length = p._latlngs.length;
    var head = e.vertex === 0;
    var tail = e.vertex === length - 1;
    var tip = head || tail;

    if (e.target == this._active) {
      if (tail) {
        if (length === 1) {
          this._removePolyline(p);
        }
        this._stopDrawing();
      }
      else {
        this._addNextPoint(e);
      }
    }
    else if (!this._active && this._shiftKey && e.vertex !== undefined) {
      this._removeVertex(e);
    }
    else if (tip) {
      if (!this._active) {
        this._continueRoute(e);
      }
      else if (this._active && this._shiftKey) {
        this._mergeRoute(e);
        this._stopDrawing();
      }
      else if (this._active) {
        this._addNextPoint(e);
      }
    }
    else if (!this._active) {
      this._startRoute(e);
    }
    else {
      this._addNextPoint(e);
    }
  },

  _onHandleDragEnd: function(e) {
    var p = e.target;
    if (p == this._active) return;
    var index = this._polylines.indexOf(p);
    this.fire('route:update', {index:index});
  },

});

<|endoftext|>


<commit_before>//http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
function shuffle(array, static) {
    if (!static) static = [];
    // console.log(array);
    var currentIndex = array.length
    var temporaryValue = 0
    var randomIndex = 0;
    var array = array.slice();

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

    // Pick a remaining element...
    if (static.indexOf(currentIndex) == -1) randomIndex = Math.floor(Math.random() * currentIndex);
    else randomIndex = currentIndex;
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
    }

    return array;
}

// Returns a random integer given the parameters:
//  if no params: returns [0, 1]
//  if r: returns [0, r]
//  if r, m: returns [r, m]
//  if r, m, s: returns [r, m] such that it is divisible by s
var randint = function (r, m, s) {
    if (s) {
        var max = m / s;
        var rand = Math.floor(Math.random()*(max-r+1))+r
        return rand*s

    } else if (m) {
        return Math.floor(Math.random()*(m-r+1))+r
    } else if (r) {
        return Math.floor(Math.random()*(r+1))
    } else {
        return Math.round(Math.random())
    }
}

// seconds
var retry_default = 30;
var forfeit_default = 4*60;
// [name, [[desc_num, level_num], ]]
var experiments = [

    ['gvgai_sokoban',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', 20, forfeit_default],
    ['gvgai_butterflies',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_aliens',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', 10*60, forfeit_default], // never gets shown
    ['gvgai_chase',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_frogs',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_missilecommand',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', retry_default, forfeit_default],
    ['gvgai_portals',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_zelda',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', retry_default, forfeit_default],
    ['gvgai_boulderdash',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', 45, 6*60],
    ['gvgai_survivezombies',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', 10*60, forfeit_default]
]
// var experiments = [

//     ['gvgai_sokoban',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_butterflies',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_aliens',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default], // never gets shown
//     ['gvgai_chase',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_frogs',
//         [[0, 0]], false,
//         '', retry_default, 3],
//     ['gvgai_missilecommand',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default],
//     ['gvgai_portals',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_zelda',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default],
//     ['gvgai_boulderdash',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default],
//     ['gvgai_survivezombies',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default]
// ]
//
// var experiments = experiments_normal.concat(experiments_hard);

var overtime_limit = 25*60*1000;

var get_exp = function () {
    return shuffle(experiments);
}

// console.log(get_exp());

// experiments = experiments.map(experiment => {
//     if (experiment[0] == boulder_dash[0]) {
//         return shuffle(getRandomSubarray(experiments_normal, 4).push(experiment));
//     } else if (experiments[0] == zombies[0]) {
//         return shuffle(getRandomSubarray(experiments_normal, 4)).push(experiment);
//     }
// })

// console.log(experiments);

// An object that updates what game its on
// by calling next
var Experiment = function (exp_name, cookie, randomize_exp=true, static_exps=[], randomize_color=true) {

    if (exp_name == undefined) {
        exp_name = 'exp0'
    }
    var experiment = {};

    experiment.cookie = cookie;
    experiment.expiration = 60*60*1000
    experiment.timeout = Date.now()+experiment.expiration;
    experiment.games_ordered = [];
    experiment.midpoints = {};

    var game_number = 0;

    var exp = get_exp();
    // console.log(exp);
    if (randomize_exp) {
        exp = shuffle(exp, static_exps);// [exp[0]].concat(shuffle(exp.slice(1, exp.length), static_exps));
    }
    exp.forEach(settings => {
        game_number ++;
        var game_name = settings[0];
        var game_levels = settings[1];
        experiment.midpoints[game_number] = settings[3];
        var retry_delay = settings[4];
        var forfeit_delay = settings[5];
        if (settings[2])
            game_levels = shuffle(game_levels);
        var color_scheme = 0;
        if (randomize_color) color_scheme = randint(1307674368000);
        game_levels.forEach(game_level => {
            experiment.games_ordered.push({name: game_name,
                             desc: game_level[0],
                             level: game_level[1],
                             number: game_number,
                             round: 1,
                             color_scheme: color_scheme,
                             retry_delay: retry_delay,
                             forfeit_delay: forfeit_delay,
                             time: 0})

        })
    })

    experiment.started = true;
    experiment.current_trial = 0;
    experiment.current_game_number = 1;
    experiment.max_trials = experiment.games_ordered.length;
    experiment.start_time = Date.now();
    experiment.init_time = Date.now();
    experiment.overtime_check = true;
    experiment.ended = false;
    experiment.continued = false;

    return experiment

}

Experiment.update_timeout = function (experiment) {
        experiment.timeout = Date.now()+experiment.expiration;
    }

Experiment.validate = function (experiment, validation_id) {
    return validation_id == experiment.cookie;
}

Experiment.started = function (experiment) {
    if (experiment.started) {
        experiment.started = false
        return true;
    }
    return false
}

Experiment.retry = function (experiment) {
    Experiment.update_timeout(experiment);
    var current_game = experiment.games_ordered[experiment.current_trial]
    // console.log(current_game);
    if (current_game) {
        current_game.round ++;
    }
    // console.log('retrying experiment', current_game[3])
}

Experiment.current_game = function (experiment) {
    Experiment.update_timeout(experiment);
    if (experiment.current_trial == experiment.max_trials)
        return false;
    var current_game = experiment.games_ordered[experiment.current_trial]
    var game_obj = {};
    game_obj.name = current_game.name;
    game_obj.desc = current_game.desc;
    game_obj.level = current_game.level;
    game_obj.number = current_game.number;
    game_obj.color_scheme = current_game.color_scheme;
    game_obj.retry_delay = current_game.retry_delay;
    game_obj.forfeit_delay = current_game.forfeit_delay;
    game_obj.time = Date.now() - experiment.start_time;
    game_obj.round = current_game.round;
    // console.log(current_game)
    // console.log(game_obj)
    return game_obj;
}

Experiment.remaining_games = function (experiment) {
    return experiments.length - experiment.current_game_number;
}

Experiment.midpoint_text = function (experiment) {
    experiment.init_time = Date.now();
    experiment.current_game_number = experiment.games_ordered[experiment.current_trial].number;
    return experiment.midpoints[experiment.current_game_number];
}

Experiment.current_round = function (experiment) {
    return {
        number: experiment.games_ordered[experiment.current_trial].round
    };
}

Experiment.mid_point_pure = function (experiment) {
    if (experiment.current_game_number == experiment.games_ordered[experiment.current_trial].number)
        return false;
    return true;
}

Experiment.mid_point = function (experiment) {
    if (Experiment.mid_point_pure(experiment)) {
        experiment.current_game_number ++;
        return true
    }
    return false;
}

Experiment.next = function (experiment) {
    Experiment.update_timeout(experiment);
    experiment.current_trial += 1;
}

Experiment.is_done = function  (experiment) {
    if (experiment.current_trial >= experiment.games_ordered.length || experiment.ended) {
        return true;
    }
    return false;
}

Experiment.get_data = function (experiment) {
    var data = experiment.games_ordered[experiment.current_trial];
    data.time = Date.now() - experiment.init_time;
    return experiment.games_ordered[experiment.current_trial];
}

Experiment.forfeit = function (experiment) {
    experiment.current_game_number ++;
    // current_trial --;
}

Experiment.end = function (experiment) {
    experiment.ended = true;
}

Experiment.overtime = function (experiment) {
    if (Date.now() - experiment.start_time > experiment.overtime_limit) {
        if (experiment.overtime_check) {
            experiment.overtime_check = false;
            return true
        } else {
            experiment.continued = true;
        }
    }
    return false;
}

Experiment.overtime_continued = function (experiment) {
    if (Experiment.mid_point_pure(experiment) && experiment.continued) {
        experiment.continued = false;
        return !experiment.overtime_check;
    }
    return false;
}

Experiment.timeout = function (experiment) {
    if (Date.now() > experiment.timeout)
        return true;
    return false
}

Experiment.experiments = experiments;

module.exports = Experiment;<commit_msg>okay, now everything is working<commit_after>//http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
function shuffle(array, static) {
    if (!static) static = [];
    // console.log(array);
    var currentIndex = array.length
    var temporaryValue = 0
    var randomIndex = 0;
    var array = array.slice();

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

    // Pick a remaining element...
    if (static.indexOf(currentIndex) == -1) randomIndex = Math.floor(Math.random() * currentIndex);
    else randomIndex = currentIndex;
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
    }

    return array;
}

// Returns a random integer given the parameters:
//  if no params: returns [0, 1]
//  if r: returns [0, r]
//  if r, m: returns [r, m]
//  if r, m, s: returns [r, m] such that it is divisible by s
var randint = function (r, m, s) {
    if (s) {
        var max = m / s;
        var rand = Math.floor(Math.random()*(max-r+1))+r
        return rand*s

    } else if (m) {
        return Math.floor(Math.random()*(m-r+1))+r
    } else if (r) {
        return Math.floor(Math.random()*(r+1))
    } else {
        return Math.round(Math.random())
    }
}

// seconds
var retry_default = 30;
var forfeit_default = 4*60;
// [name, [[desc_num, level_num], ]]
var experiments = [

    ['gvgai_sokoban',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', 20, forfeit_default],
    ['gvgai_butterflies',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_aliens',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', 10*60, forfeit_default], // never gets shown
    ['gvgai_chase',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_frogs',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_missilecommand',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', retry_default, forfeit_default],
    ['gvgai_portals',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', retry_default, forfeit_default],
    ['gvgai_zelda',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', retry_default, forfeit_default],
    ['gvgai_boulderdash',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        'On this game you can also use the spacebar.', 45, 6*60],
    ['gvgai_survivezombies',
        [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], false,
        '', 10*60, forfeit_default]
]
// var experiments = [

//     ['gvgai_sokoban',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_butterflies',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_aliens',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default], // never gets shown
//     ['gvgai_chase',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_frogs',
//         [[0, 0]], false,
//         '', retry_default, 3],
//     ['gvgai_missilecommand',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default],
//     ['gvgai_portals',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default],
//     ['gvgai_zelda',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default],
//     ['gvgai_boulderdash',
//         [[0, 0]], false,
//         'On this game you can also use the spacebar.', retry_default, forfeit_default],
//     ['gvgai_survivezombies',
//         [[0, 0]], false,
//         '', retry_default, forfeit_default]
// ]
//
// var experiments = experiments_normal.concat(experiments_hard);

var overtime_limit = 25*60*1000;

var get_exp = function () {
    return shuffle(experiments);
}

// console.log(get_exp());

// experiments = experiments.map(experiment => {
//     if (experiment[0] == boulder_dash[0]) {
//         return shuffle(getRandomSubarray(experiments_normal, 4).push(experiment));
//     } else if (experiments[0] == zombies[0]) {
//         return shuffle(getRandomSubarray(experiments_normal, 4)).push(experiment);
//     }
// })

// console.log(experiments);

// An object that updates what game its on
// by calling next
var Experiment = function (exp_name, cookie, randomize_exp=true, static_exps=[], randomize_color=true) {

    if (exp_name == undefined) {
        exp_name = 'exp0'
    }
    var experiment = {};

    experiment.cookie = cookie;
    experiment.expiration = 60*60*1000
    experiment.timeout = Date.now()+experiment.expiration;
    experiment.games_ordered = [];
    experiment.midpoints = {};

    var game_number = 0;

    var exp = get_exp();
    // console.log(exp);
    if (randomize_exp) {
        exp = shuffle(exp, static_exps);// [exp[0]].concat(shuffle(exp.slice(1, exp.length), static_exps));
    }
    exp.forEach(settings => {
        game_number ++;
        var game_name = settings[0];
        var game_levels = settings[1];
        experiment.midpoints[game_number] = settings[3];
        var retry_delay = settings[4];
        var forfeit_delay = settings[5];
        if (settings[2])
            game_levels = shuffle(game_levels);
        var color_scheme = 0;
        if (randomize_color) color_scheme = randint(1307674368000);
        game_levels.forEach(game_level => {
            experiment.games_ordered.push({name: game_name,
                             desc: game_level[0],
                             level: game_level[1],
                             number: game_number,
                             round: 1,
                             color_scheme: color_scheme,
                             retry_delay: retry_delay,
                             forfeit_delay: forfeit_delay,
                             time: 0})

        })
    })

    experiment.started = true;
    experiment.current_trial = 0;
    experiment.current_game_number = 1;
    experiment.max_trials = experiment.games_ordered.length;
    experiment.start_time = Date.now();
    experiment.init_time = Date.now();
    experiment.overtime_check = true;
    experiment.ended = false;
    experiment.continued = false;

    return experiment

}

Experiment.update_timeout = function (experiment) {
        experiment.timeout = Date.now()+experiment.expiration;
    }

Experiment.validate = function (experiment, validation_id) {
    return validation_id == experiment.cookie;
}

Experiment.started = function (experiment) {
    if (experiment.started) {
        experiment.started = false
        return true;
    }
    return false
}

Experiment.retry = function (experiment) {
    Experiment.update_timeout(experiment);
    var current_game = experiment.games_ordered[experiment.current_trial]
    // console.log(current_game);
    if (current_game) {
        current_game.round ++;
    }
    // console.log('retrying experiment', current_game[3])
}

Experiment.current_game = function (experiment) {
    Experiment.update_timeout(experiment);
    if (experiment.current_trial == experiment.max_trials)
        return false;
    var current_game = experiment.games_ordered[experiment.current_trial]
    var game_obj = {};
    game_obj.name = current_game.name;
    game_obj.desc = current_game.desc;
    game_obj.level = current_game.level;
    game_obj.number = current_game.number;
    game_obj.color_scheme = current_game.color_scheme;
    game_obj.retry_delay = current_game.retry_delay;
    game_obj.forfeit_delay = current_game.forfeit_delay;
    game_obj.time = Date.now() - experiment.start_time;
    game_obj.round = current_game.round;
    // console.log(current_game)
    // console.log(game_obj)
    return game_obj;
}

Experiment.remaining_games = function (experiment) {
    return experiments.length - experiment.current_game_number;
}

Experiment.midpoint_text = function (experiment) {
    experiment.init_time = Date.now();
    experiment.current_game_number = experiment.games_ordered[experiment.current_trial].number;
    return experiment.midpoints[experiment.current_game_number];
}

Experiment.current_round = function (experiment) {
    return {
        number: experiment.games_ordered[experiment.current_trial].round
    };
}

Experiment.mid_point_pure = function (experiment) {
    if (experiment.current_game_number == experiment.games_ordered[experiment.current_trial].number)
        return false;
    return true;
}

Experiment.mid_point = function (experiment) {
    if (Experiment.mid_point_pure(experiment)) {
        experiment.current_game_number ++;
        return true
    }
    return false;
}

Experiment.next = function (experiment) {
    Experiment.update_timeout(experiment);
    experiment.current_trial += 1;
}

Experiment.is_done = function  (experiment) {
    if (experiment.current_trial >= experiment.games_ordered.length || experiment.ended) {
        return true;
    }
    return false;
}

Experiment.get_data = function (experiment) {
    var data = experiment.games_ordered[experiment.current_trial];
    data.time = Date.now() - experiment.init_time;
    return experiment.games_ordered[experiment.current_trial];
}

Experiment.forfeit = function (experiment) {
    experiment.current_game_number ++;
    // current_trial --;
}

Experiment.end = function (experiment) {
    experiment.ended = true;
}

Experiment.overtime = function (experiment) {
    if (Date.now() - experiment.start_time > overtime_limit) {
        if (experiment.overtime_check) {
            experiment.overtime_check = false;
            return true
        } else {
            experiment.continued = true;
        }
    }
    return false;
}

Experiment.overtime_continued = function (experiment) {
    if (Experiment.mid_point_pure(experiment) && experiment.continued) {
        experiment.continued = false;
        return !experiment.overtime_check;
    }
    return false;
}

Experiment.timeout = function (experiment) {
    if (Date.now() > experiment.timeout)
        return true;
    return false
}

Experiment.experiments = experiments;

module.exports = Experiment;<|endoftext|>


<commit_before>import Card from '../../card'
import { Command } from 'discord.js-commando'
import SoundProcessor from '../../sound-processor'

import fs from 'fs'
import winston from 'winston'

const SOUND_KINDS = ['play', 'attack', 'trigger', 'death']

module.exports = class SoundCommand extends Command {
    constructor(client) {
        super(client, {
            name: 'sound',
            aliases: ['snd', 's', '🔈', '🔉', '🔊', '🎧', '🎵'],
            group: 'card',
            memberName: 'sound',
            guildOnly: true,
            description: 'Plays card sound in your current voice channel.',
            format:'[kind] <name>',
            examples: [
                'sound tirion',
                'sound attack jaraxxus',
                'sound death refreshment vendor',
                'sound trigger antonaidas'
            ],
            args: [
                {
                    key: 'kind',
                    prompt: '',
                    type: 'string',
                    default: 'play'
                },
                {
                    key: 'name',
                    prompt: 'what card are you searching for?\n',
                    type: 'string',
                    default: ''
                }
            ]
        })

        this.queue = []
    }

    async run(msg, args) {
        if (!msg.channel.typing) { msg.channel.startTyping() }
        if (!SOUND_KINDS.includes(args.kind)) {
            args.name = `${args.kind} ${args.name}`.trim()
            args.kind = 'play'
        }
        if (!args.name) {
            this.args[1].default = null
            args.name = await this.args[1].obtain(msg).catch(winston.error)
        }
        const card = await Card.findByName(args.name).catch(winston.error)
        const soundFilenames = card.getSoundFilenames(args.kind)
        if (!soundFilenames) {
            if (msg.channel.typing) { msg.channel.stopTyping() }
            return msg.reply(`sorry, I don't know the ${args.kind} sound for ${card.name}.`)
        }
        this.queue.push({ message: msg, soundFilenames: soundFilenames })
        if (this.queue.length === 1) { this.handleSound().catch(winston.error) }
        if (msg.channel.typing) { msg.channel.stopTyping() }
        return msg.reply(`I'll join your voice channel and play the ${args.kind} sound for ${card.name} in a moment.`)
    }

    async handleSound() {
        const message = this.queue[0].message
        const soundFilenames = this.queue[0].soundFilenames
        const file = await SoundProcessor.mergeSounds(soundFilenames).catch(winston.error)
        const connection = await this.joinVoiceChannel(message.member.voiceChannel).catch(winston.error)
        if (!connection) {
            this.queue.shift()
            fs.unlink(file, err => { if (err) { winston.error(err) } })
            if (message.member.voiceChannel) { message.member.voiceChannel.leave() }
            message.reply('sorry, there was an error joining your voice channel.')
            if (this.queue.length > 0) { this.handleSound() }
            return
        }
        connection.playFile(file).on('end', () => {
            this.queue.shift()
            fs.unlink(file, err => { if (err) { winston.error(err) } })
            if (this.queue.length > 0) {
                if (this.queue[0].message.member.voiceChannel !== connection.channel) { connection.channel.leave() }
                this.handleSound()
            } else {
                connection.channel.leave()
            }
        })
    }

    async joinVoiceChannel(voiceChannel) {
        if (!voiceChannel || voiceChannel.type !== 'voice') { return null }
        let connection = this.client.voiceConnections.find(conn => conn.channel === voiceChannel)
        if (connection) { return connection }
        return await voiceChannel.join().catch(err => {
            winston.error(err)
            return null
        })
    }
}
<commit_msg>Better errors for joining voice channels<commit_after>import Card from '../../card'
import { Command } from 'discord.js-commando'
import SoundProcessor from '../../sound-processor'

import fs from 'fs'
import winston from 'winston'

const SOUND_KINDS = ['play', 'attack', 'trigger', 'death']

module.exports = class SoundCommand extends Command {
    constructor(client) {
        super(client, {
            name: 'sound',
            aliases: ['snd', 's', '🔈', '🔉', '🔊', '🎧', '🎵'],
            group: 'card',
            memberName: 'sound',
            guildOnly: true,
            description: 'Plays card sound in your voice channel.',
            format:'[kind] <name>',
            examples: [
                'sound tirion',
                'sound attack jaraxxus',
                'sound death refreshment vendor',
                'sound trigger antonaidas'
            ],
            args: [
                {
                    key: 'kind',
                    prompt: '',
                    type: 'string',
                    default: 'play'
                },
                {
                    key: 'name',
                    prompt: 'what card are you searching for?\n',
                    type: 'string',
                    default: ''
                }
            ]
        })

        this.queue = []
    }

    async run(msg, args) {
        if (!msg.channel.typing) { msg.channel.startTyping() }
        if (!SOUND_KINDS.includes(args.kind)) {
            args.name = `${args.kind} ${args.name}`.trim()
            args.kind = 'play'
        }
        if (!args.name) {
            this.args[1].default = null
            args.name = await this.args[1].obtain(msg).catch(winston.error)
        }
        const card = await Card.findByName(args.name).catch(winston.error)
        const soundFilenames = card.getSoundFilenames(args.kind)
        if (!soundFilenames) {
            if (msg.channel.typing) { msg.channel.stopTyping() }
            return msg.reply(`sorry, I don't know the ${args.kind} sound for ${card.name}.`)
        }
        this.queue.push({ message: msg, soundFilenames: soundFilenames })
        if (this.queue.length === 1) { this.handleSound().catch(winston.error) }
        if (msg.channel.typing) { msg.channel.stopTyping() }
        return msg.reply(`I'll join your voice channel and play the ${args.kind} sound for ${card.name} in a moment.`)
    }

    async handleSound() {
        const message = this.queue[0].message
        const soundFilenames = this.queue[0].soundFilenames
        const file = await SoundProcessor.mergeSounds(soundFilenames).catch(winston.error)
        const connection = await this.joinVoiceChannel(message.member.voiceChannel).catch(winston.error)
        if (!connection || typeof connection === 'string') {
            this.queue.shift()
            fs.unlink(file, err => { if (err) { winston.error(err) } })
            if (message.member.voiceChannel) { message.member.voiceChannel.leave() }
            message.reply(`sorry, there was an error joining your voice channel, ${connection || 'unkown'}`)
            if (this.queue.length > 0) { this.handleSound() }
            return
        }
        connection.playFile(file).on('end', () => {
            this.queue.shift()
            fs.unlink(file, err => { if (err) { winston.error(err) } })
            if (this.queue.length > 0) {
                if (this.queue[0].message.member.voiceChannel !== connection.channel) { connection.channel.leave() }
                this.handleSound()
            } else {
                connection.channel.leave()
            }
        })
    }

    async joinVoiceChannel(voiceChannel) {
        if (!voiceChannel || voiceChannel.type !== 'voice') { return 'you\'re not in one' }
        let connection = this.client.voiceConnections.find(conn => conn.channel === voiceChannel)
        if (connection) { return connection }
        return await voiceChannel.join().catch(err => { return err.message.replace('You', 'I') })
    }
}
<|endoftext|>


<commit_before>/* global hexo */

/**
 * Merge configs in _data/next.yml into hexo.theme.config.
 * Note: configs in _data/next.yml will override configs in hexo.theme.config.
 */
hexo.on('generateBefore', function () {
  var data = hexo.locals.get('data');
  data && data.next && assign(hexo.theme.config, data.next);
});

// https://github.com/sindresorhus/object-assign
function assign(target, source) {
  var from;
  var keys;
  var to = toObject(target);

  for (var s = 1; s < arguments.length; s++) {
    from = arguments[s];
    keys = ownEnumerableKeys(Object(from));

    for (var i = 0; i < keys.length; i++) {
      to[keys[i]] = from[keys[i]];
    }
  }

  return to;
}

function toObject(val) {
  if (val == null) {
    throw new TypeError('Object.assign cannot be called with null or undefined');
  }

  return Object(val);
}

function ownEnumerableKeys(obj) {
  var keys = Object.getOwnPropertyNames(obj);

  if (Object.getOwnPropertySymbols) {
    keys = keys.concat(Object.getOwnPropertySymbols(obj));
  }

  return keys.filter(function (key) {
    return Object.prototype.propertyIsEnumerable.call(obj, key);
  });
}
<commit_msg>Bug: hexo.locals.get is unavailable when Hexo version is less than 3. #468<commit_after>/* global hexo */

/**
 * Merge configs in _data/next.yml into hexo.theme.config.
 * Note: configs in _data/next.yml will override configs in hexo.theme.config.
 */
hexo.on('generateBefore', function () {
  if (hexo.locals.get) {
    var data = hexo.locals.get('data');
    data && data.next && assign(hexo.theme.config, data.next);
  }
});

// https://github.com/sindresorhus/object-assign
function assign(target, source) {
  var from;
  var keys;
  var to = toObject(target);

  for (var s = 1; s < arguments.length; s++) {
    from = arguments[s];
    keys = ownEnumerableKeys(Object(from));

    for (var i = 0; i < keys.length; i++) {
      to[keys[i]] = from[keys[i]];
    }
  }

  return to;
}

function toObject(val) {
  if (val == null) {
    throw new TypeError('Object.assign cannot be called with null or undefined');
  }

  return Object(val);
}

function ownEnumerableKeys(obj) {
  var keys = Object.getOwnPropertyNames(obj);

  if (Object.getOwnPropertySymbols) {
    keys = keys.concat(Object.getOwnPropertySymbols(obj));
  }

  return keys.filter(function (key) {
    return Object.prototype.propertyIsEnumerable.call(obj, key);
  });
}
<|endoftext|>


<commit_before>import CompositeClosureHelper from '../../../Common/Core/CompositeClosureHelper';

// ----------------------------------------------------------------------------
// Global
// ----------------------------------------------------------------------------

function flipHistogram(histo2d) {
  const newHisto2d = {
    bins: histo2d.bins.map(bin => {
      const { x, y, count } = bin;
      return {
        x: y,
        y: x,
        count,
      };
    }),
    x: histo2d.y,
    y: histo2d.x,
    maxCount: histo2d.maxCount,
  };

  return newHisto2d;
}

// ----------------------------------------------------------------------------
// Histogram 2D Provider
// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, initialValues);

  CompositeClosureHelper.destroy(publicAPI, model);
  CompositeClosureHelper.isA(publicAPI, model, 'Histogram2DProvider');
  CompositeClosureHelper.dataSubscriber(publicAPI, model, 'histogram2D', {
    defaultMetadata: {
      numberOfBins: 32,
      partial: true,
    },
    set(storage, data) {
      if (!storage[data.x.name]) {
        storage[data.x.name] = {};
      }
      if (!storage[data.y.name]) {
        storage[data.y.name] = {};
      }

      // Add maxCount
      let maxCount = 0;
      data.bins.forEach(item => {
        maxCount = maxCount < item.count ? item.count : maxCount;
      });
      data.maxCount = maxCount;

      const sameAsBefore = (JSON.stringify(data) === JSON.stringify(storage[data.x.name][data.y.name]));

      storage[data.x.name][data.y.name] = data;
      storage[data.y.name][data.x.name] = flipHistogram(data);

      return sameAsBefore;
    },
    get(storage, request, dataChanged) {
      const returnedData = {};
      let count = 0;
      let maxCount = 0;
      request.variables.forEach(axisPair => {
        if (!returnedData[axisPair[0]]) {
          returnedData[axisPair[0]] = {};
        }
        if (storage[axisPair[0]] && storage[axisPair[0]][axisPair[1]]) {
          const hist2d = storage[axisPair[0]][axisPair[1]];
          count++;
          maxCount = maxCount < hist2d.maxCount ? hist2d.maxCount : maxCount;
          returnedData[axisPair[0]][axisPair[1]] = hist2d;
        }
      });

      // Attach global maxCount
      returnedData.maxCount = maxCount;

      if (count === request.variables.length || (request.metadata.partial && count > 0)) {
        return returnedData;
      }
      return null;
    },
  });
}

// ----------------------------------------------------------------------------

export const newInstance = CompositeClosureHelper.newInstance(extend);

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<commit_msg>fix(Histogram2DProvider): Handle multiple numberOfBin subscription<commit_after>import CompositeClosureHelper from '../../../Common/Core/CompositeClosureHelper';

// ----------------------------------------------------------------------------
// Expected Data Format for Histogram2D
// ----------------------------------------------------------------------------
//
// {
//   "x": {
//     delta: 3.5,
//     extent: [0, 35],
//     name: "Name of X",
//   },
//   "y": {
//     delta: 1,
//     extent: [0, 10],
//     name: "Name of Y",
//   },
//   "bins": [
//     { x: 3.5, y: 5, count: 46 }, ...
//   ]
// }
//
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// Global
// ----------------------------------------------------------------------------

function flipHistogram(histo2d) {
  const newHisto2d = {
    bins: histo2d.bins.map(bin => {
      const { x, y, count } = bin;
      return {
        x: y,
        y: x,
        count,
      };
    }),
    x: histo2d.y,
    y: histo2d.x,
    maxCount: histo2d.maxCount,
  };

  return newHisto2d;
}

// ----------------------------------------------------------------------------
// Histogram 2D Provider
// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
  Object.assign(model, initialValues);

  CompositeClosureHelper.destroy(publicAPI, model);
  CompositeClosureHelper.isA(publicAPI, model, 'Histogram2DProvider');
  CompositeClosureHelper.dataSubscriber(publicAPI, model, 'histogram2D', {
    defaultMetadata: {
      numberOfBins: 32,
      partial: true,
    },
    set(storage, data) {
      const binSize = (data.x.extent[1] - data.x.extent[0]) / data.x.delta;
      if (!storage[binSize]) {
        storage[binSize] = {};
      }
      const binStorage = storage[binSize];
      if (!binStorage[data.x.name]) {
        binStorage[data.x.name] = {};
      }
      if (!binStorage[data.y.name]) {
        binStorage[data.y.name] = {};
      }

      // Add maxCount
      let maxCount = 0;
      data.bins.forEach(item => {
        maxCount = maxCount < item.count ? item.count : maxCount;
      });
      data.maxCount = maxCount;

      const sameAsBefore = (JSON.stringify(data) === JSON.stringify(binStorage[data.x.name][data.y.name]));

      binStorage[data.x.name][data.y.name] = data;
      binStorage[data.y.name][data.x.name] = flipHistogram(data);

      return sameAsBefore;
    },
    get(storage, request, dataChanged) {
      const returnedData = {};
      let count = 0;
      let maxCount = 0;
      const { numberOfBins } = request.metadata;
      const binStorage = storage[numberOfBins];
      request.variables.forEach(axisPair => {
        if (!returnedData[axisPair[0]]) {
          returnedData[axisPair[0]] = {};
        }
        if (binStorage[axisPair[0]] && binStorage[axisPair[0]][axisPair[1]]) {
          const hist2d = binStorage[axisPair[0]][axisPair[1]];
          count++;
          maxCount = maxCount < hist2d.maxCount ? hist2d.maxCount : maxCount;
          returnedData[axisPair[0]][axisPair[1]] = hist2d;
        }
      });

      // Attach global maxCount
      returnedData.maxCount = maxCount;

      if (count === request.variables.length || (request.metadata.partial && count > 0)) {
        return returnedData;
      }
      return null;
    },
  });
}

// ----------------------------------------------------------------------------

export const newInstance = CompositeClosureHelper.newInstance(extend);

// ----------------------------------------------------------------------------

export default { newInstance, extend };
<|endoftext|>


<commit_before>
module("scrollEnd", {
  setup : function() {
    this.agent = eg.agent;
    this.isFireEvent = false;
    this.topPos = 10;
    this.intervalNum = 0;

  },
  teardown : function() {
    eg.agent = this.agent;
    $(window).off("scrollend");
  }
});

test("getDeviceType : android && 2.1 ", function() {
    // Given
  eg.agent = function(){
      return {
         "os" : {
             "name" : "android",
             "version" : "2.1"
         },
         "browser" : {}
      }
    }
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TOUCHBASE);

});

test("getDeviceType : android && chrome ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "2.1"
       },
       "browser" : {
            "name" : "chrome"
       }
     }
    };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.CHROME);

});

test("getDeviceType : android && version 3.x over ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "3.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TIMERBASE);

});

test("getDeviceType : ios && version 8.x over ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "ios",
           "version" : "8.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TIMERBASE);

});

test("getDeviceType : window && version 8.x over ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "window",
           "version" : "8.0"
       },
       "browser" : {
            "name" : ""
       }
     }
  };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TIMERBASE);

});

test("touchbase scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "2.1"
       },
       "browser" : {
            "name" : ""
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });

    $(document).trigger("touchstart");
    $(document).trigger("touchmove");
    this.topPos += 10;
    window.scrollTo(0, this.topPos);
    $(document).trigger("touchend");
    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 50){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.TOUCHBASE);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

test("scroll scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "ios",
           "version" : "7.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });

    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 20){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.SCROLLBASE);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

test("timer scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "ios",
           "version" : "8.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });

    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 20){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.TIMERBASE);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

test("chrome scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "4.1"
       },
       "browser" : {
            "name" : "chrome"
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });
    $(document).trigger("orientationchange");

    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 40){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.CHROME);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

<commit_msg>test(scrollEnd) : Modify test code<commit_after>
module("scrollEnd", {
  setup : function() {
    this.agent = eg.agent;
    this.isFireEvent = false;
    this.topPos = 10;
    this.intervalNum = 0;

  },
  teardown : function() {
    eg.agent = this.agent;
    $(window).off("scrollend");
  }
});

test("getDeviceType : android && 2.1 ", function() {
    // Given
  eg.agent = function(){
      return {
         "os" : {
             "name" : "android",
             "version" : "2.1"
         },
         "browser" : {}
      }
    }
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TOUCHBASE);

});

test("getDeviceType : android && chrome ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "2.1"
       },
       "browser" : {
            "name" : "chrome"
       }
     }
    };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.CHROME);

});

test("getDeviceType : android && version 3.x over ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "3.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TIMERBASE);

});

test("getDeviceType : ios && version 8.x over ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "ios",
           "version" : "8.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TIMERBASE);

});

test("getDeviceType : window && version 8.x over ", function() {
    // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "window",
           "version" : "8.0"
       },
       "browser" : {
            "name" : ""
       }
     }
  };
    var method = eg._invoke("scrollEnd",[null,null,null,null]);

    // When
    $(window).on("scrollend", function(){
    });

    // Then
    equal(method.getDeviceType(), method.TIMERBASE);

});

test("touchbase scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "2.1"
       },
       "browser" : {
            "name" : ""
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });

    $(document).trigger("touchstart");
    $(document).trigger("touchmove");
    this.topPos += 10;
    window.scrollTo(0, this.topPos);
    $(document).trigger("touchend");
    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 50){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.TOUCHBASE);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

test("scroll scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "ios",
           "version" : "7.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });

    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 20){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.SCROLLBASE);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

test("timer scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "ios",
           "version" : "8.0"
       },
       "browser" : {
            "name" : ""
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });

    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 20){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.TIMERBASE);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

test("chrome scroll", function() {
  // Given
  eg.agent = function(){
    return {
       "os" : {
           "name" : "android",
           "version" : "4.1"
       },
       "browser" : {
            "name" : "chrome"
       }
     }
    };

    window.scrollTo(0, 1);
    var method = eg._invoke("scrollEnd",[null,null,null,null]);
    var self = this;

  // When
    $(window).on("scrollend", function(){
       self.isFireEvent = true;
    });
    $(window).trigger("orientationchange");

    this.intervalNum = setInterval(function(){
        self.topPos += 10;
        window.scrollTo(0, self.topPos);
        if(self.topPos > 40){
            clearInterval(self.intervalNum);
        }
    }, 30);

  // Then
  equal(method.getDeviceType(), method.CHROME);

  stop();
  setTimeout(function(){
      strictEqual(self.isFireEvent , true, "scrollend event occurred");
      start();
  }, 500);
});

<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } els<commit_msg>Reverting changes<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else<|endoftext|>