<commit_before>#!/usr/bin/env node

'use strict';

const childProcess = require('child_process');
const Promise = require('bluebird');
const DEFAULT_BRANCH_NAME = 'master';

/**
 * Calls `git` with the given arguments from the CWD
 * @param {string[]} args A list of arguments
 * @param {string} [stdin] The stdin for the process
 * @returns {Promise<string>} The output from `git`
 */
function git (args, stdin) {
  return new Promise((resolve, reject) => {
    const child = childProcess.spawn('git', args);

    if (typeof stdin === 'string') {
      child.stdin.write(stdin);
      child.stdin.end();
    }

    let stdout = '';
    let stderr = '';

    child.stdout.on('data', data => stdout += data);
    child.stderr.on('data', data => stderr += data);

    child.on('close', exitCode => exitCode ? reject(stderr) : resolve(stdout));
  }).then(stdout => stdout.replace(/\n$/, ''));
}

const commitCache = new Map();
/**
 * Gets the patch id of a single commit
 * @param {string} hash The commit hash
 * @returns {Promise<string>} The diff of the commit with the given hash
 */
function getCommitDiffId (hash) {
  if (!commitCache.has(hash)) {
    commitCache.set(hash, git(['diff', `${hash}^`, hash]).then(diff => git(['patch-id'], diff)));
  }
  return commitCache.get(hash);
}

git(['for-each-ref', 'refs/heads/', '--format=%(refname:short)'])
  .then(branchListOutput => branchListOutput.split('\n'))
  .tap(branchNames => {
    if (branchNames.indexOf(DEFAULT_BRANCH_NAME) === -1) {
      throw `fatal: no branch named '${DEFAULT_BRANCH_NAME}' found in this repo`;
    }
  }).filter(branchName =>
    // Get the common ancestor with the branch and master
    branchName !== DEFAULT_BRANCH_NAME && git(['merge-base', DEFAULT_BRANCH_NAME, branchName]).then(commonAncestorHash =>
      // Get the diff between the common ancestor and the branch tip
      git(['diff', `${commonAncestorHash}...${branchName}`]).then(diff => git(['patch-id'], diff)).then(branchPatchId =>
        // Iterate through all the commits to master since the ancestor
        git(['log', '--format=%H', `${commonAncestorHash}...${DEFAULT_BRANCH_NAME}`])
          .then(logOutput => logOutput ? logOutput.split('\n') : [])
          .map(getCommitDiffId)
          // If the patch for any commit to master since the ancestor is the same as the patch between the ancestor
          // and the branch tip, the branch can be deleted.
          .then(results => results.some(commitPatchId => commitPatchId === branchPatchId))
      )
    )
  )
  .tap(branchNamesToDelete => branchNamesToDelete.length && git(['checkout', DEFAULT_BRANCH_NAME]))
  .mapSeries(branchName => git(['branch', '-D', branchName]))
  .mapSeries(stdout => console.log(stdout))
  .catch(err => console.error(err.cause || err));
<commit_msg>Fix: Cap the number of processes running at a time (fixes #1)<commit_after>#!/usr/bin/env node

'use strict';

const childProcess = require('child_process');
const Promise = require('bluebird');
const DEFAULT_BRANCH_NAME = 'master';

/**
 * Calls `git` with the given arguments from the CWD
 * @param {string[]} args A list of arguments
 * @param {string} [stdin] The stdin for the process
 * @returns {Promise<string>} The output from `git`
 */
function git (args, stdin) {
  return new Promise((resolve, reject) => {
    const child = childProcess.spawn('git', args);

    if (typeof stdin === 'string') {
      child.stdin.write(stdin);
      child.stdin.end();
    }

    let stdout = '';
    let stderr = '';

    child.stdout.on('data', data => stdout += data);
    child.stderr.on('data', data => stderr += data);

    child.on('close', exitCode => exitCode ? reject(stderr) : resolve(stdout));
  }).then(stdout => stdout.replace(/\n$/, ''));
}

const commitCache = new Map();
/**
 * Gets the patch id of a single commit
 * @param {string} hash The commit hash
 * @returns {Promise<string>} The diff of the commit with the given hash
 */
function getCommitDiffId (hash) {
  if (!commitCache.has(hash)) {
    commitCache.set(hash, git(['diff', `${hash}^`, hash]).then(diff => git(['patch-id'], diff)));
  }
  return commitCache.get(hash);
}

git(['for-each-ref', 'refs/heads/', '--format=%(refname:short)'])
  .then(branchListOutput => branchListOutput.split('\n'))
  .tap(branchNames => {
    if (branchNames.indexOf(DEFAULT_BRANCH_NAME) === -1) {
      throw `fatal: no branch named '${DEFAULT_BRANCH_NAME}' found in this repo`;
    }
  }).filter(branchName =>
    // Get the common ancestor with the branch and master
    branchName !== DEFAULT_BRANCH_NAME && git(['merge-base', DEFAULT_BRANCH_NAME, branchName]).then(commonAncestorHash =>
      // Get the diff between the common ancestor and the branch tip
      git(['diff', `${commonAncestorHash}...${branchName}`]).then(diff => git(['patch-id'], diff)).then(branchPatchId =>
        // Iterate through all the commits to master since the ancestor
        git(['log', '--format=%H', `${commonAncestorHash}...${DEFAULT_BRANCH_NAME}`])
          .then(logOutput => logOutput ? logOutput.split('\n') : [])
          .map(getCommitDiffId, { concurrency: 10 })
          // If the patch for any commit to master since the ancestor is the same as the patch between the ancestor
          // and the branch tip, the branch can be deleted.
          .then(results => results.some(commitPatchId => commitPatchId === branchPatchId))
      )
    ),
    { concurrency: 1 }
  )
  .tap(branchNamesToDelete => branchNamesToDelete.length && git(['checkout', DEFAULT_BRANCH_NAME]))
  .mapSeries(branchName => git(['branch', '-D', branchName]))
  .mapSeries(stdout => console.log(stdout))
  .catch(err => console.error(err.cause || err));
<|endoftext|>


<commit_before>//conditions for winning
// 1-2-3, 4-5-6, 7-8-9
// 1-4-7, 2-5-8, 3-6-9
// 1-5-9, 3-5-7

var blues = []; //stores blue players moves
var reds = []; //stores red players moves

var blueMove = function(){

  //ALERT Blue player to move!
  $('#p1').show();
  $('#p2').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    blues.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledBlue');

    console.log(blues);

    //disable the square from being clicked again unless new game is started
    $('

').insertAfter(this);

    // check if blue wins:
    //    yes --> reset (built into counter function)
    blueCounter();

  });

    //    no --> prompt red player to move

};
//-------------end blueMove();

var redMove = function(){

  //ALERT red player to move!
  $('#p2').show();
  $('#p1').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    reds.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledRed');

    console.log(reds);
    // check if red wins:
    //    yes --> reset (built into counter function)
    redCounter();

  });

  //    no --> prompt blue player to move

};
//--------------end redMove();

var blueCounter = function(){
  if(
    ($('.one').hasClass('filledBlue') && $('.two').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))
    ||
    ($('.four').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.six').hasClass('filledBlue'))
    ||
    ($('.seven').hasClass('filledBlue') && $('.eight').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.four').hasClass('filledBlue') && $('.seven').hasClass('filledBlue'))
    ||
    ($('.two').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.eight').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.six').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))

  ){
    return(true);
  }
};
//----------------end blueCounter();

var redCounter = function(){
  if(
    ($('.one').hasClass('filledRed') && $('.two').hasClass('filledRed') && $('.three').hasClass('filledRed'))
    ||
    ($('.four').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.six').hasClass('filledRed'))
    ||
    ($('.seven').hasClass('filledRed') && $('.eight').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.four').hasClass('filledRed') && $('.seven').hasClass('filledRed'))
    ||
    ($('.two').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.eight').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.six').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.nine').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.three').hasClass('filledRed'))

  ){
      return(true);
  }
};
//-----------------end redCounter();

var boardCheck = function(){
  if(
    blueCounter()
  ){
    alert('A WINNER IS BLUE PLAYER!');
    reset();
  }
  else if (
    redCounter()
  ){
      alert('A WINNER IS RED PLAYER!')
      reset();
  }
};
//-------------end boardCheck();

var reset = function(){
  $('.square').removeClass('filledBlue');
  $('.square').removeClass('filledRed');
  blues = [];
  reds=[];
};
<commit_msg>something's fucky with the boardCheck() logic...auto applies a win when squares 3 and 5 are clicked<commit_after>//conditions for winning
// 1-2-3, 4-5-6, 7-8-9
// 1-4-7, 2-5-8, 3-6-9
// 1-5-9, 3-5-7

