<commit_before>//--------------------------------------------------------------------------//
//                                                                          //
//                         J S - B V - S A M P L I N G                      //
//                                                                          //
//                                                                          //
// Permission is hereby granted, free of charge, to any person obtaining    //
// a copy of this software and associated documentation files (the          //
// "Software"), to deal in the Software without restriction, including      //
// without limitation the rights to use, copy, modify, merge, publish,      //
// distribute, sublicense, and/or sell copies of the Software, and to       //
// permit persons to whom the Software is furnished to do so, subject to    //
// the following conditions:                                                //
//                                                                          //
// The above copyright notice and this permission notice shall be           //
// included in all copies or substantial portions of the Software.          //
//                                                                          //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          //
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                    //
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE   //
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION   //
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION    //
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.          //
// License information here                                                 //
//                                                                          //
// Author: Jon Anthony (2014)                                               //
//                                                                          //
//--------------------------------------------------------------------------//
//

// General JS sort predicate (this should really go in some general
// util pkg).
function _spred (l, r) {
    return ((l < r) ? -1 : ((l > r) ? 1 : 0));
}

// An estimator of coverage depth of corresponding data file (for the
// index reader - bam or vcf) which uses bytes in region segments as
// the indicator.  Returns the estimations as an object of 'segment
// information' maps, where each key is a reference id and each such
// map is:
//
// {relBinNum: (segment-bin-num - start16kbBinid)
//  pos:       (relBinNum * 16KB)
//  depth:     total-byte-count}
//
function estimateCoverageDepth (indexReader, cb) {
    var rdrThis = indexReader;

    if (rdrThis.estimates) {
        if (cb) {cb.call(rdrThis, rdrThis.estimates)};
        return rdrThis.estimates;
    } else {
        var indexWreads =
            rdrthis.idxContent.indexseq.reduce(
                function(V, x, i, _){
                    if (x.n_bin != 0 || x.n_intv != 0)
                        V.push([x, i]);
                    return V;
                }, []);

        rdrThis.estimates =
            indexWreads.reduce(
                function(RD, I) {
                    var ref = I[1];
                    var withLeafBins = I[0].binseq.filter(
                        function(o){
                            return (o.bin >= start16kbBinid &&
                                    o.bin <= end16kbBinid);});

                    refsegs =
                        withLeafBins.reduce(
                            function(segs, o){
                                var b = o.bin;
                                var relBinNum = (b - start16kbBinid);
                                var position =  (relBinNum * _16KB);
                                var readDepth =
                                    o.chunkseq.reduce(
                                        function(bc, chunk) {
                                            var b = chunk.cnk_beg.valueOf();
                                            var e = chunk.cnk_end.valueOf();
                                            return bc + (rshift16(e) -
                                                         rshift16(b));
                                        }, 0);
                                segs.push(
                                    {relBinNum: relBinNum,
                                     pos: position, depth: readDepth});
                                return segs;
                            }, []);
                    return RD[ref] = refsegs;
                }, {});
        return estimateCoverageDepth(indexReader, cb);
    };
}

// Mapping function over the estimate read coverage segments of
// reference REFID.  See estimateCoverageDepth for more on segments.
// Requires that estimateCoverageDepth has been run; if not will
// implicitly run it.  FN is a function of a segment information map.
// For the sq of segment information maps for REFID [segmap...],
// returns the sq [fn(seqmap)...].  If keepNils is true, returns fn
// results which are nil (undefined), otherwise, returns only non nil
// results.
function mapSegCoverage (indexReader, refid, fn, keepNils) {
    var info = function (i) {
        var e = indexReader.estimates[refid][i];
        return (e) ? e : {relBinNum: i, pos: i * 16384, depth: 0}
    };

    var res = [];
    for (var i = 0; i < (end16kbBinid - start16kbBinid); i++) {
        var user_res = fn.call(indexReader, info(i))
        if (keepNils) {
            res.push(user_res);
        } else if (user_res) {
            res.push(user_res);
        }
    };
    return res;
}

// For a sq of reference objects REFS (as obtained from file header
// information), and option set OPTIONS (a map of parameter options),
// obtains a set of region samples for each reference in refs.  The
// resulting set is intended to be a 'representative sample' of the
// base file.
//
// Tuning parameters in options are binSize, the max size covered by a
// bin; binNumber, the max number of bins to consider for a ref;
// start, the starting position of the sequence associated with a ref
// for a sampling.  Defaults are binSize = 40000 bases, binNumber =
// 20, start = 1.
//
// Returns a map {regions: [reginfo...], regstr: json-string-for-regions}
//
// where reginfo = {name: ref.name, start: int, end: int} and regions
// is sorted ascendingly by name by numerical start
//
//
function samplingRegions (refs, options) {
    var bsize = options.binSize || 40000;
    var bcnt  = options.binNumber || 20;
    var start = options.start || 1;
    var regions =
        refs.reduce(
            function(regs, ref) {
                var len = ref.l_ref - start;
                if (len > 0 && len < (bcnt * bsize)) {
                    regs.push({name: ref.name, start: start, end: ref.l_ref});
                } else if (len > 0) {
                    // There are cases where it is too painful to
                    // write functional code in js...
                    for (var i = 0; i < bcnt; i++) {
                        var nstart = start + Math.floor(Math.random() * len);
                        regs.push(
                            {name: ref.name,
                             start: nstart,
                             end: nstart + bsize});
                    };
                };
                return regs;
            }, []);

    regions = regions.sort(function(l,r){
        if (l.name ==  r.name) {
            return parseInt(l.start) - parseInt(r.start)
        } else {
            return _spred(l.name, r.name);
        }});

    return {regions: regions,
            regstr: JSON.stringify(regions.map(
                function(r){
                    // This is broken - SERVERs should change names if needed!
                    return {start: r.start, end: r.l_ref, chr: r.name}}))};
}

// Convert ref objects to old format.  Servers should be upgraded to
// use the actual bai index names, but this will provide interim
// support.  Takes a sq REFS of reference objs, each of format {name:
// string, l_ref: int, l_name: int} and converts to sq of objs of
// format {name: string, end: int}
function new2oldRefs (refs) {
    return refs.map(function(ref) {return {name: ref.name, end: ref.l_ref}});
}

// Obtain a bamstats-alive url encoding for a region sampling of REFS
// a sq of reference objects as obtained from file header information.
// Performs a samplingRegions operation to obtain the region
// information and then generates a corresponding url for the
// bamstats-alive server.  OPTIONS is as for samplingRegions.
// bsaliveURL is the base http address for a bamstats-alive server.
function bamStatsAliveSamplingURL (refs, options, bsaliveURL) {
    var regionInfo = samplingRegions(refs, options);
    var regions = regionInfo.regions;
    var regStr = regionInfo.regStr;
    return encodeURI(
        bsaliveURL +
            '?cmd=-u 3000 -r \'' + regStr + '\' ' +
            encodeURIComponent(getBamRegionsUrl(regions)));
}<commit_msg>fix bug in sampling<commit_after>//--------------------------------------------------------------------------//
//                                                                          //
//                         J S - B V - S A M P L I N G                      //
//                                                                          //
//                                                                          //
// Permission is hereby granted, free of charge, to any person obtaining    //
// a copy of this software and associated documentation files (the          //
// "Software"), to deal in the Software without restriction, including      //
// without limitation the rights to use, copy, modify, merge, publish,      //
// distribute, sublicense, and/or sell copies of the Software, and to       //
// permit persons to whom the Software is furnished to do so, subject to    //
// the following conditions:                                                //
//                                                                          //
// The above copyright notice and this permission notice shall be           //
// included in all copies or substantial portions of the Software.          //
//                                                                          //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          //
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                    //
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE   //
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION   //
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION    //
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.          //
// License information here                                                 //
//                                                                          //
// Author: Jon Anthony (2014)                                               //
//                                                                          //
//--------------------------------------------------------------------------//
//

// General JS sort predicate (this should really go in some general
// util pkg).
function _spred (l, r) {
    return ((l < r) ? -1 : ((l > r) ? 1 : 0));
}

// An estimator of coverage depth of corresponding data file (for the
// index reader - bam or vcf) which uses bytes in region segments as
// the indicator.  Returns the estimations as an object of 'segment
// information' maps, where each key is a reference id and each such
// map is:
//
// {relBinNum: (segment-bin-num - start16kbBinid)
//  pos:       (relBinNum * 16KB)
//  depth:     total-byte-count}
//
function estimateCoverageDepth (indexReader, cb) {
    var rdrThis = indexReader;

    if (rdrThis.estimates) {
        if (cb) {cb.call(rdrThis, rdrThis.estimates)};
        return rdrThis.estimates;
    } else {
        var indexWreads =
            rdrThis.idxContent.indexseq.reduce(
                function(V, x, i, _){
                    if (x.n_bin != 0 || x.n_intv != 0)
                        V.push([x, i]);
                    return V;
                }, []);

        rdrThis.estimates =
            indexWreads.reduce(
                function(RD, I) {
                    var ref = I[1];
                    var withLeafBins = I[0].binseq.filter(
                        function(o){
                            return (o.bin >= start16kbBinid &&
                                    o.bin <= end16kbBinid);});

                    refsegs =
                        withLeafBins.reduce(
                            function(segs, o){
                                var b = o.bin;
                                var relBinNum = (b - start16kbBinid);
                                var position =  (relBinNum * _16KB);
                                var readDepth =
                                    o.chunkseq.reduce(
                                        function(bc, chunk) {
                                            var b = chunk.cnk_beg.valueOf();
                                            var e = chunk.cnk_end.valueOf();
                                            return bc + (rshift16(e) -
                                                         rshift16(b));
                                        }, 0);
                                segs.push(
                                    {relBinNum: relBinNum,
                                     pos: position, depth: readDepth});
                                return segs;
                            }, []);
                    RD[ref] = refsegs;
                    return RD;
                }, {});
        return estimateCoverageDepth(indexReader, cb);
    };
}

// Mapping function over the estimate read coverage segments of
// reference REFID.  See estimateCoverageDepth for more on segments.
// Requires that estimateCoverageDepth has been run; if not will
// implicitly run it.  FN is a function of a segment information map.
// For the sq of segment information maps for REFID [segmap...],
// returns the sq [fn(seqmap)...].  If keepNils is true, returns fn
// results which are nil (undefined), otherwise, returns only non nil
// results.
function mapSegCoverage (indexReader, refid, fn, keepNils) {
    var info = function (i) {
        var e = indexReader.estimates[refid][i];
        return (e) ? e : {relBinNum: i, pos: i * 16384, depth: 0}
    };

    var res = [];
    for (var i = 0; i < (end16kbBinid - start16kbBinid); i++) {
        var user_res = fn.call(indexReader, info(i))
        if (keepNils) {
            res.push(user_res);
        } else if (user_res) {
            res.push(user_res);
        }
    };
    return res;
}

// For a sq of reference objects REFS (as obtained from file header
// information), and option set OPTIONS (a map of parameter options),
// obtains a set of region samples for each reference in refs.  The
// resulting set is intended to be a 'representative sample' of the
// base file.
//
// Tuning parameters in options are binSize, the max size covered by a
// bin; binNumber, the max number of bins to consider for a ref;
// start, the starting position of the sequence associated with a ref
// for a sampling.  Defaults are binSize = 40000 bases, binNumber =
// 20, start = 1.
//
// Returns a map {regions: [reginfo...], regstr: json-string-for-regions}
//
// where reginfo = {name: ref.name, start: int, end: int} and regions
// is sorted ascendingly by name by numerical start
//
//
function samplingRegions (refs, options) {
    var bsize = options.binSize || 40000;
    var bcnt  = options.binNumber || 20;
    var start = options.start || 1;
    var regions =
        refs.reduce(
            function(regs, ref) {
                var len = ref.l_ref - start;
                if (len > 0 && len < (bcnt * bsize)) {
                    regs.push({name: ref.name, start: start, end: ref.l_ref});
                } else if (len > 0) {
                    // There are cases where it is too painful to
                    // write functional code in js...
                    for (var i = 0; i < bcnt; i++) {
                        var nstart = start + Math.floor(Math.random() * len);
                        regs.push(
                            {name: ref.name,
                             start: nstart,
                             end: nstart + bsize});
                    };
                };
                return regs;
            }, []);

    regions = regions.sort(function(l,r){
        if (l.name ==  r.name) {
            return parseInt(l.start) - parseInt(r.start)
        } else {
            return _spred(l.name, r.name);
        }});

    return {regions: regions,
            regstr: JSON.stringify(regions.map(
                function(r){
                    // This is broken - SERVERs should change names if needed!
                    return {start: r.start, end: r.l_ref, chr: r.name}}))};
}

// Convert ref objects to old format.  Servers should be upgraded to
// use the actual bai index names, but this will provide interim
// support.  Takes a sq REFS of reference objs, each of format {name:
// string, l_ref: int, l_name: int} and converts to sq of objs of
// format {name: string, end: int}
function new2oldRefs (refs) {
    return refs.map(function(ref) {return {name: ref.name, end: ref.l_ref}});
}

// Obtain a bamstats-alive url encoding for a region sampling of REFS
// a sq of reference objects as obtained from file header information.
// Performs a samplingRegions operation to obtain the region
// information and then generates a corresponding url for the
// bamstats-alive server.  OPTIONS is as for samplingRegions.
// bsaliveURL is the base http address for a bamstats-alive server.
function bamStatsAliveSamplingURL (refs, options, bsaliveURL) {
    var regionInfo = samplingRegions(refs, options);
    var regions = regionInfo.regions;
    var regStr = regionInfo.regStr;
    return encodeURI(
        bsaliveURL +
            '?cmd=-u 3000 -r \'' + regStr + '\' ' +
            encodeURIComponent(getBamRegionsUrl(regions)));
}<|endoftext|>


<commit_before>/**
 * @file Page rendering module.
 */

/* jshint strict: false, browser: true, globalstrict: true */
/* global require, module */

'use strict';
var d3 = require('d3');
var flameGraphModule = require('./flame_graph.js');
var memoryStatsModule = require('./memory_stats.js');
var codeHeatmapModule = require('./code_heatmap.js');

var JSON_URI = 'profile';
var POLL_INTERVAL = 300;  // msec

/**
 * Creates empty div with specified ID and class tab-content.
 * @param {string} id - div ID.
 */
function createTabContent_(id) {
  return d3.select('body')
    .append('div')
    .attr('class', 'tab-content')
    .attr('id', id);
}

/**
 *  Creates flame graph tab header with specified status and
 *  appends it to the parent node.
 *  @param {Object} parent - Parent element to append tab to.
 *  @param {status} status - Specified tab status.
 */
function createFlameGraphTab_(parent, status) {
  parent.append('li')
    .attr('class', status)
    .text('Flame graph')
    .on('click', function(d) {
      d3.selectAll('li')
        .attr('class', 'not-selected');
      d3.select(this)
        .attr('class', 'selected');
      showTab_('flame-graph');
    });
}

/**
 *  Creates memory stats tab header with specified status and
 *  appends it to the parent node.
 *  @param {Object} parent - Parent element to append tab to.
 *  @param {status} status - Specified tab status.
 */
function createMemoryChartTab_(parent, status) {
  parent.append('li')
    .attr('class', status)
    .text('Memory stats')
    .on('click', function(d) {
      d3.selectAll('li')
        .attr('class', 'not-selected');
      d3.select(this)
        .attr('class', 'selected');
      showTab_('memory-chart');
    });
}

/**
 *  Creates code heatmap tab header with specified status and
 *  appends it to the parent node.
 *  @param {Object} parent - Parent element to append tab to.
 *  @param {status} status - Specified tab status.
 */
function createCodeHeatmapTab_(parent, status) {
  parent.append('li')
    .attr('class', status)
    .text('Code heatmap')
    .on('click', function(d) {
      d3.selectAll('li')
        .attr('class', 'not-selected');
      d3.select(this)
        .attr('class', 'selected');
      showTab_('code-heatmap');
    });
}

/**
 * Renders stats page.
 * @param {Object} data - Data for page rendering.
 */
function renderPage(data) {
  var tabHeader = d3.select('body')
    .append('ul')
    .attr('class', 'tab-header');

  var props = Object.keys(data);
  props.sort();
  for (var i = 0; i < props.length; i++) {
    var status = (i === 0) ? 'selected' : 'not-selected';
    var display = (i === 0) ? 'block' : 'none';
    switch (props[i]) {
    case 'c':
      createFlameGraphTab_(tabHeader, status);
      var flameGraph = createTabContent_('flame-graph');
      flameGraphModule.renderFlameGraph(data.c, flameGraph);
      flameGraph.attr('style', 'display: ' + display);
      break;
    case 'm':
      createMemoryChartTab_(tabHeader, status);
      var memoryChart = createTabContent_('memory-chart');
      memoryStatsModule.renderMemoryStats(data.m, memoryChart);
      memoryChart.attr('style', 'display: ' + display);
      break;
    case 'h':
      createCodeHeatmapTab_(tabHeader, status);
      var codeHeatmap = createTabContent_('code-heatmap');
      codeHeatmapModule.renderCodeHeatmap(data.h, codeHeatmap);
      codeHeatmap.attr('style', 'display: ' + display);
      break;
    }
  }
}

/**
  * Makes tab specified by tabId active.
  * @param {string} tabId - Next active tab identifier.
  */
function showTab_(tabId) {
  var allTabs = document.getElementsByClassName('tab-content');
  for (var i = 0; i < allTabs.length; i++) {
    allTabs[i].style.display = 'none';
  }
  var currentTab = document.getElementById(tabId);
  currentTab.style.display = 'block';
}

/** Makes request to server and renders page with received data. */
function main() {
  var progressIndicator = d3.select('body')
    .append('div')
    .attr('id', 'progress-indicator');

  var timerId = setInterval(function() {
    d3.json(JSON_URI, function(data) {
      if (Object.keys(data).length !== 0) {
        progressIndicator.remove();
        clearInterval(timerId);
        renderPage(data);
      }
    });
  }, POLL_INTERVAL);
}

main();
<commit_msg>Change UI poll interval.<commit_after>/**
 * @file Page rendering module.
 */

/* jshint strict: false, browser: true, globalstrict: true */
/* global require, module */

'use strict';
var d3 = require('d3');
var flameGraphModule = require('./flame_graph.js');
var memoryStatsModule = require('./memory_stats.js');
var codeHeatmapModule = require('./code_heatmap.js');

var JSON_URI = 'profile';
var POLL_INTERVAL = 100;  // msec

/**
 * Creates empty div with specified ID and class tab-content.
 * @param {string} id - div ID.
 */
function createTabContent_(id) {
  return d3.select('body')
    .append('div')
    .attr('class', 'tab-content')
    .attr('id', id);
}

/**
 *  Creates flame graph tab header with specified status and
 *  appends it to the parent node.
 *  @param {Object} parent - Parent element to append tab to.
 *  @param {status} status - Specified tab status.
 */
function createFlameGraphTab_(parent, status) {
  parent.append('li')
    .attr('class', status)
    .text('Flame graph')
    .on('click', function(d) {
      d3.selectAll('li')
        .attr('class', 'not-selected');
      d3.select(this)
        .attr('class', 'selected');
      showTab_('flame-graph');
    });
}

/**
 *  Creates memory stats tab header with specified status and
 *  appends it to the parent node.
 *  @param {Object} parent - Parent element to append tab to.
 *  @param {status} status - Specified tab status.
 */
function createMemoryChartTab_(parent, status) {
  parent.append('li')
    .attr('class', status)
    .text('Memory stats')
    .on('click', function(d) {
      d3.selectAll('li')
        .attr('class', 'not-selected');
      d3.select(this)
        .attr('class', 'selected');
      showTab_('memory-chart');
    });
}

/**
 *  Creates code heatmap tab header with specified status and
 *  appends it to the parent node.
 *  @param {Object} parent - Parent element to append tab to.
 *  @param {status} status - Specified tab status.
 */
function createCodeHeatmapTab_(parent, status) {
  parent.append('li')
    .attr('class', status)
    .text('Code heatmap')
    .on('click', function(d) {
      d3.selectAll('li')
        .attr('class', 'not-selected');
      d3.select(this)
        .attr('class', 'selected');
      showTab_('code-heatmap');
    });
}

/**
 * Renders stats page.
 * @param {Object} data - Data for page rendering.
 */
function renderPage(data) {
  var tabHeader = d3.select('body')
    .append('ul')
    .attr('class', 'tab-header');

  var props = Object.keys(data);
  props.sort();
  for (var i = 0; i < props.length; i++) {
    var status = (i === 0) ? 'selected' : 'not-selected';
    var display = (i === 0) ? 'block' : 'none';
    switch (props[i]) {
    case 'c':
      createFlameGraphTab_(tabHeader, status);
      var flameGraph = createTabContent_('flame-graph');
      flameGraphModule.renderFlameGraph(data.c, flameGraph);
      flameGraph.attr('style', 'display: ' + display);
      break;
    case 'm':
      createMemoryChartTab_(tabHeader, status);
      var memoryChart = createTabContent_('memory-chart');
      memoryStatsModule.renderMemoryStats(data.m, memoryChart);
      memoryChart.attr('style', 'display: ' + display);
      break;
    case 'h':
      createCodeHeatmapTab_(tabHeader, status);
      var codeHeatmap = createTabContent_('code-heatmap');
      codeHeatmapModule.renderCodeHeatmap(data.h, codeHeatmap);
      codeHeatmap.attr('style', 'display: ' + display);
      break;
    }
  }
}