var blues = []; //stores blue players moves
var reds = []; //stores red players moves

var blueMove = function(){

  //ALERT Blue player to move!
  $('#p1').show();
  $('#p2').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    blues.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledBlue');

    console.log(blues);

    //disable the square from being clicked again unless new game is started
    $('

').insertAfter(this);

    // check if blue wins:
    //    yes --> reset (built into counter function)
    //boardCheck();

  });

    //    no --> prompt red player to move

};
//-------------end blueMove();

var redMove = function(){

  //ALERT red player to move!
  $('#p2').show();
  $('#p1').hide();

  // register blue players input
  $('.square').click(function(){
    var $result = $(this).attr('class');
    //alert($result);
    reds.push($(this).attr('id'));
    $(this).click(false);
    $(this).toggleClass('filledRed');

    console.log(reds);
    //disable the square from being clicked again unless new game is started
    $('

').insertAfter(this);

    // check if red wins:
    //    yes --> reset (built into counter function)
    //boardCheck();

  });

  //    no --> prompt blue player to move

};
//--------------end redMove();

var blueCounter = function(){
  if(
    ($('.one').hasClass('filledBlue') && $('.two').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))
    ||
    ($('.four').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.six').hasClass('filledBlue'))
    ||
    ($('.seven').hasClass('filledBlue') && $('.eight').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.four').hasClass('filledBlue') && $('.seven').hasClass('filledBlue'))
    ||
    ($('.two').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.eight').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.six').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))

    ||

    ($('.one').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.nine').hasClass('filledBlue'))
    ||
    ($('.three').hasClass('filledBlue') && $('.five').hasClass('filledBlue') && $('.three').hasClass('filledBlue'))

  ){
    return(true);
  }
};
//----------------end blueCounter();

var redCounter = function(){
  if(
    ($('.one').hasClass('filledRed') && $('.two').hasClass('filledRed') && $('.three').hasClass('filledRed'))
    ||
    ($('.four').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.six').hasClass('filledRed'))
    ||
    ($('.seven').hasClass('filledRed') && $('.eight').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.four').hasClass('filledRed') && $('.seven').hasClass('filledRed'))
    ||
    ($('.two').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.eight').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.six').hasClass('filledRed') && $('.nine').hasClass('filledRed'))

    ||

    ($('.one').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.nine').hasClass('filledRed'))
    ||
    ($('.three').hasClass('filledRed') && $('.five').hasClass('filledRed') && $('.three').hasClass('filledRed'))

  ){
      return(true);
  }
};
//-----------------end redCounter();

var boardCheck = function(){
  if(
    blueCounter()
  ){
    alert('A WINNER IS BLUE PLAYER!');
    reset();
  }
  else if (
    redCounter()
  ){
      alert('A WINNER IS RED PLAYER!')
      reset();
  }
};
//-------------end boardCheck();

var reset = function(){
  $('.square').removeClass('filledBlue');
  $('.square').removeClass('filledRed');
  $('.clickBlock').remove();
  blues = [];
  reds=[];
};
<|endoftext|>


<commit_before>
(function($){$.fn.s3upload=function(settings){var config={text:"Select file...",path:"/s3upload.swf",prefix:"",signature_url:"/s3upload",required:false,submit_on_all_complete:true,error_class:"s3_error",file_types:[]};if(settings)$.extend(config,settings);var elements=this.map(function(){if($(this).is("form"))return $(this).find(":file").toArray();return $(this);});var s3uploaders=0;var started=0;var completed=0;return elements.each(function(){s3uploaders++;var form=$(this).closest("form");var id=$(this).attr("id")||"s3upload_"+s3uploaders;var name=$(this).attr("name");$(this).replaceWith("

");var el=$("#"+id);var flash_div=$("

").appendTo("body");var filters=$.map(config.file_types,function(f,i){return f.join("#");}).join("|");console.log(filters);var fv={id:"flash_"+id,prefix:config.prefix,signatureURL:config.signature_url,filters:filters};var attr={wmode:"transparent"};swfobject.embedSWF(config.path,fv.id,"100%","100%","9.0.0",false,fv,false,attr,function(e){if(e.success){var swf=e.ref;el.text(config.text);flash_div.css({width:el.width(),height:el.height(),position:"absolute",top:el.offset().top,left:el.offset().left});var formSubmit=function(){if(config.required&&!swf.info)swf.onerror("Error: No file selected.");else
swf.upload();return false;}form.submit(formSubmit);swf.onselect=function(name,size,type){swf.info={name:name,size:size,type:type};var def=true;if($.isFunction(config.onselect))def=config.onselect.call(swf,swf.info);if(def){el.text(name);}}swf.oncancel=function(){var def=true;if($.isFunction(config.oncancel))def=config.oncancel.call(swf,swf.info);if(def){el.text(config.text);}swf.info=null;}swf.onstart=function(){var def=true;if($.isFunction(config.onstart))def=config.onstart.call(swf,swf.info);if(def){}started++;swf.disable();}swf.onprogress=function(p){var def=true;if($.isFunction(config.onprogress))def=config.onprogress.call(swf,p,swf.info);if(def){el.text(Math.ceil(p*100)+"%");}}swf.onerror=function(msg){var def=true;if($.isFunction(config.onerror))def=config.onerror.call(swf,msg,swf.info);if(def){el.html(""+msg+"");}swf.enable();}swf.oncomplete=function(key){var def=true;if($.isFunction(config.oncomplete))def=config.oncomplete.call(swf,swf.info);if(def){}swf.info.key=key;var el_info=el.nextAll("input[name^="+name+"]");if(el_info.length==0){for(var k in swf.info)el.after("<input type='hidden' name='"+name+"["+k+"]' value='"+swf.info[k]+"' />");}else{for(var k in swf.info)el.siblings("input[name="+name+"["+k+"]]").val(swf.info[k]);}completed++;form.unbind("submit",formSubmit);if(started==completed&&submit_on_all_complete){form.submit();}}}});});};})(jQuery);<commit_msg>Uploaded the minified version.<commit_after>/*	S3Upload 0.1.0 <http://github.com/slaskis/s3upload>
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/

(function($){$.fn.s3upload=function(settings){var config={text:"Select file...",path:"/s3upload.swf",prefix:"",signature_url:"/s3upload",required:false,submit_on_all_complete:true,error_class:"s3_error",file_types:[]};if(settings)$.extend(config,settings);var elements=this.map(function(){if($(this).is("form"))return $(this).find(":file").toArray();return $(this);});$.fn.s3upload.instances=$.fn.s3upload.instances||0;var started=0;var completed=0;return elements.each(function(){var form=$(this).closest("form");var id=$(this).attr("id")||"s3upload_"+$.fn.s3upload.instances;var name=$(this).attr("name");$(this).replaceWith("

");var el=$("#"+id);el.attr("class",$(this).attr("class"));var flash_div=$("

").appendTo("body");var filters=$.map(config.file_types,function(f,i){return f.join("#");}).join("|");var fv={id:"flash_"+id,prefix:config.prefix,signatureURL:config.signature_url,filters:filters};var params={wmode:"transparent",menu:false};swfobject.embedSWF(config.path,fv.id,"100%","100%","9.0.0",false,fv,params,false,function(e){if(e.success){var swf=e.ref;el.html(config.text);swf.update_interval=setInterval(function(){var pos=el.offset();flash_div.css({width:el.width(),height:el.height(),position:"absolute",top:pos.top,left:pos.left});},100);var formSubmit=function(){if(config.required&&!swf.info)swf.onerror("Error: No file selected.");else
swf.upload();return false;}form.submit(formSubmit);swf.onmouseevent=function(type,x,y){var def=true;if($.isFunction(config["on"+type]))def=config["on"+type].call(el,x,y);if(def){el.trigger(type);}}swf.onselect=function(name,size,type){swf.info={name:name,size:size,type:type};var def=true;if($.isFunction(config.onselect))def=config.onselect.call(el,swf.info);if(def){el.html(name);}}swf.oncancel=function(){var def=true;if($.isFunction(config.oncancel))def=config.oncancel.call(el,swf.info);if(def){el.html(config.text);}swf.info=null;}swf.onstart=function(){var def=true;if($.isFunction(config.onstart))def=config.onstart.call(el,swf.info);if(def){}started++;swf.disable();}swf.onprogress=function(p){var def=true;if($.isFunction(config.onprogress))def=config.onprogress.call(el,p,swf.info);if(def){el.html(Math.ceil(p*100)+"%");}}swf.onerror=function(msg){var def=true;if($.isFunction(config.onerror))def=config.onerror.call(el,msg,swf.info);if(def){el.html(""+msg+"");}swf.enable();}swf.oncomplete=function(key){swf.info.key=key;var def=true;if($.isFunction(config.oncomplete))def=config.oncomplete.call(el,swf.info);if(def){}if(el.nextAll("input[name^="+name+"]").length==0)for(var k in swf.info)el.after("<input type='hidden' name='"+name+"["+k+"]' value='"+swf.info[k]+"' />");else
for(var k in swf.info)el.siblings("input[name="+name+"["+k+"]]").val(swf.info[k]);completed++;form.unbind("submit",formSubmit);if(!config.submit_on_all_complete)swf.enable();else if(started==completed)form.submit();}}});$.fn.s3upload.instances++;});};})(jQuery);<|endoftext|>


<commit_before>// webpack v4
const path = require('path');

module.exports = {
  mode: 'production',
  entry: { main: './index_browser.js' },
  output: {
    path: path.resolve(__dirname),
    filename: 'browser.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader",
        }
      },
    ]
  },
  plugins: [ ],
  optimization: {
    minimize: true
  }
};<commit_msg>Export the browser module with UMD<commit_after>// webpack v4
const path = require('path');

module.exports = {
  mode: 'production',
  entry: { main: './index_browser.js' },
  output: {
    path: path.resolve(__dirname),
    filename: 'browser.js',
    library: 'irc-framework',
    libraryTarget: 'umd',
    umdNamedDefine: true
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: "babel-loader",
        }
      },
    ]
  },
  plugins: [ ],
  optimization: {
    minimize: true
  }
};<|endoftext|>


<commit_before>//
// A view representing a main landing page
// which can display "My Programs", "Recording Now" data
// and "Previously Recorded" data
//
var LandingPageDataSetView = function(options) {

    var base = BaseView(options);

    //
    // AJAX call and handler for updating "Recording Now" and
    // "Previously Recorded" div.
    //
    var loadDataSets = function(div) {

        // console.log("[DEBUG] loading recorded data...");

        div.empty();
        div.text("Loading recorded data...");

        var url = '/ext/flow/list_datasets';

        $.ajax({
            url:    url,
            method: 'POST',
            data:   { csrf_token: g_csrfToken },
            success: function(data) {
                var response = JSON.parse(data);

                //console.log("[DEBUG] List datasets", response);

                if(response.success) {

                    var items = response.items;
                    var recording = [];
                    var recorded = [];
                    for(var i = 0; i < items.length; i++) {
                        var item = items[i];
                        // console.log("[DEBUG] Checking metadata", item.metadata);
                        if(item.metadata && item.metadata.recording == true) {
                            recording.push(item);
                        } else {
                            recorded.push(item);
                        }
                    }

                    div.empty();

                    var createDataSetList = function(displayName, list) {
                        if(list.length == 0) {
                            return;
                        }
						var recordButton = false;
						if(displayName == "Recording Now")
							recordButton = true;
                        for(var i = 0; i < list.length; i++) {
                            var btn = createMyDataSetBtn ( list[i], i, recordButton );
                            btn.appendTo(div);
                            // console.log("[DEBUG] Creating dataset item", items[i]);
                        }
                    }

                    createDataSetList("Recording Now", recording);
                    createDataSetList("Previously Recorded", recorded);

                    if(recording.length == 0 && recorded.length == 0) {
                        addNoDatasetsToMenu(div);
                    }

                } else {
                    addNoDatasetsToMenu(div);
                    console.log("[ERROR] Error listing datasets", response);
                }
            },
            error: function(data) {
                addNoDatasetsToMenu(div);
                console.log("[ERROR] List datasets error", data);
            },
        });

    };

    //
    //didn't find any datasets, add a menu entry letting the user know there are no datasets available
    //
    this.addNoDatasetsToMenu = function(div){
        div.empty();
        var emptyButton = $('<div>', {class: 'diagramMenuEntryNoSelect noSelect menudarkgray'} ).text("no available datasets");
        div.append(emptyButton);
    }

    //
    // create a menu item button to load a saved dataset
    //
    var createMyDataSetBtn = function(item, index, addRecordButton) {
        var btn;
        var filename = item.name;
		if(addRecordButton){
			if(index%2 == 0){
				btn = $('<div>', {class: 'diagramMenuHeader menudarkgray'} );
			}
			else{
				btn = $('<div>', {class: 'diagramMenuHeader menulightgray'} );
			}
			var title = $('<div>', {class: 'diagramMenuEntryWithGlyph noSelect'} ).text(filename);
			var chevron = $('<div>', {class: 'diagramMenuChevron glyphicon glyphicon-play-circle', css:{color:'000000', display: 'block'}} );
			btn.append(title);
			btn.append(chevron);
		}
		else{
			if(index%2 == 0){
				//diagramMenuHeader
				btn = $('<button>', { text:filename, class: 'diagramMenuEntry menulightgray' } );
			}
			else{
				btn = $('<button>', { text:filename, class: 'diagramMenuEntry menudarkgray' } );
			}
		}

        btn.click(item, function(e) {
            console.log("[DEBUG] DataSetButton click", e.data);
            var dataSetView = getTopLevelView('data-set-view');
            dataSetView.loadDataSet(e.data);
            showTopLevelView('data-set-view');
        });

        return btn;
    }

    base.show = function() {
        var content = jQuery('#'+base.getDivId());
        loadDataSets(content);
    }

    return base;
}
<commit_msg>update recording icon<commit_after>//
// A view representing a main landing page
// which can display "My Programs", "Recording Now" data
// and "Previously Recorded" data
//
var LandingPageDataSetView = function(options) {

    var base = BaseView(options);

    //
    // AJAX call and handler for updating "Recording Now" and
    // "Previously Recorded" div.
    //
    var loadDataSets = function(div) {

        // console.log("[DEBUG] loading recorded data...");

        div.empty();
        div.text("Loading recorded data...");

        var url = '/ext/flow/list_datasets';

        $.ajax({
            url:    url,
            method: 'POST',
            data:   { csrf_token: g_csrfToken },
            success: function(data) {
                var response = JSON.parse(data);

                //console.log("[DEBUG] List datasets", response);

                if(response.success) {

                    var items = response.items;
                    var recording = [];
                    var recorded = [];
                    for(var i = 0; i < items.length; i++) {
                        var item = items[i];
                        // console.log("[DEBUG] Checking metadata", item.metadata);
                        if(item.metadata && item.metadata.recording == true) {
                            recording.push(item);
                        } else {
                            recorded.push(item);
                        }
                    }

                    div.empty();

                    var createDataSetList = function(displayName, list) {
                        if(list.length == 0) {
                            return;
                        }
						var recordButton = false;
						if(displayName == "Recording Now")
							recordButton = true;
                        for(var i = 0; i < list.length; i++) {
                            var btn = createMyDataSetBtn ( list[i], i, recordButton );
                            btn.appendTo(div);
                            // console.log("[DEBUG] Creating dataset item", items[i]);
                        }
                    }

                    createDataSetList("Recording Now", recording);
                    createDataSetList("Previously Recorded", recorded);

                    if(recording.length == 0 && recorded.length == 0) {
                        addNoDatasetsToMenu(div);
                    }

                } else {
                    addNoDatasetsToMenu(div);
                    console.log("[ERROR] Error listing datasets", response);
                }
            },
            error: function(data) {
                addNoDatasetsToMenu(div);
                console.log("[ERROR] List datasets error", data);
            },
        });

    };

    //
    //didn't find any datasets, add a menu entry letting the user know there are no datasets available
    //
    this.addNoDatasetsToMenu = function(div){
        div.empty();
        var emptyButton = $('<div>', {class: 'diagramMenuEntryNoSelect noSelect menudarkgray'} ).text("no available datasets");
        div.append(emptyButton);
    }

    //
    // create a menu item button to load a saved dataset
    //
    var createMyDataSetBtn = function(item, index, addRecordButton) {
        var btn;
        var filename = item.name;
		if(addRecordButton){
			if(index%2 == 0){
				btn = $('<div>', {class: 'diagramMenuHeader menudarkgray'} );
			}
			else{
				btn = $('<div>', {class: 'diagramMenuHeader menulightgray'} );
			}
			var title = $('<div>', {class: 'diagramMenuEntryWithGlyph noSelect'} ).text(filename);
			var chevron = $('<div>', {class: 'diagramMenuChevron glyphicon glyphicon-play-circle', css:{color:'FF0000', display: 'block'}} );
			btn.append(title);
			btn.append(chevron);
		}
		else{
			if(index%2 == 0){
				//diagramMenuHeader
				btn = $('<button>', { text:filename, class: 'diagramMenuEntry menulightgray' } );
			}
			else{
				btn = $('<button>', { text:filename, class: 'diagramMenuEntry menudarkgray' } );
			}
		}

        btn.click(item, function(e) {
            console.log("[DEBUG] DataSetButton click", e.data);
            var dataSetView = getTopLevelView('data-set-view');
            dataSetView.loadDataSet(e.data);
            showTopLevelView('data-set-view');
        });

        return btn;
    }

    base.show = function() {
        var content = jQuery('#'+base.getDivId());
        loadDataSets(content);
    }

    return base;
}
<|endoftext|>


<commit_before>/* eslint-disable import/no-extraneous-dependencies, global-require */
const webpack = require('webpack')
const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')