/**
  * Makes tab specified by tabId active.
  * @param {string} tabId - Next active tab identifier.
  */
function showTab_(tabId) {
  var allTabs = document.getElementsByClassName('tab-content');
  for (var i = 0; i < allTabs.length; i++) {
    allTabs[i].style.display = 'none';
  }
  var currentTab = document.getElementById(tabId);
  currentTab.style.display = 'block';
}

/** Makes request to server and renders page with received data. */
function main() {
  var progressIndicator = d3.select('body')
    .append('div')
    .attr('id', 'progress-indicator');

  var timerId = setInterval(function() {
    d3.json(JSON_URI, function(data) {
      console.log(data);
      if (Object.keys(data).length !== 0) {
        progressIndicator.remove();
        clearInterval(timerId);
        renderPage(data);
      }
    });
  }, POLL_INTERVAL);
}

main();
<|endoftext|>


<commit_before>var Leap = require('leapjs');
var robot = require("robotjs");

var bangEventEmitted = false;

function clamp(val, min, max) {
    return Math.min(Math.max(val, min), max);
}

var sensitivity = 0.08;
var xTolerance = 40;

var controller = new Leap.Controller()
controller.setBackground(true);
controller.loop(function(frame) {
    if (frame.hands.length === 0) {
        bangEventEmitted = false;
    }

    var mouse = robot.getMousePos();
    frame.hands.forEach(function(hand) {

        var posX = hand.indexFinger.stabilizedTipPosition[0];
        var handDirectionY = hand.direction[1];

        // This is kasey stuff:
        /*
        var yVec = Leap.vec3.fromValues(0, handDirectionY, 0);
        var yBasis = Leap.vec3.fromValues(0,1,0);
        var yAngle = Math.asin(Leap.vec3.dot(yVec, yBasis) / handDirectionY);
        console.log(Leap.vec3.dot(yVec, yBasis) / handDirectionY);
        var angleLimit = (7*Math.PI)/18;
        var yAngle = clamp(yAngle, -angleLimit, angleLimit);
        var newY = 799 + ((yAngle + angleLimit) / (2*angleLimit));
        robot.moveMouse(mouse.x + (posX * sensitivity), newY);
        */

        var yComponentThreshold = 0.5;
        if (handDirectionY > yComponentThreshold) {
            robot.moveMouse(mouse.x + (posX * sensitivity), mouse.y - 5);
        } else {
            robot.moveMouse(mouse.x + (posX * sensitivity), (-handDirectionY * mouse.y * 2) + 400);
        }

        if (!hand.indexFinger.extended || !hand.middleFinger.extended) {
            if (!bangEventEmitted) {
                console.log('BANG!!!');
                robot.mouseClick();
                bangEventEmitted = true;
            }
        } else {
            bangEventEmitted = false;
        }
    });
});

<commit_msg>Added camera controls based on the x,y position of the hand.<commit_after>var Leap = require('leapjs');
var robot = require("robotjs");

var bangEventEmitted = false;

//Move value towards the target by the specfied amount
function moveTowards(val, target, amount) {
    var dir = (val > target) ? -1 : 1;

    return val + (amount * dir);
}

//Camera benhavior variables
var sensitivityX = 0.09;
var sensitivityY = 0.0725;

var centerX = 0;
var x_box_width = 12.5;

var centerY = 220;
var y_box_width = 15;

var x_safe = [centerX - x_box_width, centerX + x_box_width]
var y_safe = [centerY - y_box_width, centerY + y_box_width];

//Main event loop
var controller = new Leap.Controller()
controller.setBackground(true);
controller.loop(function(frame) {
    if (frame.hands.length === 0) {
        bangEventEmitted = false;
    }

    var mouse = robot.getMousePos();
    frame.hands.forEach(function(hand) {

        //Update camera position
        var posX = hand.indexFinger.stabilizedTipPosition[0];
        var posY = hand.indexFinger.stabilizedTipPosition[1];

        if (posX > x_safe[0] && posX < x_safe[1]) {
            posX = 0;
        }
        else {
            posX = moveTowards(posX, centerX, x_box_width);
        }

        //Disable y mostion if we're in the safe box.
        if (posY > y_safe[0] && posY < y_safe[1]) {
            posY = centerY;
        }
        else {
            posY = moveTowards(posY, centerY, y_box_width);

            //Add a scaling factor on downwards motion to compensate for reduced range of motion
            if (posY < centerY) {
                var min_scale = 2;
                var max_scale = 4.5;
                var y_max = centerY - y_box_width;
                var scale = min_scale + (max_scale - min_scale) * (posY - y_max)/(-y_max);
                posY *= 1/scale;
            }
        }

        robot.moveMouse(mouse.x + (posX * sensitivityX), mouse.y + ((centerY - posY) * sensitivityY));

        //Check for a trigger pull gesture
        if (!hand.indexFinger.extended || !hand.middleFinger.extended) {
            if (!bangEventEmitted) {
                console.log('BANG!!!');
                robot.mouseClick();
                bangEventEmitted = true;
            }
        } else {
            bangEventEmitted = false;
        }
    });
});

<|endoftext|>


<commit_before>const http = require("http");
const url  = require("url");
const fs   = require("fs");
const path = require("path");
const zlib = require("zlib");
const c = require('child_process');

const port  = parseInt(process.argv[2] || 8888, 10);
const server = require('./servlet.js');

const base = './';

// build menu
const files = fs.readdirSync(base);
// 对文件夹更改进行排序
files.sort(function(a, b) {
  let astat = fs.lstatSync(base + a);
  let bstat = fs.lstatSync(base + b);

  return bstat.mtime - astat.mtime;
});

const pagePreFix = '';
const sourcePrefix = 'https://github.com/vincc/h5coach/tree/master/';

let html = fs.readFileSync('./index.html').toString();

let ul_html = '
';

const mlList = [
    'src'
    ];

// 添加列表内容
mlList.forEach(function(f) {
    let npath = path.join(base, f);
    let array = findHtml(npath);

  array.sort(function(a, b) {
        return b[2].mtime - a[2].mtime
  });

  if (array.length > 0) {

        const filedir = sourcePrefix + 'assets/' + f;
        ul_html += `<p><a href='${filedir}' target='_blank' title='查看源码'>${f}</a></p><ul class='list'>`;

        array.forEach(function(p) {
            const title = /<title>(.*)<\/title>/.test(fs.readFileSync(p[0]).toString()) ? RegExp.$1 : 'Document';
            const tiAtl = /<metac>(.*)<\/metac>/.test(fs.readFileSync(p[0]).toString()) ? RegExp.$1 : 'Null';

            ul_html += `<li><a href='${p[0]}' target='_blank' class='' title='${tiAtl}'>${title}</a></li>`;
        });

        ul_html += '
';
    }
});

ul_html += '
';
html = html.replace(/()[\s\S]*?(<\/body>)/, '$1' + ul_html + '$2');

fs.writeFileSync('./index.html', html);

//打开浏览器
let cmd = null;
if (process.platform == 'win32') {
    cmd = 'start';
} else if (process.platform == 'linux') {
    cmd = 'xdg-open';
} else if (process.platform == 'darwin') {
    cmd = 'open';
}

cmd && c.exec (cmd + ' ' + 'http://localhost:' + port + '/' );

function findHtml(folder_path, collector) {
    collector = collector || [];

    let files = fs.readdirSync(folder_path += '/');
    let npath, stat;

    files.forEach(function(f) {
    npath = folder_path + f;
    stat = fs.lstatSync(npath);

    if (stat.isDirectory()) {
        findHtml(npath, collector);
        return;
    }

    if (/^[^_].+\.html/.test(f)) {
        collector.push([npath, f, stat]);
    }
  });

  return collector;
}<commit_msg># 修改main 路径引用<commit_after>#!/usr/bin/env node

const   http = require("http"),
        url  = require("url"),
        fs   = require("fs"),
        path = require("path"),
        zlib = require("zlib"),
        c = require('child_process');

const port  = parseInt(process.argv[2] || 8888, 10);
const server = require('./servlet.js');

const base = './';

// build menu
const files = fs.readdirSync(base);
// 对文件夹更改进行排序
files.sort(function(a, b) {
  let astat = fs.lstatSync(base + a);
  let bstat = fs.lstatSync(base + b);

  return bstat.mtime - astat.mtime;
});

const pagePreFix = '';
const sourcePrefix = 'https://github.com/vincc/h5coach/tree/master/';

let html = fs.readFileSync('./index.html').toString();

let ul_html = '
';

const mlList = [
    'src'
    ];

// 添加列表内容
mlList.forEach(function(f) {
    let npath = path.join(base, f);
    let array = findHtml(npath);

  array.sort(function(a, b) {
        return b[2].mtime - a[2].mtime
  });

  if (array.length > 0) {

        const filedir = sourcePrefix + 'assets/' + f;
        ul_html += `<p><a href='${filedir}' target='_blank' title='查看源码'>${f}</a></p><ul class='list'>`;

        array.forEach(function(p) {
            const title = /<title>(.*)<\/title>/.test(fs.readFileSync(p[0]).toString()) ? RegExp.$1 : 'Document';
            const tiAtl = /<metac>(.*)<\/metac>/.test(fs.readFileSync(p[0]).toString()) ? RegExp.$1 : 'Null';

            ul_html += `<li><a href='${p[0]}' target='_blank' class='' title='${tiAtl}'>${title}</a></li>`;
        });

        ul_html += '
';
    }
});

ul_html += '
';
html = html.replace(/()[\s\S]*?(<\/body>)/, '$1' + ul_html + '$2');

fs.writeFileSync('./index.html', html);

//打开浏览器
let cmd = null;
if (process.platform == 'win32') {
    cmd = 'start';
} else if (process.platform == 'linux') {
    cmd = 'xdg-open';
} else if (process.platform == 'darwin') {
    cmd = 'open';
}

cmd && c.exec (cmd + ' ' + 'http://localhost:' + port + '/' );

function findHtml(folder_path, collector) {
    collector = collector || [];

    let files = fs.readdirSync(folder_path += '/');
    let npath, stat;

    files.forEach(function(f) {
    npath = folder_path + f;
    stat = fs.lstatSync(npath);

    if (stat.isDirectory()) {
        findHtml(npath, collector);
        return;
    }

    if (/^[^_].+\.html/.test(f)) {
        collector.push([npath, f, stat]);
    }
  });

  return collector;
}<|endoftext|>


<commit_before>"use strict";
var TXT_LENGTH = 50;
var HINT_DELAY = 1500;

var hint = function() {
    var storedKeyDOM;
    var timer;

    var reset = function() {
        window.clearTimeout(timer);
        if (typeof(storedKeyDOM) !== "undefined") {
            storedKeyDOM.classList.remove("hint");
        }
    };

    var set = function(keyDOM) {
        reset();
        storedKeyDOM = keyDOM;
        timer = window.setTimeout(function() {
            storedKeyDOM.classList.add("hint");
        }, HINT_DELAY);
    };

    return {
        reset: reset,
        set: set
    };
}();

var config = function() {
    var c = {
        active: undefined,
        data: {}
    };

    function storedConfigs() {
        var result = [];
        for (var d in c.data) {
            result.push(d);
        };
        return result;
    }

    function setActiveConfig(configName) {
        if (c.data[configName] === undefined) {
            console.log("Error: Unknown config name: " + configName);
            return false;
        };
        c.active = configName;
        return true;
    }

    function addConfig(keyboard, language, layout) {
        var orderdKeys = [];
        var rankedKeys = [];
        var name = keyboard + "_" + layout + " (" + language + ")";
        var keyConfig = keyboards[keyboard].layout[language][layout];
        var order = keyboards[keyboard].ordering;

        for (var o in order) {
            for (var l in keyConfig) {
                if (keyConfig[l] === order[o] &&
                    languages[language].indexOf(l) !== -1
                ) {
                    orderdKeys.push(l);
                }
            }
        }

        for (var i = 0; i < 4; i++) {
            rankedKeys.push({
                "key": orderdKeys[0],
                "points": 0,
                "count": 0
            });
            orderdKeys.splice(0, 1);
        }

        c.active = name;
        c.data[name] = {
            keyboard: keyboard,
            language: language,
            layout: layout,
            rankedKeys: rankedKeys,
            orderdKeys: orderdKeys
        };
        save();
    }

    function updateKeys(rankedKeys, orderdKeys) {
        c.data[c.active].rankedKeys = rankedKeys;
        c.data[c.active].orderdKeys = orderdKeys;
        save();
    }

    function get(key) {
        return c.data[c.active][key];
    }

    function save() {
        localStorage.setItem("configs", JSON.stringify(c));
    }

    function isNew() {
        if (c.active === undefined) {
            return true;
        };
        return false;
    }

    if (window.localStorage.configs !== undefined) {
        c = JSON.parse(window.localStorage.configs);
    };

    return {
        isNew: isNew,
        addConfig: addConfig,
        updateKeys: updateKeys,
        get: get,
        save: save,
    }
}();

function exercise() {
    var lessonString;
    var pos;
    var error;
    var timeStamp;
    var keyLogging = {};
    var rankedKeys = config.get("rankedKeys");
    var orderdKeys = config.get("orderdKeys");

    var txtDone = document.getElementById('txtDone');
    var txtNow = document.getElementById('txtNow');
    var txtNext = document.getElementById('txtNext');

    keyboard.setKeyboard(config.get("keyboard"));
    newLesson();

    window.onkeypress = function(event){
        checkInput(event);
    };

    function updateView() {
        txtDone.innerHTML = lessonString.substring(0, pos);
        txtNow.innerHTML = lessonString[pos] || "";
        txtNow.classList.remove("error");
        txtNext.innerHTML = lessonString.substring(pos+1, TXT_LENGTH);

        if (pos === 0) {
            var buffer = "";
            rankedKeys.forEach(function(item, _) {
                buffer += '';
                buffer += item.key;
                buffer += '';
            });
            document.getElementById("keysRanked").innerHTML = buffer;
            buffer = "";
            orderdKeys.forEach(function(item, _) {
                buffer += '';
                buffer += item;
                buffer += '';
            });
            document.getElementById("keysNext").innerHTML = buffer;
        }
    }

    function newLesson() {
        var keys = [];

        keyLogging = {};
        pos = 0;

        var space = 4 + Math.floor(Math.random() * 4);
        if (rankedKeys[rankedKeys.length-1].points > 1500) {
            rankedKeys.push({
               "key": orderdKeys[0],
               "points": 0,
               "count": 0
            });
            orderdKeys.splice(0, 1);
            config.updateKeys(rankedKeys, orderdKeys);
        };

        rankedKeys.forEach(function(element) {
            keys.push(element.key);
        });

        lessonString = generateList(config.get("language"), keys, TXT_LENGTH);
        updateView();
        hint.set(keyboard.getDOM(lessonString[pos].toLowerCase()));
    }

    function checkInput(event) {
        if (lessonString[pos] === String.fromCharCode(event.which)) {
            var timeStampEnd = new Date().getTime();
            if (pos !== 0) {
                var key = lessonString[pos];
                if (typeof(keyLogging[key]) === "undefined") {
                    keyLogging[key] = {count: 0, time: 0, err: 0};
                }
                keyLogging[key].count++;
                keyLogging[key].time += timeStampEnd - timeStamp;
                keyLogging[key].err += error;
            }
            pos++;
            if (pos < TXT_LENGTH) {
                hint.set(keyboard.getDOM(lessonString[pos].toLowerCase()));
            } else {
                calculatePoints();
                hint.reset();
                newLesson();
            }
            updateView();
            timeStamp = new Date().getTime();
            error = false;
        } else {
            txtNow.classList.add("error");
            error = true;
        }
    }

    function calculatePoints() {
        rankedKeys.forEach(function(item, index) {
            var k = item.key;
            if (typeof(keyLogging[k]) === "undefined") {
                return;
            }
            var speed = 2000 - (keyLogging[k].time / keyLogging[k].count);
            if (speed < 0) {
                speed = 0;
            }
            var errors = (1 - (keyLogging[k].err / keyLogging[k].count));
            var points = (speed*errors);
            if (item.points !== 0) {
                points += item.points * 2;
                points /= 3;
            }
            rankedKeys[index].points = points.toFixed(2);
            rankedKeys[index].count += keyLogging[k].count;
        });
        rankedKeys.sort(function(a, b){
            return b.points - a.points;
        });
        config.updateKeys(rankedKeys, orderdKeys);
    }
}

var keyboard = function(){
    var keyDOMs = {};

    function setKeyboard(){
        document.getElementById("keyboard").innerHTML =
            keyboards[config.get("keyboard")].svg;
        var layout = keyboards[config.get("keyboard")]
            .layout[config.get("language")]
            [config.get("layout")];
        for (var l in layout) {
            keyDOMs[l] = document.getElementById(layout[l]);
            document.getElementById(layout[l] + 'K').innerHTML = l.toUpperCase();
            if (l == 'ß') {
                document.getElementById(layout[l] + 'K').innerHTML = l.toLowerCase();
            };
        }
    }

    function getDOM(key) {
        return keyDOMs[key];
    }

    return {
        setKeyboard: setKeyboard,
        getDOM: getDOM
    };
}();

function setupLanguage() {
    var setupLanguage = document.getElementById("setupLanguage");
    var selectLanguage = document.getElementById("selectLanguage");
    var startLayoutConfig = document.getElementById("startLayoutConfig");

    setupLanguage.style.display = "block";
    for (var l in languages) {
        var option = document.createElement("option");
        option.text = l;
        selectLanguage.add(option);
    }

    startLayoutConfig.onclick = function() {
        setupOwnLayout(selectKeyboard.value, selectLanguage.value);
        setupLanguage.style.display = "none";
    };
}

function setup() {
    var setup = document.getElementById("setup");
    var setupLayout = document.getElementById("setupLayout");
    var saveConfig = document.getElementById("saveConfig");
    var selectKeyboard = document.getElementById("selectKeyboard");
    var selectLayout = document.getElementById("selectLayout");
    var ownLayout = document.getElementById("ownLayout");
    var preview = document.getElementById("preview");

    setup.style.display = "block";
    updateKeyboards();

    selectKeyboard.onchange = function(event) {
        updateLayout(event.target.value);
        preview.innerHTML = keyboards[event.target.value].svg;
        selectLayout.disabled = false;
        //ownLayout.disabled = false;
    };

    selectLayout.onchange = function() {
        saveConfig.disabled = false;
    };

    ownLayout.onclick = function() {
        preview.innerHTML = "";
        setup.style.display = "none";
        setupLanguage();
    };

    saveConfig.onclick = function() {
        save();
    };

    function updateKeyboards() {
        selectKeyboard.innerHTML = "";
        for (var k in keyboards) {
            var option = document.createElement("option");
            option.text = k;
            selectKeyboard.add(option);
        }
        selectKeyboard.selectedIndex = -1;
    }

    function updateLayout(keyboardType) {
        selectLayout.innerHTML = "";
        for (var language in keyboards[keyboardType].layout) {
            for (var layout in keyboards[keyboardType].layout[language]) {
                var option = document.createElement("option");
                option.text = layout + " (" + language + ")";
                option.value = JSON.stringify({layout, language});
                selectLayout.add(option);
            };
        };
        selectLayout.selectedIndex = -1;
        selectLayout.disabled = true;
    }

    function save() {
        var layout = JSON.parse(selectLayout.value);
        config.addConfig(selectKeyboard.value,
                         layout.language,
                         layout.layout);
        preview.innerHTML = "";
        setup.style.display = "none";
        exercise();
    }
}

function showWelcome() {
    var welcome = document.getElementById("welcome");
    var startSetup = document.getElementById("startSetup");

    welcome.style.display = "block";
    startSetup.onclick = function() {
        welcome.style.display = "none";
        setup();
    };
}