const publicPath = '/'

let appEntry
let plugins
let devServer
let devtool

if (process.env.PRODUCTION) {
  console.log('Running in production mode')

  appEntry = [path.resolve(__dirname, 'client')]
  devtool = 'source-map'
  plugins = [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.CommonsChunkPlugin({name: 'vendor', filename: 'vendor.js'}),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production')
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
        screw_ie8: true
      }
    }),
    new ExtractTextPlugin('[name].css')
  ]
  devServer = {}
} else {
  appEntry = [
    'webpack/hot/dev-server',
    'webpack-hot-middleware/client',
    path.resolve(__dirname, 'client'),
  ]

  plugins = [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new ExtractTextPlugin('[name].css'),
  ]

  devServer = {
    noInfo: false,
    publicPath,
    quiet: false,
    hot: true,
    stats: {
      assets: false,
      chunkModules: false,
      chunks: false,
      colors: true,
      hash: false,
      timings: false,
      version: false,
    },
    historyApiFallback: true,
  }

  devtool = 'eval'
}

module.exports = {
  devtool,
  entry: {
    app: appEntry,
  },
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: '[name].js',
    publicPath,
  },
  resolve: {
    extensions: ['.js', '.jsx', '.css'],
  },
  devServer,
  plugins,
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loaders: ['babel-loader'],
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
            {
              loader: 'postcss-loader',
              options: {
                plugins: () => [
                  require('autoprefixer'), // Automatically include vendor prefixes
                  require('postcss-nested'), // Enable nested rules, like in Sass
                ],
              },
            },
          ],
        }),
      },
      {
        test: /\.js$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
        query: {
          configFile: './.eslintrc',
        },
      },
    ],
  },
}
<commit_msg>Some logging<commit_after>/* eslint-disable import/no-extraneous-dependencies, global-require */
require('./server/logger.js')
const webpack = require('webpack')
const path = require('path')
const ExtractTextPlugin = require('extract-text-webpack-plugin')

const publicPath = '/'

let appEntry
let plugins
let devServer
let devtool

if (process.env.NODE_ENV == 'production') {
  log('Bundling assets for production...')
  appEntry = [path.resolve(__dirname, 'client')]
  devtool = 'source-map'
  plugins = [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.CommonsChunkPlugin({name: 'vendor', filename: 'vendor.js'}),
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('production')
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
        screw_ie8: true
      }
    }),
    new ExtractTextPlugin('[name].css')
  ]
  devServer = {}
} else {
  log(`Bundling assets for ${process.env.NODE_ENV}...`)

  appEntry = [
    'webpack/hot/dev-server',
    'webpack-hot-middleware/client',
    path.resolve(__dirname, 'client'),
  ]

  plugins = [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new ExtractTextPlugin('[name].css'),
  ]

  devServer = {
    noInfo: false,
    publicPath,
    quiet: false,
    hot: true,
    stats: {
      assets: false,
      chunkModules: false,
      chunks: false,
      colors: true,
      hash: false,
      timings: false,
      version: false,
    },
    historyApiFallback: true,
  }

  devtool = 'eval'
}

module.exports = {
  devtool,
  entry: {
    app: appEntry,
  },
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: '[name].js',
    publicPath,
  },
  resolve: {
    extensions: ['.js', '.jsx', '.css'],
  },
  devServer,
  plugins,
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loaders: ['babel-loader'],
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
            {
              loader: 'postcss-loader',
              options: {
                plugins: () => [
                  require('autoprefixer'), // Automatically include vendor prefixes
                  require('postcss-nested'), // Enable nested rules, like in Sass
                ],
              },
            },
          ],
        }),
      },
      {
        test: /\.js$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
        query: {
          configFile: './.eslintrc',
        },
      },
    ],
  },
}
<|endoftext|>