function setupOwnLayout(keyboard, language) {
    var setupLayout = document.getElementById("setupLayout");
    var activeId;
    var letters;
    var mapping = {};
    var defaultLetters = [".", ",", "'"];

    function setKey(event) {
        var key = String.fromCharCode(event.which).toLowerCase();

        if (activeId === undefined) {
            return;
        };
        if (mapping.hasOwnProperty(key) === false) {
            return;
        };
        if (mapping[key] !== undefined) {
            document.getElementById(mapping[key] + 'K').innerHTML = "";
        };
        for (var k in mapping) {
            if (mapping[k] === activeId) {
                mapping[k] = undefined;
            };
        }
        document.getElementById(activeId + 'K').innerHTML = key.toUpperCase();
        if (key == 'ß') {
            document.getElementById(activeId + 'K').innerHTML = key.toLowerCase();
        };
        mapping[key] = activeId;
        updateView();
        event.preventDefault();
    }

    function updateView() {
        var undefKeys = [];

        for (var k in mapping) {
            if (mapping[k] === undefined) {
                undefKeys.push('');
                undefKeys.push(k);
                undefKeys.push('');
            };
        };
        document.getElementById("letters").innerHTML = undefKeys.join("");
        for (var k in mapping) {
            if (mapping[k] === undefined) {
                return;
            };
        };

    }

    function save() {
        document.removeEventListener("keypress", setKey);
        keyboards[keyboard].ordering.forEach(function(element) {
            document.getElementById(element).onclick = function(){};
            document.getElementById("setupLayoutSave").removeEventListener("click", save);
        });
    }

    letters = languages[language];
    letters = letters.concat(defaultLetters);
    letters.forEach(function(letter) {
        mapping[letter] = undefined;
    });

    setupLayout.style.display = "block";

    document.getElementById("setupLayoutKeyboard").innerHTML =
        keyboards[keyboard].svg;
    keyboards[keyboard].ordering.forEach(function(element) {
        document.getElementById(element).onclick = function(){
            if (activeId !== undefined) {
                document.getElementById(activeId).classList.remove("hint");
            };
            activeId = element;
            document.getElementById(activeId).classList.add("hint");
        };
    });

    document.getElementById("setupLayoutSave").addEventListener("click", save);
    document.addEventListener("keypress", setKey);

    updateView();
};

function init() {
    //window.localStorage.clear();

    // drop backspace
    document.addEventListener("keydown", function(event) {
        if (event.which === 8) {
           event.preventDefault();
        }
    });

    if (config.isNew() === true) {
        showWelcome();
    } else {
        exercise();
    }
}
<commit_msg>make the training a bit easier<commit_after>"use strict";
var TXT_LENGTH = 50;
var HINT_DELAY = 1500;

var hint = function() {
    var storedKeyDOM;
    var timer;

    var reset = function() {
        window.clearTimeout(timer);
        if (typeof(storedKeyDOM) !== "undefined") {
            storedKeyDOM.classList.remove("hint");
        }
    };

    var set = function(keyDOM) {
        reset();
        storedKeyDOM = keyDOM;
        timer = window.setTimeout(function() {
            storedKeyDOM.classList.add("hint");
        }, HINT_DELAY);
    };

    return {
        reset: reset,
        set: set
    };
}();

var config = function() {
    var c = {
        active: undefined,
        data: {}
    };

    function storedConfigs() {
        var result = [];
        for (var d in c.data) {
            result.push(d);
        };
        return result;
    }

    function setActiveConfig(configName) {
        if (c.data[configName] === undefined) {
            console.log("Error: Unknown config name: " + configName);
            return false;
        };
        c.active = configName;
        return true;
    }

    function addConfig(keyboard, language, layout) {
        var orderdKeys = [];
        var rankedKeys = [];
        var name = keyboard + "_" + layout + " (" + language + ")";
        var keyConfig = keyboards[keyboard].layout[language][layout];
        var order = keyboards[keyboard].ordering;

        for (var o in order) {
            for (var l in keyConfig) {
                if (keyConfig[l] === order[o] &&
                    languages[language].indexOf(l) !== -1
                ) {
                    orderdKeys.push(l);
                }
            }
        }

        for (var i = 0; i < 4; i++) {
            rankedKeys.push({
                "key": orderdKeys[0],
                "points": 0,
                "count": 0
            });
            orderdKeys.splice(0, 1);
        }

        c.active = name;
        c.data[name] = {
            keyboard: keyboard,
            language: language,
            layout: layout,
            rankedKeys: rankedKeys,
            orderdKeys: orderdKeys
        };
        save();
    }

    function updateKeys(rankedKeys, orderdKeys) {
        c.data[c.active].rankedKeys = rankedKeys;
        c.data[c.active].orderdKeys = orderdKeys;
        save();
    }

    function get(key) {
        return c.data[c.active][key];
    }

    function save() {
        localStorage.setItem("configs", JSON.stringify(c));
    }

    function isNew() {
        if (c.active === undefined) {
            return true;
        };
        return false;
    }

    if (window.localStorage.configs !== undefined) {
        c = JSON.parse(window.localStorage.configs);
    };

    return {
        isNew: isNew,
        addConfig: addConfig,
        updateKeys: updateKeys,
        get: get,
        save: save,
    }
}();

function exercise() {
    var lessonString;
    var pos;
    var error;
    var timeStamp;
    var keyLogging = {};
    var rankedKeys = config.get("rankedKeys");
    var orderdKeys = config.get("orderdKeys");

    var txtDone = document.getElementById('txtDone');
    var txtNow = document.getElementById('txtNow');
    var txtNext = document.getElementById('txtNext');

    keyboard.setKeyboard(config.get("keyboard"));
    newLesson();

    window.onkeypress = function(event){
        checkInput(event);
    };

    function updateView() {
        txtDone.innerHTML = lessonString.substring(0, pos);
        txtNow.innerHTML = lessonString[pos] || "";
        txtNow.classList.remove("error");
        txtNext.innerHTML = lessonString.substring(pos+1, TXT_LENGTH);

        if (pos === 0) {
            var buffer = "";
            rankedKeys.forEach(function(item, _) {
                buffer += '';
                buffer += item.key;
                buffer += '';
            });
            document.getElementById("keysRanked").innerHTML = buffer;
            buffer = "";
            orderdKeys.forEach(function(item, _) {
                buffer += '';
                buffer += item;
                buffer += '';
            });
            document.getElementById("keysNext").innerHTML = buffer;
        }
    }

    function newLesson() {
        var keys = [];

        keyLogging = {};
        pos = 0;

        var space = 4 + Math.floor(Math.random() * 4);
        if (rankedKeys[rankedKeys.length-1].points > 1500) {
            rankedKeys.push({
               "key": orderdKeys[0],
               "points": 0,
               "count": 0
            });
            orderdKeys.splice(0, 1);
            config.updateKeys(rankedKeys, orderdKeys);
        };

        rankedKeys.forEach(function(element) {
            keys.push(element.key);
        });

        lessonString = generateList(config.get("language"), keys, TXT_LENGTH);
        updateView();
        hint.set(keyboard.getDOM(lessonString[pos].toLowerCase()));
    }

    function checkInput(event) {
        if (lessonString[pos] === String.fromCharCode(event.which)) {
            var timeStampEnd = new Date().getTime();
            if (pos !== 0) {
                var key = lessonString[pos];
                if (typeof(keyLogging[key]) === "undefined") {
                    keyLogging[key] = {count: 0, time: 0, err: 0};
                }
                keyLogging[key].count++;
                keyLogging[key].time += timeStampEnd - timeStamp;
                keyLogging[key].err += error;
            }
            pos++;
            if (pos < TXT_LENGTH) {
                hint.set(keyboard.getDOM(lessonString[pos].toLowerCase()));
            } else {
                calculatePoints();
                hint.reset();
                newLesson();
            }
            updateView();
            timeStamp = new Date().getTime();
            error = false;
        } else {
            txtNow.classList.add("error");
            error = true;
        }
    }

    function calculatePoints() {
        rankedKeys.forEach(function(item, index) {
            var k = item.key;
            if (typeof(keyLogging[k]) === "undefined") {
                return;
            }
            var speed = 2500 - (keyLogging[k].time / keyLogging[k].count);
            if (speed < 0) {
                speed = 0;
            }
            var errors = (1 - (keyLogging[k].err / keyLogging[k].count));
            var points = (speed*errors);
            if (item.points !== 0) {
                points += item.points * 2;
                points /= 3;
            }
            rankedKeys[index].points = points.toFixed(2);
            rankedKeys[index].count += keyLogging[k].count;
        });
        rankedKeys.sort(function(a, b){
            return b.points - a.points;
        });
        config.updateKeys(rankedKeys, orderdKeys);
    }
}

var keyboard = function(){
    var keyDOMs = {};

    function setKeyboard(){
        document.getElementById("keyboard").innerHTML =
            keyboards[config.get("keyboard")].svg;
        var layout = keyboards[config.get("keyboard")]
            .layout[config.get("language")]
            [config.get("layout")];
        for (var l in layout) {
            keyDOMs[l] = document.getElementById(layout[l]);
            document.getElementById(layout[l] + 'K').innerHTML = l.toUpperCase();
            if (l == 'ß') {
                document.getElementById(layout[l] + 'K').innerHTML = l.toLowerCase();
            };
        }
    }

    function getDOM(key) {
        return keyDOMs[key];
    }

    return {
        setKeyboard: setKeyboard,
        getDOM: getDOM
    };
}();

function setupLanguage() {
    var setupLanguage = document.getElementById("setupLanguage");
    var selectLanguage = document.getElementById("selectLanguage");
    var startLayoutConfig = document.getElementById("startLayoutConfig");

    setupLanguage.style.display = "block";
    for (var l in languages) {
        var option = document.createElement("option");
        option.text = l;
        selectLanguage.add(option);
    }

    startLayoutConfig.onclick = function() {
        setupOwnLayout(selectKeyboard.value, selectLanguage.value);
        setupLanguage.style.display = "none";
    };
}

function setup() {
    var setup = document.getElementById("setup");
    var setupLayout = document.getElementById("setupLayout");
    var saveConfig = document.getElementById("saveConfig");
    var selectKeyboard = document.getElementById("selectKeyboard");
    var selectLayout = document.getElementById("selectLayout");
    var ownLayout = document.getElementById("ownLayout");
    var preview = document.getElementById("preview");

    setup.style.display = "block";
    updateKeyboards();

    selectKeyboard.onchange = function(event) {
        updateLayout(event.target.value);
        preview.innerHTML = keyboards[event.target.value].svg;
        selectLayout.disabled = false;
        //ownLayout.disabled = false;
    };

    selectLayout.onchange = function() {
        saveConfig.disabled = false;
    };

    ownLayout.onclick = function() {
        preview.innerHTML = "";
        setup.style.display = "none";
        setupLanguage();
    };

    saveConfig.onclick = function() {
        save();
    };

    function updateKeyboards() {
        selectKeyboard.innerHTML = "";
        for (var k in keyboards) {
            var option = document.createElement("option");
            option.text = k;
            selectKeyboard.add(option);
        }
        selectKeyboard.selectedIndex = -1;
    }

    function updateLayout(keyboardType) {
        selectLayout.innerHTML = "";
        for (var language in keyboards[keyboardType].layout) {
            for (var layout in keyboards[keyboardType].layout[language]) {
                var option = document.createElement("option");
                option.text = layout + " (" + language + ")";
                option.value = JSON.stringify({layout, language});
                selectLayout.add(option);
            };
        };
        selectLayout.selectedIndex = -1;
        selectLayout.disabled = true;
    }

    function save() {
        var layout = JSON.parse(selectLayout.value);
        config.addConfig(selectKeyboard.value,
                         layout.language,
                         layout.layout);
        preview.innerHTML = "";
        setup.style.display = "none";
        exercise();
    }
}