<commit_before>(function(){

    xtag.register('widget-DAQhisto', {
        extends: 'div',
        lifecycle: {
            created: function() {
                var histos = ['spectrum', 'time', 'pulse', 'waveform'],
                    i;

                    for(i=0; i<histos.length; i++){
                        this[histos[i]] = document.createElement('div')
                        this[histos[i]].setAttribute('id', histos[i])
                        this[histos[i]].setAttribute('class', 'DAQhisto')
                        this.appendChild(this[histos[i]]);
                    }

                //let repopulate know that the detector would like to be updated every loop:
                if(!window.refreshTargets)
                    window.refreshTargets = [];
                window.refreshTargets[window.refreshTargets.length] = this;
            },
            inserted: function() {},
            removed: function() {},
            attributeChanged: function() {}
        },
        events: {

        },
        accessors: {

        },
        methods: {

            'update': function(){
                var i,
                    data = [];

                for(i=0; i<2048; i++){
                    data.push([i, Math.random()]);
                }

                if(this.spectrumPlot)
                    this.spectrumPlot.destroy()

                this.spectrumPlot = new Dygraph(document.getElementById('spectrum'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

                if(this.timePlot)
                    this.timePlot.destroy()

                this.timePlot = new Dygraph(document.getElementById('time'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

                if(this.pulsePlot)
                    this.pulsePlot.destroy()

                this.spectrumPlot = new Dygraph(document.getElementById('pulse'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

                if(this.waveformPlot)
                    this.waveformPlot.destroy()

                this.spectrumPlot = new Dygraph(document.getElementById('waveform'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

            }

        }
    });

})();<commit_msg>daq plots<commit_after>(function(){

    xtag.register('widget-DAQhisto', {
        extends: 'div',
        lifecycle: {
            created: function() {
                var histos = ['spectrum', 'time', 'pulse', 'waveform'],
                    i;

                    for(i=0; i<histos.length; i++){
                        this[histos[i]] = document.createElement('div')
                        this[histos[i]].setAttribute('id', histos[i] + 'Plot')
                        this[histos[i]].setAttribute('class', 'DAQhisto')
                        this.appendChild(this[histos[i]]);
                    }

                //let repopulate know that the detector would like to be updated every loop:
                if(!window.refreshTargets)
                    window.refreshTargets = [];
                window.refreshTargets[window.refreshTargets.length] = this;
            },
            inserted: function() {},
            removed: function() {},
            attributeChanged: function() {}
        },
        events: {

        },
        accessors: {

        },
        methods: {

            'update': function(){
                var i,
                    data = [];

                for(i=0; i<2048; i++){
                    data.push([i, Math.random()]);
                }

                if(this.spectrumPlot)
                    this.spectrumPlot.destroy()

                this.spectrumPlot = new Dygraph(document.getElementById('spectrumPlot'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

                if(this.timePlot)
                    this.timePlot.destroy()

                this.timePlot = new Dygraph(document.getElementById('timePlot'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

                if(this.pulsePlot)
                    this.pulsePlot.destroy()

                this.spectrumPlot = new Dygraph(document.getElementById('pulsePlot'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

                if(this.waveformPlot)
                    this.waveformPlot.destroy()

                this.spectrumPlot = new Dygraph(document.getElementById('waveformPlot'), data, {
                    title: 'test',
                    xlabel: 'ns',
                    ylabel: 'mV',
                    width: this.offsetWidth*0.4,
                    height: this.offsetWidth*0.2,
                    sigFigs: 2,
                    strokeWidth: 4,
                    yAxisLabelWidth: 75,
                    xAxisHeight: 30,
                    highlightCircleSize: 6,
                    showLabelsOnHighlight: false,
                    stepPlot: true,
                    includeZero: true,
                    colors: ['#F1C40F', '#2ECC71', '#E74C3C', '#ECF0F1', '#1ABC9C', '#E67E22', '#9B59B6']
                });

            }

        }
    });

})();<|endoftext|>


<commit_before>'use strict';

// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider',
  function ($stateProvider, $urlRouterProvider) {

    // Redirect to 404 when route not found
    $urlRouterProvider.otherwise('not-found');

    // Home state routing
    $stateProvider
      .state('home', {
        url: '/',
        templateUrl: 'modules/core/views/home.client.view.html'
      })
      .state('not-found', {
        url: '/not-found',
        templateUrl: 'modules/core/views/404.client.view.html'
      });
  }
]);
<commit_msg>Added routing for login page to open first on app startup<commit_after>'use strict';

// Setting up route
angular.module('core').config(['$stateProvider', '$urlRouterProvider',
  function ($stateProvider, $urlRouterProvider) {

    // Redirect to 404 when route not found
    $urlRouterProvider.otherwise('not-found');

    // Home state routing
    $stateProvider
      .state('home', {
        url: '/',
        templateUrl: 'modules/core/views/home.client.view.html'
      })
      .state('not-found', {
        url: '/not-found',
        templateUrl: 'modules/core/views/404.client.view.html'
      })
    .state('sign-in', {
      url: '/authentication/signin',
      templateUrl: 'modules/users/views/authentication/signin.client.view.html'
    });
  }
]);
<|endoftext|>


<commit_before>module.exports = function(RED) {
	"use strict";
	// require any external libraries we may need....
	var path = require('path');
	var Blynk = require('blynk-library');
	//var blynkConnections = [];
	//var blynkConfigNode = null;
	//var pins = [];
	// Provide context.global access to node info.
	//RED.settings.functionGlobalContext.blynkPins = pins;
	function logInfo(node, message) {
		if(RED.settings.verbose) {
			node.log(message);
		}
	}
	function logWarn(node, message) {
		if(RED.settings.verbose) {
			node.warn(message);
		}
	}
	function logError(node, message) {
		//if(RED.settings.verbose) {
			node.error(message);
		//}
	}

	function setupStatusEvents (context) {
		context.server.blynk.on('connect', function() {
			logInfo(context, "connected");
			context.status({fill:"green",shape:"dot",text:"connected"});
			context.state = 'connected';
		});
		context.server.blynk.on('disconnect', function() {
			logInfo(context, "disconnected");
			if(context.state != 'errored') {
				context.status({fill:"red",shape:"ring",text:"disconnected"});
			}
			context.state = 'connected';
		});
		context.server.blynk.on('error', function(err) {
			logError(context, "errored");
			logError(context, context.status);
			//context.error(err, "");
			context.status({fill:"red",shape:"ring",text:err});
			context.state = 'errored';
		});

	}

	function BlynkServer(n) {
		//console.log('blynk server init', n.key);
		RED.nodes.createNode(this, n);
		this.key = n.key;
		this.usessl = n.usessl;
		this.addr = n.host;
		this.port = n.port;
		this.pins = [];

		// initialize Blynk or fetch it from the global reference
		// (used across Node-Red deployments which recreate all the nodes)
		// so we only get to initialise one single Blynk connection
		// only when the node.js VM is starting
		var blynkConfigNode = this;
		//TODO: this needs to be pooled, should be possible to add more than 1 blynk server

		if (typeof this.blynk === 'undefined') {

			logInfo(blynkConfigNode,'new connection with key: ' + this.key + ' SSL: ' + this.usessl);
			var options = {};
			var connOptions = {};

			if(this.addr) {
				logInfo(blynkConfigNode, 'using host ' + this.addr);
				connOptions.addr = this.addr;
			}
			if(this.port) {
				logInfo(blynkConfigNode, 'using port ' + this.port);
				connOptions.port = this.port;
			}

			if(this.usessl) {
				options.connector = new Blynk.SslClient(connOptions);
			} else {
				options.connector = new Blynk.TcpClient(connOptions);
			}

			this.blynk = new Blynk.Blynk(this.key, options); /* Blynk events */
			//is this an ok way of doing it?
			this.blynk.setMaxListeners(100);

			this.blynk.on('connect', function() {
				//console.log("Server ready.", blynkConfigNode.key);
				blynkConfigNode.log('key: ' + blynkConfigNode.key + ' connected');
				//todo: emit connect and disconnect event to nodes
			});
			this.blynk.on('disconnect', function() {
				//logWarn(blynkConfigNode, "key: " + blynkConfigNode.key + ' disconnected');
				blynkConfigNode.log("key: " + blynkConfigNode.key + ' disconnected');
				//todo
			});
			this.blynk.on('error', function(err) {
				logError(blynkConfigNode, 'key: ' +  blynkConfigNode.key + ' reason: ' + err);
			});

			//TODO: error handling
		} /* =============== Node-Red events ================== */
		this.on("close", function() {
			logInfo(this, 'key: '+  this.key + ' node-red close');
			//TODO: cleanup
			//blynkConnection.disconnect();
			this.blynk.disconnect();
			this.blynk.removeAllListeners();
			this.pins = [];
			//cleanup retry timer
			if(this.blynk.timerConn) {
				clearInterval(this.blynk.timerConn);
			}
			this.blynk = null;
		});
	}
	RED.nodes.registerType("blynk-server", BlynkServer);

	function BlynkReadEventNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);

		// Store local copies of the node configuration (as defined in the .html)
		this.server = RED.nodes.getNode(n.server);
		this.pin = n.pin;
		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		} else {
			// does exist
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);
		logInfo(node, 'on pin ' + this.pin + ' added');
		this.server.pins[this.pin].on('read', function() {
			logInfo(node, 'on pin ' +  node.pin + ' requested');
			var msg = {};
			msg.pin = node.pin;
			msg.payload = node.pin;
			node.send(msg);
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-read-event", BlynkReadEventNode);

	function BlynkWriteEventNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);
		// Store local copies of the node configuration (as defined in the .html)
		this.server = RED.nodes.getNode(n.server);
		this.pin = n.pin;

		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		} else {
			// does exist
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);
		logInfo(node, 'on pin ' + this.pin + ' added');
		this.server.pins[this.pin].on('write', function(p) {
			logInfo(node, 'on pin ' +  node.pin + ' received ' + p);
			var msg = {};
			msg.pin = node.pin;
			msg.payload = p;
			node.send(msg);
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-write-event", BlynkWriteEventNode);

	function BlynkWriteNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);
		//get config node
		this.server = RED.nodes.getNode(n.server);
		// Store local copies of the node configuration (as defined in the .html)
		this.pin = n.pin;

		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		} else {
			// does exist
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);

		logInfo(node, 'on pin ' +  node.pin + ' added');

		this.on("input", function(msg) {
			if (msg.hasOwnProperty("payload")) {
				logInfo(node, 'on pin ' +  node.pin + ' writing ' + msg.payload);
				this.server.pins[node.pin].write(msg.payload);
			} else {
				node.warn(RED._("blynk.errors.invalid-payload"));
			}
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-write", BlynkWriteNode);

	function BlynkNotifyNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);
		//get config node
		this.server = RED.nodes.getNode(n.server);
		// Store local copies of the node configuration (as defined in the .html)

		//if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
		//	this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		//} else {
			// does exist
		//}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);
		logInfo(node, 'on pin ' +  node.pin + ' added');

		this.on("input", function(msg) {
			if (msg.hasOwnProperty("payload")) {
				logInfo(node, 'on pin ' +  node.pin + ' notifying ' + msg.payload);
				this.server.blynk.notify(msg.payload);
			} else {
				node.warn(RED._("blynk.errors.invalid-payload"));
			}
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-notify", BlynkNotifyNode);

	function BlynkLCDPrintNode(n) {
		RED.nodes.createNode(this, n);
		//get config node
		this.server = RED.nodes.getNode(n.server);
		// Store local copies of the node configuration (as defined in the .html)
		this.pin = n.pin;
		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.WidgetLCD(this.pin);
		} else {
			// does exist
			this.warn(RED._("LCD Pin already in use"));
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);

		logInfo(node, 'on pin ' +  node.pin + ' added');

		this.on("input", function(msg) {
			if (msg.hasOwnProperty("payload")) {
				if(msg.payload == 'clear-lcd') {
					logInfo(node, 'on pin ' +  node.pin + ' printing ' + msg.payload);
					this.server.pins[node.pin].clear();

				} else {
					var line = 0;
					if (msg.topic && !isNaN(msg.topic)){
						line = msg.topic;
					}

					logInfo(node, 'on pin ' +  node.pin + ' printing ' + msg.payload);
					this.server.pins[node.pin].print(0, line, msg.payload);
				}
			} else {
				node.warn(RED._("blynk.errors.invalid-payload"));
			}
		});
	}
	RED.nodes.registerType("blynk-lcd-print", BlynkLCDPrintNode);

}<commit_msg>Added bridge functionality<commit_after>module.exports = function(RED) {
	"use strict";
	// require any external libraries we may need....
	var path = require('path');
	var Blynk = require('blynk-library');
	//var blynkConnections = [];
	//var blynkConfigNode = null;
	//var pins = [];
	// Provide context.global access to node info.
	//RED.settings.functionGlobalContext.blynkPins = pins;
	function logInfo(node, message) {
		if(RED.settings.verbose) {
			node.log(message);
		}
	}
	function logWarn(node, message) {
		if(RED.settings.verbose) {
			node.warn(message);
		}
	}
	function logError(node, message) {
		//if(RED.settings.verbose) {
			node.error(message);
		//}
	}

	function setupStatusEvents (context) {
		context.server.blynk.on('connect', function() {
			logInfo(context, "connected");
			context.status({fill:"green",shape:"dot",text:"connected"});
			if(context.type == 'bridge' ) {
                                context.bridge.setAuthToken(context.target);
                        }
			context.state = 'connected';
		});
		context.server.blynk.on('disconnect', function() {
			logInfo(context, "disconnected");
			if(context.state != 'errored') {
				context.status({fill:"red",shape:"ring",text:"disconnected"});
			}
			context.state = 'disconnected';
		});
		context.server.blynk.on('error', function(err) {
			logError(context, "errored");
			logError(context, context.status);
			//context.error(err, "");
			context.status({fill:"red",shape:"ring",text:err});
			context.state = 'errored';
		});

	}

	function BlynkServer(n) {
		//console.log('blynk server init', n.key);
		RED.nodes.createNode(this, n);
		this.key = n.key;
		this.usessl = n.usessl;
		this.addr = n.host;
		this.port = n.port;
		this.pins = [];

		// initialize Blynk or fetch it from the global reference
		// (used across Node-Red deployments which recreate all the nodes)
		// so we only get to initialise one single Blynk connection
		// only when the node.js VM is starting
		var blynkConfigNode = this;
		//TODO: this needs to be pooled, should be possible to add more than 1 blynk server

		if (typeof this.blynk === 'undefined') {

			logInfo(blynkConfigNode,'new connection with key: ' + this.key + ' SSL: ' + this.usessl);
			var options = {};
			var connOptions = {};

			if(this.addr) {
				logInfo(blynkConfigNode, 'using host ' + this.addr);
				connOptions.addr = this.addr;
			}
			if(this.port) {
				logInfo(blynkConfigNode, 'using port ' + this.port);
				connOptions.port = this.port;
			}

			if(this.usessl) {
				options.connector = new Blynk.SslClient(connOptions);
			} else {
				options.connector = new Blynk.TcpClient(connOptions);
			}

			this.blynk = new Blynk.Blynk(this.key, options); /* Blynk events */
			//is this an ok way of doing it?
			this.blynk.setMaxListeners(100);

			this.blynk.on('connect', function() {
				//console.log("Server ready.", blynkConfigNode.key);
				blynkConfigNode.log('key: ' + blynkConfigNode.key + ' connected');
				//todo: emit connect and disconnect event to nodes
			});
			this.blynk.on('disconnect', function() {
				//logWarn(blynkConfigNode, "key: " + blynkConfigNode.key + ' disconnected');
				blynkConfigNode.log("key: " + blynkConfigNode.key + ' disconnected');
				//todo
			});
			this.blynk.on('error', function(err) {
				logError(blynkConfigNode, 'key: ' +  blynkConfigNode.key + ' reason: ' + err);
			});

			//TODO: error handling
		} /* =============== Node-Red events ================== */
		this.on("close", function() {
			logInfo(this, 'key: '+  this.key + ' node-red close');
			//TODO: cleanup
			//blynkConnection.disconnect();
			this.blynk.disconnect();
			this.blynk.removeAllListeners();
			this.pins = [];
			//cleanup retry timer
			if(this.blynk.timerConn) {
				clearInterval(this.blynk.timerConn);
			}
			this.blynk = null;
		});
	}
	RED.nodes.registerType("blynk-server", BlynkServer);

	function BlynkReadEventNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);

		// Store local copies of the node configuration (as defined in the .html)
		this.server = RED.nodes.getNode(n.server);
		this.pin = n.pin;
		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		} else {
			// does exist
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);
		logInfo(node, 'on pin ' + this.pin + ' added');
		this.server.pins[this.pin].on('read', function() {
			logInfo(node, 'on pin ' +  node.pin + ' requested');
			var msg = {};
			msg.pin = node.pin;
			msg.payload = node.pin;
			node.send(msg);
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-read-event", BlynkReadEventNode);

	function BlynkWriteEventNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);
		// Store local copies of the node configuration (as defined in the .html)
		this.server = RED.nodes.getNode(n.server);
		this.pin = n.pin;

		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		} else {
			// does exist
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);
		logInfo(node, 'on pin ' + this.pin + ' added');
		this.server.pins[this.pin].on('write', function(p) {
			logInfo(node, 'on pin ' +  node.pin + ' received ' + p);
			var msg = {};
			msg.pin = node.pin;
			msg.payload = p;
			node.send(msg);
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-write-event", BlynkWriteEventNode);

	function BlynkWriteNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);
		//get config node
		this.server = RED.nodes.getNode(n.server);
		// Store local copies of the node configuration (as defined in the .html)
		this.pin = n.pin;

		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		} else {
			// does exist
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);

		logInfo(node, 'on pin ' +  node.pin + ' added');

		this.on("input", function(msg) {
			if (msg.hasOwnProperty("payload")) {
				logInfo(node, 'on pin ' +  node.pin + ' writing ' + msg.payload);
				this.server.pins[node.pin].write(msg.payload);
			} else {
				node.warn(RED._("blynk.errors.invalid-payload"));
			}
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-write", BlynkWriteNode);

	function BlynkNotifyNode(n) {
		// Create a RED node
		RED.nodes.createNode(this, n);
		//get config node
		this.server = RED.nodes.getNode(n.server);
		// Store local copies of the node configuration (as defined in the .html)

		//if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
		//	this.server.pins[this.pin] = new this.server.blynk.VirtualPin(this.pin);
		//} else {
			// does exist
		//}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);
		logInfo(node, 'on pin ' +  node.pin + ' added');

		this.on("input", function(msg) {
			if (msg.hasOwnProperty("payload")) {
				logInfo(node, 'on pin ' +  node.pin + ' notifying ' + msg.payload);
				this.server.blynk.notify(msg.payload);
			} else {
				node.warn(RED._("blynk.errors.invalid-payload"));
			}
		});
	}
	// Register the node by name. This must be called before overriding any of the
	// Node functions.
	RED.nodes.registerType("blynk-notify", BlynkNotifyNode);

	function BlynkLCDPrintNode(n) {
		RED.nodes.createNode(this, n);
		//get config node
		this.server = RED.nodes.getNode(n.server);
		// Store local copies of the node configuration (as defined in the .html)
		this.pin = n.pin;
		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
			this.server.pins[this.pin] = new this.server.blynk.WidgetLCD(this.pin);
		} else {
			// does exist
			this.warn(RED._("LCD Pin already in use"));
		}
		// copy "this" object in case we need it in context of callbacks of other functions.
		var node = this;
		setupStatusEvents (node);

		logInfo(node, 'on pin ' +  node.pin + ' added');

		this.on("input", function(msg) {
			if (msg.hasOwnProperty("payload")) {
				if(msg.payload == 'clear-lcd') {
					logInfo(node, 'on pin ' +  node.pin + ' printing ' + msg.payload);
					this.server.pins[node.pin].clear();

				} else {
					var line = 0;
					if (msg.topic && !isNaN(msg.topic)){
						line = msg.topic;
					}

					logInfo(node, 'on pin ' +  node.pin + ' printing ' + msg.payload);
					this.server.pins[node.pin].print(0, line, msg.payload);
				}
			} else {
				node.warn(RED._("blynk.errors.invalid-payload"));
			}
		});
	}
	RED.nodes.registerType("blynk-lcd-print", BlynkLCDPrintNode);

	 function BlynkBridgeNode(n) {
		RED.nodes.createNode(this, n);
		//get config node
		this.server = RED.nodes.getNode(n.server);
		// Store local copies of the node configuration (as defined in the .html)
		this.pin = n.pin;
                this.type = 'bridge';
                this.target = n.target;
		if (typeof this.server.pins[this.pin] === 'undefined') {
			// does not exist
                        this.bridge =  new this.server.blynk.WidgetBridge(this.pin);
		} else {
			// does exist
			this.warn(RED._("Bridge Pin already in use"));
		}
		// copy "this" object in case we need it in context of callbacks of other functions.

		var node = this;
		setupStatusEvents (node);

		logInfo(node, 'on pin ' +  node.pin + ' added');

		this.on("input", function(msg) {
			if (msg.hasOwnProperty("payload")) {
				this.bridge.virtualWrite(msg.pin, msg.payload);
			} else {
				node.warn(RED._("blynk.errors.invalid-payload"));
			}
		});
	}
	RED.nodes.registerType("blynk-bridge", BlynkBridgeNode);

}
<|endoftext|>


<commit_before>console.log("This is a kite simulator");
function liftCoefficient(alpha){
  // This is a simplified formula for lift coefficient
  // Fit with lift for an infinite elliptic wing for small angle
  // Maximum lift at 45°
  // No lift at 90°
  // Negative lift from 90°
  Cl = Math.PI*Math.sin (2*alpha);
  return Cl;
 }
function dragCoefficient(alpha){
  Cd0 = 0.1;
  AR = 5; // Aspect ratio
  e = 1;
  inducedDragCoefficient = Math.pow(2*Math.PI*Math.sin(alpha),2)/(Math.PI*AR*e);
  Cd = inducedDragCoefficient + Cd0;
  return Cd;
}
var V = 10;

line_length     = 10;
wind_velocity   = 10;
kite_mass       = 2;
kite_surface    = 6;
rho_air         = 1;    // Air density
elevation0      = 0;
omega0          = 0;    // Angular rate
AoKdeg          = 50;   // Angle of Keying (calage)
sampleTime      = 0.0005; // Sample time
earth_gravity              = 9.81;
g= earth_gravity;
meter2pix = 20;
reel_speed = 0;

AoK = AoKdeg*Math.PI/180;
omega = 0;
elevation = 0;
y_base = 0;
z_base = 0;

// y is horizontal and positive in wind propagation direction
// z is vertical and positive up

// Base velocity relative to ground projected in ground axis
// Base is assumed to be static
v_base = 0;
w_base = 0;
document.getElementById("angleOfKeyRange").addEventListener("change", updateAngleOfKey);
document.getElementById("lineLengthRange").addEventListener("change", updateLineLength);
document.getElementById("windVelocityRange").addEventListener("change", updateWindVelocity);
document.getElementById("kiteMassRange").addEventListener("change", updateKiteMass);
document.getElementById("kiteSurfaceRange").addEventListener("change", updateKiteSurface);
document.getElementById("myCheck").addEventListener("change", updateGravity);
document.getElementById("reelSpeedRange").addEventListener("change", updateReelSpeed);
setInterval(update, 1);
setInterval(updatePlot,100);
var d = new Date();
var t0 = d.getTime();
told = 0;
simulation_time = 0;

function plot(y_base, z_base, y_kite, z_kite, pitch){
  rotateKite(pitch);
  translateKite(y_kite, z_kite);
}
function updatePlot(){
  plot(y_base, z_base, y_kite, z_kite, pitch);
  updateOutput();
  setLineLength();
}

//function update(dt, AoK){
function update(){

  // Try to use real time
  d = new Date();
  t = d.getTime()-t0;
  dt = (t-told)/1000;
  told = t;
  //console.log(dt/sampleTime)
  // Use constant sampleTime instead (to avoid Nan for unknown reason)
  dt = sampleTime// +0*dt;

  // Compute kite position
  y_kite = y_base + line_length * Math.cos(elevation);
  z_kite = z_base + line_length * Math.sin(elevation);

  pitch = AoK -elevation;
  //console.log(pitch);

  // Kite velocity relative to ground, projected in ground axis
  // Line is assumed straight.
  v_kite = v_base - omega*line_length*Math.cos(Math.PI/2 - elevation) + reel_speed*Math.cos(elevation);
  w_kite = w_base + omega*line_length*Math.sin(Math.PI/2 - elevation) + reel_speed*Math.sin(elevation);

  // Wind velocity: air velocity relative to ground, projected in ground axis
  // Assumed to be constant in time and space and horizontal
  v_wind = wind_velocity;
  w_wind = 0;

  // Wind relative velocity : air velocity relative to kite, projected in ground axis
  v_air_kite = v_wind-v_kite;
  w_air_kite = w_wind-w_kite;

  // Angle of attack of the kite, defined between kite chord and relative air velocity
  angle_air_kite = Math.atan2(w_air_kite, v_air_kite);
  AoA = angle_air_kite +pitch;
  //console.log(AoA);
  // Dynamic pressure
  q = 1/2*rho_air *(v_air_kite*v_air_kite + w_air_kite*w_air_kite);

  // Lift and drag are in apparent wind frame
  lift   = q*kite_surface*liftCoefficient(AoA);
  drag   = q*kite_surface*dragCoefficient(AoA);

  // Rotate to ground frame
  Fz = lift* Math.cos(angle_air_kite) + drag*Math.sin(angle_air_kite);
  Fy = -lift* Math.sin(angle_air_kite) + drag*Math.cos(angle_air_kite);

  // Torque computed at base
  ML = +Fz * y_kite-kite_mass*g*y_kite;
  MD = -Fy * z_kite;

  // Angular acceleration
  omegap = 1/(kite_mass*line_length^2) * (ML + MD)- 0.0*omega;  //x*omega = amortissement
  //console.log(omegap);
  // Saturate to avoid instabilities
  omegap = Math.max(-60000, Math.min(omegap,60000));

  simulation_time = simulation_time + dt;

  // Compute line length
  line_length = line_length + reel_speed*dt;
  if (line_length<2)
  {
    reel_speed = 0;
    line_length = 2;
  }

  omega = omega + omegap * dt;

  // Saturate to avoid divergences
  //console.log(omega);
  omega = Math.max(-60, Math.min(omega,60));

  elevation = elevation + omega * dt;
  y_base = y_base + v_base*dt;
  z_base = z_base + w_base*dt;

    // Compute line tension
  line_tension = Fy*Math.cos(elevation) +  (Fz-kite_mass*g)*Math.sin(elevation) + kite_mass*omega*omega*line_length;
}
function rotateKite(r){
    kite = document.getElementById("kite");
        r_deg = r*180/Math.PI;
		kite.setAttribute('transform', 'rotate(' +r_deg +')');
		}
function translateKite(y, z){
  kite_frame = document.getElementById("local_frame");
  kite_line = document.getElementById("kite_line");
  kite_frame.setAttribute('transform', 'translate(' +y*meter2pix +','+ -z*meter2pix +')');
  kite_line.setAttribute('x2', y*meter2pix);
  kite_line.setAttribute('y2', -z*meter2pix);
}

function updateAngleOfKey(){
		//get elements
		var myRange = document.getElementById("angleOfKeyRange");
		var myOutput = document.getElementById("angleOfKey");
		//copy the value over
		myOutput.value = myRange.value;
    AoK = myOutput.value*Math.PI/180;
	}
function updateLineLength(){
		//get elements
		var myRange = document.getElementById("lineLengthRange");
		var myOutput = document.getElementById("lineLength");
		//copy the value over
		myOutput.value = myRange.value;
    //line_length = myOutput.value;
	}
function setLineLength(){
		//get elements
		var myRange = document.getElementById("lineLengthRange");
		var myOutput = document.getElementById("lineLength");
		//copy the value over
		myOutput.value = Math.round(line_length*10)/10;
    myRange.value = line_length;
	}
function updateReelSpeed(){
		//get elements
		var myRange = document.getElementById("reelSpeedRange");
		var myOutput = document.getElementById("reelSpeed");
		//copy the value over
		myOutput.value = myRange.value;
    reel_speed = myOutput.value;
	}
  function updateWindVelocity(){
		//get elements
		var myRange = document.getElementById("windVelocityRange");
		var myOutput = document.getElementById("windVelocity");
		//copy the value over
		myOutput.value = myRange.value;
    wind_velocity = myOutput.value;
	}
  function updateKiteMass(){
		//get elements
		var myRange = document.getElementById("kiteMassRange");
		var myOutput = document.getElementById("kiteMass");
		//copy the value over
		myOutput.value = myRange.value;
    kite_mass = myOutput.value;
	}
  function updateKiteSurface(){
		//get elements
		var myRange = document.getElementById("kiteSurfaceRange");
		var myOutput = document.getElementById("kiteSurface");
		//copy the value over
		myOutput.value = myRange.value;
    kite_surface = myOutput.value;
	}
  function updateGravity(){
		//get elements

		var myCheck = document.getElementById("myCheck");
    g = earth_gravity*myCheck.checked;
	}
  function updateOutput(){
    var myOutput = document.getElementById("elevation");
    myOutput.value = Math.round(elevation*180/Math.PI*10)/10;

    myOutput = document.getElementById("time");
    myOutput.value = Math.round(simulation_time*100)/100;

    myOutput = document.getElementById("lineTension");
    myOutput.value = Math.round(line_tension*10)/100;

    myOutput = document.getElementById("kiteSpeed");
    myOutput.value = Math.round(omega*line_length*10)/10;
  }

<commit_msg>Speed up (dirty)<commit_after>console.log("This is a kite simulator");
function liftCoefficient(alpha){
  // This is a simplified formula for lift coefficient
  // Fit with lift for an infinite elliptic wing for small angle
  // Maximum lift at 45°
  // No lift at 90°
  // Negative lift from 90°
  Cl = Math.PI*Math.sin (2*alpha);
  return Cl;
 }
function dragCoefficient(alpha){
  Cd0 = 0.1;
  AR = 5; // Aspect ratio
  e = 1;
  inducedDragCoefficient = Math.pow(2*Math.PI*Math.sin(alpha),2)/(Math.PI*AR*e);
  Cd = inducedDragCoefficient + Cd0;
  return Cd;
}
var V = 10;

line_length     = 10;
wind_velocity   = 10;
kite_mass       = 2;
kite_surface    = 6;
rho_air         = 1;    // Air density
elevation0      = 0;
omega0          = 0;    // Angular rate
AoKdeg          = 50;   // Angle of Keying (calage)
sampleTime      = 0.0005; // Sample time
earth_gravity              = 9.81;
g= earth_gravity;
meter2pix = 20;
reel_speed = 0;

AoK = AoKdeg*Math.PI/180;
omega = 0;
elevation = 0;
y_base = 0;
z_base = 0;

// y is horizontal and positive in wind propagation direction
// z is vertical and positive up

// Base velocity relative to ground projected in ground axis
// Base is assumed to be static
v_base = 0;
w_base = 0;
document.getElementById("angleOfKeyRange").addEventListener("change", updateAngleOfKey);
document.getElementById("lineLengthRange").addEventListener("change", updateLineLength);
document.getElementById("windVelocityRange").addEventListener("change", updateWindVelocity);
document.getElementById("kiteMassRange").addEventListener("change", updateKiteMass);
document.getElementById("kiteSurfaceRange").addEventListener("change", updateKiteSurface);
document.getElementById("myCheck").addEventListener("change", updateGravity);
document.getElementById("reelSpeedRange").addEventListener("change", updateReelSpeed);
setInterval(updaten, 1);
setInterval(updatePlot,100);
var d = new Date();
var t0 = d.getTime();
told = 0;
simulation_time = 0;

function plot(y_base, z_base, y_kite, z_kite, pitch){
  rotateKite(pitch);
  translateKite(y_kite, z_kite);
}
function updatePlot(){
  plot(y_base, z_base, y_kite, z_kite, pitch);
  updateOutput();
  setLineLength();
}
function updaten()
{
  for (i=0;i<8;i++) // Dirty manual tuning to get close of real time on my computer
  {
    update();
  }
}

//function update(dt, AoK){
function update(){

  // Try to use real time
  d = new Date();
  t = d.getTime()-t0;
  dt = (t-told)/1000;
  told = t;
  //console.log(dt/sampleTime)
  // Use constant sampleTime instead (to avoid Nan for unknown reason)
  dt = sampleTime// +0*dt;

  // Compute kite position
  y_kite = y_base + line_length * Math.cos(elevation);
  z_kite = z_base + line_length * Math.sin(elevation);

  pitch = AoK -elevation;
  //console.log(pitch);

  // Kite velocity relative to ground, projected in ground axis
  // Line is assumed straight.
  v_kite = v_base - omega*line_length*Math.cos(Math.PI/2 - elevation) + reel_speed*Math.cos(elevation);
  w_kite = w_base + omega*line_length*Math.sin(Math.PI/2 - elevation) + reel_speed*Math.sin(elevation);

  // Wind velocity: air velocity relative to ground, projected in ground axis
  // Assumed to be constant in time and space and horizontal
  v_wind = wind_velocity;
  w_wind = 0;

  // Wind relative velocity : air velocity relative to kite, projected in ground axis
  v_air_kite = v_wind-v_kite;
  w_air_kite = w_wind-w_kite;

  // Angle of attack of the kite, defined between kite chord and relative air velocity
  angle_air_kite = Math.atan2(w_air_kite, v_air_kite);
  AoA = angle_air_kite +pitch;
  //console.log(AoA);
  // Dynamic pressure
  q = 1/2*rho_air *(v_air_kite*v_air_kite + w_air_kite*w_air_kite);

  // Lift and drag are in apparent wind frame
  lift   = q*kite_surface*liftCoefficient(AoA);
  drag   = q*kite_surface*dragCoefficient(AoA);

  // Rotate to ground frame
  Fz = lift* Math.cos(angle_air_kite) + drag*Math.sin(angle_air_kite);
  Fy = -lift* Math.sin(angle_air_kite) + drag*Math.cos(angle_air_kite);

  // Torque computed at base
  ML = +Fz * y_kite-kite_mass*g*y_kite;
  MD = -Fy * z_kite;

  // Angular acceleration
  omegap = 1/(kite_mass*line_length^2) * (ML + MD)- 0.0*omega;  //x*omega = amortissement
  //console.log(omegap);
  // Saturate to avoid instabilities
  omegap = Math.max(-60000, Math.min(omegap,60000));

  simulation_time = simulation_time + dt;

  // Compute line length
  line_length = line_length + reel_speed*dt;
  if (line_length<2)
  {
    reel_speed = 0;
    line_length = 2;
  }

  omega = omega + omegap * dt;

  // Saturate to avoid divergences
  //console.log(omega);
  omega = Math.max(-60, Math.min(omega,60));

  elevation = elevation + omega * dt;
  y_base = y_base + v_base*dt;
  z_base = z_base + w_base*dt;

    // Compute line tension
  line_tension = Fy*Math.cos(elevation) +  (Fz-kite_mass*g)*Math.sin(elevation) + kite_mass*omega*omega*line_length;
}
function rotateKite(r){
    kite = document.getElementById("kite");
        r_deg = r*180/Math.PI;
		kite.setAttribute('transform', 'rotate(' +r_deg +')');
		}
function translateKite(y, z){
  kite_frame = document.getElementById("local_frame");
  kite_line = document.getElementById("kite_line");
  kite_frame.setAttribute('transform', 'translate(' +y*meter2pix +','+ -z*meter2pix +')');
  kite_line.setAttribute('x2', y*meter2pix);
  kite_line.setAttribute('y2', -z*meter2pix);
}

function updateAngleOfKey(){
		//get elements
		var myRange = document.getElementById("angleOfKeyRange");
		var myOutput = document.getElementById("angleOfKey");
		//copy the value over
		myOutput.value = myRange.value;
    AoK = myOutput.value*Math.PI/180;
	}
function updateLineLength(){
		//get elements
		var myRange = document.getElementById("lineLengthRange");
		var myOutput = document.getElementById("lineLength");
		//copy the value over
		myOutput.value = myRange.value;
    //line_length = myOutput.value;
	}
function setLineLength(){
		//get elements
		var myRange = document.getElementById("lineLengthRange");
		var myOutput = document.getElementById("lineLength");
		//copy the value over
		myOutput.value = Math.round(line_length*10)/10;
    myRange.value = line_length;
	}
function updateReelSpeed(){
		//get elements
		var myRange = document.getElementById("reelSpeedRange");
		var myOutput = document.getElementById("reelSpeed");
		//copy the value over
		myOutput.value = myRange.value;
    reel_speed = myOutput.value;
	}
  function updateWindVelocity(){
		//get elements
		var myRange = document.getElementById("windVelocityRange");
		var myOutput = document.getElementById("windVelocity");
		//copy the value over
		myOutput.value = myRange.value;
    wind_velocity = myOutput.value;
	}
  function updateKiteMass(){
		//get elements
		var myRange = document.getElementById("kiteMassRange");
		var myOutput = document.getElementById("kiteMass");
		//copy the value over
		myOutput.value = myRange.value;
    kite_mass = myOutput.value;
	}
  function updateKiteSurface(){
		//get elements
		var myRange = document.getElementById("kiteSurfaceRange");
		var myOutput = document.getElementById("kiteSurface");
		//copy the value over
		myOutput.value = myRange.value;
    kite_surface = myOutput.value;
	}
  function updateGravity(){
		//get elements

		var myCheck = document.getElementById("myCheck");
    g = earth_gravity*myCheck.checked;
	}
  function updateOutput(){
    var myOutput = document.getElementById("elevation");
    myOutput.value = Math.round(elevation*180/Math.PI*10)/10;

    myOutput = document.getElementById("time");
    myOutput.value = Math.round(simulation_time*100)/100;

    myOutput = document.getElementById("lineTension");
    myOutput.value = Math.round(line_tension*10)/100;

    myOutput = document.getElementById("kiteSpeed");
    myOutput.value = Math.round(omega*line_length*10)/10;
  }

<|endoftext|>