function showWelcome() {
    var welcome = document.getElementById("welcome");
    var startSetup = document.getElementById("startSetup");

    welcome.style.display = "block";
    startSetup.onclick = function() {
        welcome.style.display = "none";
        setup();
    };
}

function setupOwnLayout(keyboard, language) {
    var setupLayout = document.getElementById("setupLayout");
    var activeId;
    var letters;
    var mapping = {};
    var defaultLetters = [".", ",", "'"];

    function setKey(event) {
        var key = String.fromCharCode(event.which).toLowerCase();

        if (activeId === undefined) {
            return;
        };
        if (mapping.hasOwnProperty(key) === false) {
            return;
        };
        if (mapping[key] !== undefined) {
            document.getElementById(mapping[key] + 'K').innerHTML = "";
        };
        for (var k in mapping) {
            if (mapping[k] === activeId) {
                mapping[k] = undefined;
            };
        }
        document.getElementById(activeId + 'K').innerHTML = key.toUpperCase();
        if (key == 'ß') {
            document.getElementById(activeId + 'K').innerHTML = key.toLowerCase();
        };
        mapping[key] = activeId;
        updateView();
        event.preventDefault();
    }

    function updateView() {
        var undefKeys = [];

        for (var k in mapping) {
            if (mapping[k] === undefined) {
                undefKeys.push('');
                undefKeys.push(k);
                undefKeys.push('');
            };
        };
        document.getElementById("letters").innerHTML = undefKeys.join("");
        for (var k in mapping) {
            if (mapping[k] === undefined) {
                return;
            };
        };

    }

    function save() {
        document.removeEventListener("keypress", setKey);
        keyboards[keyboard].ordering.forEach(function(element) {
            document.getElementById(element).onclick = function(){};
            document.getElementById("setupLayoutSave").removeEventListener("click", save);
        });
    }

    letters = languages[language];
    letters = letters.concat(defaultLetters);
    letters.forEach(function(letter) {
        mapping[letter] = undefined;
    });

    setupLayout.style.display = "block";

    document.getElementById("setupLayoutKeyboard").innerHTML =
        keyboards[keyboard].svg;
    keyboards[keyboard].ordering.forEach(function(element) {
        document.getElementById(element).onclick = function(){
            if (activeId !== undefined) {
                document.getElementById(activeId).classList.remove("hint");
            };
            activeId = element;
            document.getElementById(activeId).classList.add("hint");
        };
    });

    document.getElementById("setupLayoutSave").addEventListener("click", save);
    document.addEventListener("keypress", setKey);

    updateView();
};

function init() {
    //window.localStorage.clear();

    // drop backspace
    document.addEventListener("keydown", function(event) {
        if (event.which === 8) {
           event.preventDefault();
        }
    });

    if (config.isNew() === true) {
        showWelcome();
    } else {
        exercise();
    }
}
<|endoftext|>


<commit_before>/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define, brackets, $ */

define(function (require, exports, module)
{
    "use strict";

	// Load brackets modules
	var ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
		CommandManager = brackets.getModule("command/CommandManager");

	// Load stylesheet
	ExtensionUtils.loadStyleSheet(module, "brackets-notifications.css");

	// All notifications are appended to this container
	$(".main-view .content #editor-holder").append("

");

	// Adds the notification to the notifications container
	function constructNotification(input)
	{
		console.log("Construct Notification");

		// ReturnData contains the notification element and the action elements for binding events to
		var returnData = {};

		// Define defaults
        var defaults =
        {
            title:"",
            message:"",
            time:2000
        }
        // Merge missing defaults into input
        for(var prop in defaults)
        {
            input[prop] = input[prop] !== undefined? input[prop] : defaults[prop];
        }

		// Contruct and append notification
		var notification = $("

"+input.title+"

"+input.message+"

");
        if(input.actions !== undefined)
		{
			var actions = $("

");
			returnData.actions = [];
			for(var i=0; i<input.actions.length; i++)
			{
				var action = $("
"+input.actions[i].label+"
");
				if(action[i].callback !== undefined)
				{
					action.click(input.actions[i].callback);
				}
				actions.append(action);
				returnData.actions[input.actions[i]] = action;
			}
			notification.append(actions);
		}
		notification.click(clickHandler);
		$("#notifications-container").append(notification);
        returnData.notification = notification;

		// Fade if time is set
		if(input.time !== 0)
        {
            notification.delay(input.time).fadeOut();
        }

		return returnData;
	}

    // First, register a command - a UI-less object associating an id to a handler
    var NOTIFICATION_COMMAND_ID = "notifications.notification";   // package-style naming to avoid collisions      TODO: Check whether this is not crazy naming..
    CommandManager.register("Send Notification notification", NOTIFICATION_COMMAND_ID, constructNotification);

    // Handle clicks.
    function clickHandler(e)
    {
        $(this).fadeOut();
    }
});
<commit_msg>Let's name all the things similarly, that won't go wrong..<commit_after>/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 50 */
/*global define, brackets, $ */

define(function (require, exports, module)
{
    "use strict";

	// Load brackets modules
	var ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
		CommandManager = brackets.getModule("command/CommandManager");

	// Load stylesheet
	ExtensionUtils.loadStyleSheet(module, "brackets-notifications.css");

	// All notifications are appended to this container
	$(".main-view .content #editor-holder").append("

");

	// Adds the notification to the notifications container
	function constructNotification(input)
	{
		console.log("Construct Notification");

		// ReturnData contains the notification element and the action elements for binding events to
		var returnData = {};

		// Define defaults
        var defaults =
        {
            title:"",
            message:"",
            time:2000
        }
        // Merge missing defaults into input
        for(var prop in defaults)
        {
            input[prop] = input[prop] !== undefined? input[prop] : defaults[prop];
        }

		// Contruct and append notification
		var notification = $("

"+input.title+"

"+input.message+"

");
        if(input.actions !== undefined)
		{
			var actions = $("

");
			returnData.actions = [];
			for(var i=0; i<input.actions.length; i++)
			{
				var action = $("
"+input.actions[i].label+"
");
				if(input.actions[i].callback !== undefined)
				{
					action.click(input.actions[i].callback);
				}
				actions.append(action);
				returnData.actions[input.actions[i]] = action;
			}
			notification.append(actions);
		}
		notification.click(clickHandler);
		$("#notifications-container").append(notification);
        returnData.notification = notification;

		// Fade if time is set
		if(input.time !== 0)
        {
            notification.delay(input.time).fadeOut();
        }

		return returnData;
	}

    // First, register a command - a UI-less object associating an id to a handler
    var NOTIFICATION_COMMAND_ID = "notifications.notification";   // package-style naming to avoid collisions      TODO: Check whether this is not crazy naming..
    CommandManager.register("Send Notification notification", NOTIFICATION_COMMAND_ID, constructNotification);

    // Handle clicks.
    function clickHandler(e)
    {
        $(this).fadeOut();
    }
});
<|endoftext|>


<commit_before>// import modules
require('prototype.spawn')();
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
var roleBuilder = require('role.builder');
var roleRepairer = require('role.repairer');
var roleWallRepairer = require('role.wallRepairer');

module.exports.loop = function () {

    var harvesters = [];

    // check for memory entries of died creeps by iterating over Memory.creeps
    for (let name in Memory.creeps) {
        // and checking if the creep is still alive
        if (Game.creeps[name] == undefined) {
            // if not, delete the memory entry
            delete Memory.creeps[name];
        }
    }

    // for every creep name in Game.creeps
    for (let name in Game.creeps) {
        // get the creep object
        var creep = Game.creeps[name];

        // if creep is harvester, call harvester script
        if (creep.memory.role == 'harvester') {
            roleHarvester.run(creep);
            harvesters.push(Game.creeps[i]);
        }
        // if creep is upgrader, call upgrader script
        else if (creep.memory.role == 'upgrader') {
            roleUpgrader.run(creep);
        }
        // if creep is builder, call builder script
        else if (creep.memory.role == 'builder') {
            roleBuilder.run(creep);
        }
        // if creep is repairer, call repairer script
        else if (creep.memory.role == 'repairer') {
            roleRepairer.run(creep);
        }
        // if creep is wallRepairer, call wallRepairer script
        else if (creep.memory.role == 'wallRepairer') {
            roleWallRepairer.run(creep);
        }
    }

    var towers = Game.rooms.find(FIND_STRUCTURES, {
        filter: (s) => s.structureType == STRUCTURE_TOWER
    });
    for (let tower of towers) {
        var target = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
        if (target != undefined) {
            tower.attack(target);
        }
    }

    // setup some minimum numbers for different roles
    var minimumNumberOfHarvesters = 4;;
    var minimumNumberOfUpgraders = 2;
    var minimumNumberOfBuilders = 4;
    var minimumNumberOfRepairers = 1;
    var minimumNumberOfWallRepairers = 1;

    // count the number of creeps alive for each role
    // _.sum will count the number of properties in Game.creeps filtered by the
    //  arrow function, which checks for the creep being a harvester
    var numberOfHarvesters = _.sum(Game.creeps, (c) => c.memory.role == 'harvester');
    var numberOfUpgraders = _.sum(Game.creeps, (c) => c.memory.role == 'upgrader');
    var numberOfBuilders = _.sum(Game.creeps, (c) => c.memory.role == 'builder');
    var numberOfRepairers = _.sum(Game.creeps, (c) => c.memory.role == 'repairer');
    var numberOfWallRepairers = _.sum(Game.creeps, (c) => c.memory.role == 'wallRepairer');

    var energy = Game.spawns.Spawn1.room.energyCapacityAvailable;
    var name = undefined;

    // if not enough harvesters
    if (numberOfHarvesters < minimumNumberOfHarvesters) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'harvester');

        // if spawning failed and we have no harvesters left
        if (name == ERR_NOT_ENOUGH_ENERGY && numberOfHarvesters == 0) {
            // spawn one with what is available
            name = Game.spawns.Spawn1.createCustomCreep(
                Game.spawns.Spawn1.room.energyAvailable, 'harvester');
        }
    }
    // if not enough upgraders
    else if (numberOfUpgraders < minimumNumberOfUpgraders) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'upgrader');
    }
    // if not enough repairers
    else if (numberOfRepairers < minimumNumberOfRepairers) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'repairer');
    }
    // if not enough builders
    else if (numberOfBuilders < minimumNumberOfBuilders) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'builder');
    }
    // if not enough wallRepairers
    else if (numberOfWallRepairers < minimumNumberOfWallRepairers) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'wallRepairer');
    }
    else {
        // else try to spawn a builder
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'builder');
    }

    // print name to console if spawning was a success
    // name > 0 would not work since string > 0 returns false
    if (!(name < 0)) {
        console.log("Spawned new creep: " + name);
    }
};<commit_msg>no message<commit_after>// import modules
require('prototype.spawn')();
var roleHarvester = require('role.harvester');
var roleUpgrader = require('role.upgrader');
var roleBuilder = require('role.builder');
var roleRepairer = require('role.repairer');
var roleWallRepairer = require('role.wallRepairer');

module.exports.loop = function () {

    var harvesters = [];

    // check for memory entries of died creeps by iterating over Memory.creeps
    for (let name in Memory.creeps) {
        // and checking if the creep is still alive
        if (Game.creeps[name] == undefined) {
            // if not, delete the memory entry
            delete Memory.creeps[name];
        }
    }

    // for every creep name in Game.creeps
    for (let name in Game.creeps) {
        // get the creep object
        var creep = Game.creeps[name];

        // if creep is harvester, call harvester script
        if (creep.memory.role == 'harvester') {
            roleHarvester.run(creep);
            harvesters.push(creep);
        }
        // if creep is upgrader, call upgrader script
        else if (creep.memory.role == 'upgrader') {
            roleUpgrader.run(creep);
        }
        // if creep is builder, call builder script
        else if (creep.memory.role == 'builder') {
            roleBuilder.run(creep);
        }
        // if creep is repairer, call repairer script
        else if (creep.memory.role == 'repairer') {
            roleRepairer.run(creep);
        }
        // if creep is wallRepairer, call wallRepairer script
        else if (creep.memory.role == 'wallRepairer') {
            roleWallRepairer.run(creep);
        }
    }

    var towers = Game.rooms.find(FIND_STRUCTURES, {
        filter: (s) => s.structureType == STRUCTURE_TOWER
    });
    for (let tower of towers) {
        var target = tower.pos.findClosestByRange(FIND_HOSTILE_CREEPS);
        if (target != undefined) {
            tower.attack(target);
        }
    }

    // setup some minimum numbers for different roles
    var minimumNumberOfHarvesters = 4;;
    var minimumNumberOfUpgraders = 2;
    var minimumNumberOfBuilders = 4;
    var minimumNumberOfRepairers = 1;
    var minimumNumberOfWallRepairers = 1;

    // count the number of creeps alive for each role
    // _.sum will count the number of properties in Game.creeps filtered by the
    //  arrow function, which checks for the creep being a harvester
    var numberOfHarvesters = _.sum(Game.creeps, (c) => c.memory.role == 'harvester');
    var numberOfUpgraders = _.sum(Game.creeps, (c) => c.memory.role == 'upgrader');
    var numberOfBuilders = _.sum(Game.creeps, (c) => c.memory.role == 'builder');
    var numberOfRepairers = _.sum(Game.creeps, (c) => c.memory.role == 'repairer');
    var numberOfWallRepairers = _.sum(Game.creeps, (c) => c.memory.role == 'wallRepairer');

    var energy = Game.spawns.Spawn1.room.energyCapacityAvailable;
    var name = undefined;

    // if not enough harvesters
    if (numberOfHarvesters < minimumNumberOfHarvesters) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'harvester');

        // if spawning failed and we have no harvesters left
        if (name == ERR_NOT_ENOUGH_ENERGY && numberOfHarvesters == 0) {
            // spawn one with what is available
            name = Game.spawns.Spawn1.createCustomCreep(
                Game.spawns.Spawn1.room.energyAvailable, 'harvester');
        }
    }
    // if not enough upgraders
    else if (numberOfUpgraders < minimumNumberOfUpgraders) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'upgrader');
    }
    // if not enough repairers
    else if (numberOfRepairers < minimumNumberOfRepairers) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'repairer');
    }
    // if not enough builders
    else if (numberOfBuilders < minimumNumberOfBuilders) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'builder');
    }
    // if not enough wallRepairers
    else if (numberOfWallRepairers < minimumNumberOfWallRepairers) {
        // try to spawn one
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'wallRepairer');
    }
    else {
        // else try to spawn a builder
        name = Game.spawns.Spawn1.createCustomCreep(energy, 'builder');
    }

    // print name to console if spawning was a success
    // name > 0 would not work since string > 0 returns false
    if (!(name < 0)) {
        console.log("Spawned new creep: " + name);
    }
};<|endoftext|>


<commit_before>/**
 * @file Node env
 * @author treelite(c.xinle@gmail.com)
 */

var extend = require('saber-lang').extend;
var configMgr = require('./lib/config');

/**
 * 全局配置
 *
 * @param {Object} options 配置信息
 * @param {string|Array.<string>=} options.template 公共模版
 * @param {Object=} options.templateConfig 模版配置信息
 * @param {Object=} options.router 路由器
 */
exports.config = function (options) {
    configMgr.set(options);
};

/**
 * 创建Presenter
 *
 * @inner
 * @param {Object} config 配置信息
 * @return {Object}
 */
exports.create = function (config) {
    var Constructor;
    config = configMgr.normal(config);

    if (config.constructor !== Object) {
        Constructor = config.constructor;
    }
    else {
        Constructor = require('./lib/Presenter');
    }

    return new Constructor(config);
};

exports.Abstract = require('./lib/Abstract');

exports.Presenter = require('./lib/Presenter');

exports.Model = require('./lib/Model');

exports.View = require('./lib/View');
<commit_msg>Change API, .create() return promise<commit_after>/**
 * @file Node env
 * @author treelite(c.xinle@gmail.com)
 */

var extend = require('saber-lang').extend;
var Resolver = require('saber-promise');
var configMgr = require('./lib/config');

function isString(value) {
    return Object.prototype.toString.call(value)
        === '[object String]';
}

/**
 * 全局配置
 *
 * @param {Object} options 配置信息
 * @param {string|Array.<string>=} options.template 公共模版
 * @param {Object=} options.templateConfig 模版配置信息
 * @param {Object=} options.templateData 公共静态模版数据
 * @param {Object=} options.router 路由器
 * @param {string=} options.basePath 动态加载Presenter的根路径
 */
exports.config = function (options) {
    configMgr.set(options);
};

/**
 * 创建Presenter
 *
 * @inner
 * @param {Object|string} config 配置信息
 * @return {Promise}
 */
exports.create = function (config) {
    // 动态加载Presenter配置
    if (isString(config)) {
        var path = require('path');
        var base = configMgr.get('basePath') || process.cwd();
        config = path.resolve(base, config);
        return exports.create(require(config));
    }

    var Constructor;
    config = configMgr.normal(config);

    if (config.constructor !== Object) {
        Constructor = config.constructor;
    }
    else {
        Constructor = require('./lib/Presenter');
    }

    return Resolver.resolved(new Constructor(config));
};

exports.Abstract = require('./lib/Abstract');

exports.Presenter = require('./lib/Presenter');

exports.Model = require('./lib/Model');

exports.View = require('./lib/View');
<|endoftext|>


<commit_before>var argv  = require('commander')
var http  = require('http')
var https = require('https')
var fs    = require('fs');
var async = require('async')

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

argv.version('0.0.2')
   .option('-s, --swagger [value]',      'Link to root Swagger resource.')
   .option('-o, --openi_server [value]', 'OPENi server where the types are to be created.')
   .option('-f, --file_output [value]',  'File where output is written to.')
   .option('-m, --mapping [value]',      'JSON object that maps related objects to OPENi Type ids.')
   .option('-g  --models [value]',       'Only create types for models within this array')
   .option('-a, --all',                  'If specified all Swagger Models are created, otherwise just models associated with PUT operations are created.')
   .on('--help', function(){
      console.log('  Examples:');
      console.log('');
      console.log('    node main.js -s https://dev.openi-ict.eu/api-spec/v1/api_framework -o dev.openi-ict.eu -f out.json');
      console.log('');
   })
   .parse(process.argv);

if (!argv.swagger || !argv.openi_server || !argv.file_output){
   console.log('');
   console.log('\033[91m Error: Missing parameters\033[0m');
   console.log('');
   argv.help()
   return
}

var swagger                = argv.swagger
var server                 = argv.openi_server
var out                    = argv.file_output
var modelsToProcess        = (argv.models)  ? JSON.parse(argv.models)  : []
var mapping                = (argv.mapping) ? JSON.parse(argv.mapping) : {}
var o = {}

var url_action = (0 === swagger.indexOf('https://')) ?  https : http

var writeData = function (){
   fs.writeFile(out, JSON.stringify(o), function(err) {
      if(err) {
         console.log("Error: ", err);
      } else {
         //console.log("The output was saved to file: " + out);
      }
   });
}

var getData = function(url, success, callback){

   url_action.get(url, function(res) {
      var data = ""
      res.on("data", function(chunk) {
         data+=chunk
      });
      res.on('end', function() {
         try{
            success(JSON.parse(data), callback)
         }
         catch (e){
            if (301 === res.statusCode){
               getData(res.headers.location, success, callback)
               return
            }
            console.log("Error parsing url: ", url)
            console.log("Error message: ", e)
         }
      });
   }).on('error', function(e) {
      console.log("Got error: " + e.message);
   });
}

var typeTranslator = function(swagger_type, swagger_name){

   if ( undefined !== swagger_type["$ref"] ){
      console.log(">>>", swagger_type["$ref"])
      return "string";
   }

   if ('url' == swagger_name.toLowerCase()){
      return 'url'
   }

   switch (swagger_type.type.toLowerCase()){
   case "integer":
   case "int":
      return "int"
      break
   case "string":
      return "string"
      break
   case "boolean":
      return "boolean"
      break
   case "date":
      return "date"
      break
   case "related":
      //console.log(swagger_type, swagger_name)
      var typeId = mapping[swagger_name]
      //console.log("related", typeId)
      if (undefined !== typeId){
         return typeId
      }
      else{
         console.log("Could not fnd related", swagger_type, swagger_name)
      }
      return "string"
      break
   default :
      return "string"
      break
   }
}

var createType = function(endpointData, model_name, type, callback){

   if (undefined === o[endpointData]){
      o[endpointData] = {}
   }

   var options = {
      host: server,
      port: 443,
      path: '/api/v1/types',
      method: 'POST',
      headers: {
         'Content-Type': 'application/json',
         'Accept': 'application/json',
         'Accept-Encoding':'gzip,deflate',
         'Content-Length': Buffer.byteLength(type),
         'Connection': 'keep-alive',
         "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36"
      }
   };

   var req = https.request(options, function(res){
      var data = ''

      res.setEncoding('utf8');
      res.on('data', function(chunk){
         data += chunk;
      });
      res.on('end', function(){

         if(undefined === data || "" === data){
         	return
         }
         if (JSON.parse(data)['@id']){
            o[endpointData][model_name] = JSON.parse(data)['@id']
         }
         else{
            var id = data.replace("{\"error\":\"Error adding entity: OPENi Type already exists (", "")
            var id = id.replace(").\"}", "")
            o[endpointData][model_name] = id
         }
         writeData()
         //callback(null)
      });
   });

   req.on('error', function(e) {
      console.log('problem with request: ' + e.message, model_name, endpointData, type);
   });

   req.write(type);
   req.end();
}

var processEndpoint = function(endpointData, callback){

   var models = {}

   if (argv.all){
      models = endpointData.models
   }
   else{
      //create models for POST models only
      for (var i = 0; i < endpointData.apis.length; i++){
         for (var j = 0; j < endpointData.apis[i].operations.length; j++){
            var operation = endpointData.apis[i].operations[j]

            var method = operation.method

            if (undefined === method){
               method = operation.httpMethod
            }

            if ('POST' === method){

               for (var k = 0; k < operation.parameters.length; k++){
                  if ('body' === operation.parameters[k].paramType.toLowerCase()){
                     var type = operation.parameters[k].type
                     if (undefined === type){
                        type = operation.parameters[k].dataType
                     }

                     if ('array' === type.toLowerCase()){
                        type = operation.parameters[k]["items"]["$ref"]
                     }

                     models[type] = endpointData.models[type]
                  }
               }
            }
         }
      }
   }

   for ( model in models){

      if ( 0 !== modelsToProcess.length && -1 === modelsToProcess.indexOf(model)){
         continue
      }

      var model_name  = model
      var model_value = endpointData.models[model]

      var host_root = swagger.split('/')[0] + "//" +  swagger.split('/')[2]

      var openiType = {"@context": [], "@reference" : host_root + '/' +  model_name}

      var counter   = 0

      for (prop in model_value.properties){

         var prop_value = model_value.properties[prop]

         openiType["@context"][counter] = {}

         openiType["@context"][counter]["@property_name"]    = prop
         openiType["@context"][counter]["@openi_type"]       = typeTranslator(prop_value, prop)
         openiType["@context"][counter]["@multiple"]         = false
         openiType["@context"][counter]["@required"]         = false
         openiType["@context"][counter]["@context_id"]       = host_root + '/' +  model_name + '/' + prop
         counter++
      }

      createType(endpointData.resourcePath.replace("/", ""), model_name, JSON.stringify(openiType), callback)
   }

}

var isValidURL = function(str) {
   var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
      '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
      '(\\#[-a-z\\d_]*)?$','i'); // fragment locater
   if(!pattern.test(str)) {;
      return false;
   } else {
      return true;
   }
}

getData(swagger, function(swagger_root){

   var processAPI = function(api, err){
      var endpoint = api.path.replace('{format}', 'json')

      if (!isValidURL(endpoint)){
         var base = swagger.substr(0, swagger.lastIndexOf('/'))
         var end  = swagger.substr(swagger.lastIndexOf('/'), swagger.length)
         if ( -1 !== end.indexOf('.')){
            endpoint = base + endpoint
         }
         else{
            endpoint = swagger + endpoint
         }
      }

      getData( endpoint, processEndpoint, err)
   }

   async.each(swagger_root.apis, processAPI, function(err){
      writeData()
   });

}, false)

<commit_msg>Changed the way contexts are set, removed host url so that type ids are the same on different hosts<commit_after>var argv  = require('commander')
var http  = require('http')
var https = require('https')
var fs    = require('fs');
var async = require('async')

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

argv.version('0.0.2')
   .option('-s, --swagger [value]',         'Link to root Swagger resource.')
   .option('-o, --openi_server [value]',    'OPENi server where the types are to be created.')
   .option('-f, --file_output [value]',     'File where output is written to.')
   .option('-m, --mapping [value]',         'JSON object that maps related objects to OPENi Type ids.')
   .option('-g  --models [value]',          'Only create types for models within this array')
   .option('-c  --context-prepend [value]', 'String to prepend to Endpoint names in context ids')
   .option('-a, --all',                     'If specified all Swagger Models are created, otherwise just models associated with PUT operations are created.')
   .on('--help', function(){
      console.log('  Examples:');
      console.log('');
      console.log('    node main.js -s https://dev.openi-ict.eu/api-spec/v1/api_framework -o dev.openi-ict.eu -f out.json');
      console.log('');
   })
   .parse(process.argv);

if (!argv.swagger || !argv.openi_server || !argv.file_output){
   console.log('');
   console.log('\033[91m Error: Missing parameters\033[0m');
   console.log('');
   argv.help()
   return
}

var swagger                = argv.swagger
var server                 = argv.openi_server
var out                    = argv.file_output
var modelsToProcess        = (argv.models)         ? JSON.parse(argv.models)  : []
var mapping                = (argv.mapping)        ? JSON.parse(argv.mapping) : {}
var contextPrepend         = (argv.contextPrepend) ? argv.contextPrepend  : ""
var o = {}

var url_action = (0 === swagger.indexOf('https://')) ?  https : http

var writeData = function (){

   fs.writeFile(out, JSON.stringify(o), function(err) {
      if(err) {
         console.log("Error: ", err);
      } else {
         //console.log("The output was saved to file: " + out);
      }
   });
}

var getData = function(url, success, callback){

   url_action.get(url, function(res) {
      var data = ""
      res.on("data", function(chunk) {
         data+=chunk
      });
      res.on('end', function() {
         try{
            success(JSON.parse(data), callback)
         }
         catch (e){
            if (301 === res.statusCode){
               getData(res.headers.location, success, callback)
               return
            }
            console.log("Error parsing url: ", url)
            console.log("Error message: ", e)
         }
      });
   }).on('error', function(e) {
      console.log("Got error: " + e.message);
   });
}

var typeTranslator = function(swagger_type, swagger_name){

   if ( undefined !== swagger_type["$ref"] ){
      console.log(">>>", swagger_type["$ref"])
      return "string";
   }

   if ('url' == swagger_name.toLowerCase()){
      return 'url'
   }

   switch (swagger_type.type.toLowerCase()){
   case "integer":
   case "int":
      return "int"
      break
   case "string":
      return "string"
      break
   case "boolean":
      return "boolean"
      break
   case "date":
      return "date"
      break
   case "related":
      //console.log(swagger_type, swagger_name)
      var typeId = mapping[swagger_name]
      //console.log("related", typeId)
      if (undefined !== typeId){
         return typeId
      }
      else{
         console.log("Could not fnd related", swagger_type, swagger_name)
      }
      return "string"
      break
   default :
      return "string"
      break
   }
}

var createType = function(endpointData, model_name, type, callback){

   if (undefined === o[endpointData]){
      o[endpointData] = {}
   }

   var options = {
      host: server,
      port: 443,
      path: '/api/v1/types',
      method: 'POST',
      headers: {
         'Content-Type': 'application/json',
         'Accept': 'application/json',
         'Accept-Encoding':'gzip,deflate',
         'Content-Length': Buffer.byteLength(type),
         'Connection': 'keep-alive',
         "User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36"
      }
   };

   var req = https.request(options, function(res){
      var data = ''

      res.setEncoding('utf8');
      res.on('data', function(chunk){
         data += chunk;
      });
      res.on('end', function(){

         if(undefined === data || "" === data){
         	return
         }
         if (JSON.parse(data)['@id']){
            if (argv.all){
               o[endpointData][model_name] = JSON.parse(data)['@id']
            }
            else{
               o[endpointData] = JSON.parse(data)['@id']
            }
         }
         else{
            var id = data.replace("{\"error\":\"Error adding entity: OPENi Type already exists (", "")
            var id = id.replace(").\"}", "")
            if (argv.all){
               o[endpointData][model_name] = id
            }
            else{
               o[endpointData] = id
            }
         }
         writeData()
         //callback(null)
      });
   });

   req.on('error', function(e) {
      console.log('problem with request: ' + e.message, model_name, endpointData, type);
   });

   req.write(type);
   req.end();
}

var processEndpoint = function(endpointData, callback){

   var models = {}

   if (argv.all || 0 !== modelsToProcess.length){
      models = endpointData.models
   }
   else{
      //create models for POST models only
      for (var i = 0; i < endpointData.apis.length; i++){
         for (var j = 0; j < endpointData.apis[i].operations.length; j++){
            var operation = endpointData.apis[i].operations[j]

            var method = operation.method

            if (undefined === method){
               method = operation.httpMethod
            }

            if ('POST' === method){

               for (var k = 0; k < operation.parameters.length; k++){
                  if ('body' === operation.parameters[k].paramType.toLowerCase()){
                     var type = operation.parameters[k].type
                     if (undefined === type){
                        type = operation.parameters[k].dataType
                     }

                     if ('array' === type.toLowerCase()){
                        type = operation.parameters[k]["items"]["$ref"]
                     }

                     models[type] = endpointData.models[type]
                  }
               }
            }
         }
      }
   }

   for ( model in models){

      if ( 0 !== modelsToProcess.length && -1 === modelsToProcess.indexOf(model)){
         continue
      }

      var model_name  = model
      var model_value = endpointData.models[model]

      var host_root = swagger.split('/')[0] + "//" +  swagger.split('/')[2]

      var openiType = {"@context": [], "@reference" : contextPrepend + model_name}

      var counter   = 0

      for (prop in model_value.properties){

         var prop_value = model_value.properties[prop]

         openiType["@context"][counter] = {}

         openiType["@context"][counter]["@property_name"]    = prop
         openiType["@context"][counter]["@openi_type"]       = typeTranslator(prop_value, prop)
         openiType["@context"][counter]["@multiple"]         = false
         openiType["@context"][counter]["@required"]         = false
         openiType["@context"][counter]["@context_id"]       = contextPrepend + model_name + '/' + prop
         counter++
      }

      createType(endpointData.resourcePath.replace("/", ""), model_name, JSON.stringify(openiType), callback)
   }

}

var isValidURL = function(str) {
   var pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
      '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
      '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
      '(\\#[-a-z\\d_]*)?$','i'); // fragment locater
   if(!pattern.test(str)) {;
      return false;
   } else {
      return true;
   }
}

getData(swagger, function(swagger_root){

   var processAPI = function(api, err){
      var endpoint = api.path.replace('{format}', 'json')

      if (!isValidURL(endpoint)){
         var base = swagger.substr(0, swagger.lastIndexOf('/'))
         var end  = swagger.substr(swagger.lastIndexOf('/'), swagger.length)
         if ( -1 !== end.indexOf('.')){
            endpoint = base + endpoint
         }
         else{
            endpoint = swagger + endpoint
         }
      }

      getData( endpoint, processEndpoint, err)
   }

   async.each(swagger_root.apis, processAPI, function(err){
      writeData()
   });

}, false)

<|endoftext|>