<commit_before>// Core of fnfnen.
// Variables  {{{1

var DUMMY_SINCE_ID = 1;
var MAX_COUNT = 200;
var TWITTER_API_URI = 'http://api.twitter.com/1/';
var TWITTER_UI_URI = 'http://twitter.com/';
var UPDATE_AT_START_P = false;  // FIXME: Should be true for daily use.
var UPDATE_INTERVAL = 5 * 60 * 1000;  // in milliseconds

var g_since_id = null;
var g_update_timer = null;
var g_user = null;

// Code  {{{1
function after_post()  //{{{2
{
  $('#tweet_box').val('');
  return;
}

function authenticate()  //{{{2
{
  call_twitter_api(TWITTER_UI_URI,
                   'account/verify_credentials',
                   {'callback': 'callback_authenticate'});
  return;
}

function callback_authenticate(d)
{
  if (d.error)
    return alert(d.error);

  g_user = d;

  update();
  return;
}

function before_post()  //{{{2
{
  // Update timeline manually.
  if ($('#tweet_box').val() == '') {
    update();
    return false;
  }

  // FIXME: Disable or warn too long tweet.
  return true;
}

function call_twitter_api(base_uri, api_name, _parameters)  //{{{2
{
  parameters = $.extend(false, _parameters, {'seq': g_seq++});

  var ps = [];
  for (var key in parameters)
    ps.push(key + '=' + parameters[key]);

  g_lcds_nodes[api_name] = load_cross_domain_script(
    base_uri + api_name + '.json' + '?' + ps.join('&'),
    g_lcds_nodes[api_name]
 );
}

var g_seq = (new Date).getTime();
var g_lcds_nodes = {}

function create_element(element_name)  //{{{2
{
  return $(document.createElement(element_name));
}

function html_from_tweet(tweet)  //{{{2
{
  // FIXME: Add a button to reply on a tweet.
  // FIXME: Add a button to retweet a tweet.
  // FIXME: Add a button to toggle "favorite".
  // FIXME: Add a link to the user of a tweet.
  // FIXME: Add the posted time of a tweet.
  // FIXME: Add the user's icon of a tweet.
  // FIXME: Expand abbreviated URIs in a tweet.
  // FIXME: Make links for URIs in a tweet.
  return (''
          /* screen name */
          + ''
          + tweet.user.screen_name
          + ''
          /* text */
          + ''
          + tweet.text
          + ''
         );
}

function load_cross_domain_script(uri, node)  //{{{2
{
  if (node && node.parentNode)
    node.parentNode.removeChild(node);

  node = document.createElement("script");
  node.src = uri;
  node.type = "text/javascript";
  document.body.appendChild(node);

  return node;
}

function scroll(y_coordinate)  //{{{2
{
  scrollTo(0, y_coordinate);
  return;
}

function show_tweets(d, node_column)  //{{{2
{
  // d = [{newest-tweet}, ..., {oldest-tweet}]
  if (d.length == 0)
    return 0;

  var node_tweet_hub = create_element('div');
  var node_dummy_tweet = create_element('div');

  node_tweet_hub.append(node_dummy_tweet);
  node_tweet_hub.addClass('tweet-hub');

  for (var i in d) {
    var node_tweet = create_element('div');
    node_tweet.addClass('tweet');
    node_tweet.attr('id', node_column.attr('id') + '-' + d[i].id);
    node_tweet.html(html_from_tweet(d[i]));
    node_tweet.data('json', d[i]);

    node_tweet_hub.prepend(node_tweet);
  }

  node_dummy_tweet.remove();

  node_column.append(node_tweet_hub);

  // Scroll to the head of the latest tweet hub.
  // FIXME: Customize behavior on this autoscroll.
  scroll(node_column.attr('scrollHeight')
         - node_tweet_hub.attr('scrollHeight'));
  return d.length;
}

function update()  //{{{2
{
  if (!g_user)
    return authenticate();

  call_twitter_api(TWITTER_API_URI,
                   'statuses/home_timeline',
                   {'callback': 'callback_update',
                    'count': MAX_COUNT,
                    'since_id': g_since_id || DUMMY_SINCE_ID});
  return;
}

function callback_update(d)
{
  $('#i_last_updated_time').text('Last updated: ' + new Date().toString());

  if (d.error)
  {
    $('#i_error_message').text(d.error);
    alert(d.error);
    return;
  }

  if (g_since_id) {
    for (var i = 0; i < d.length; i++) {
      if (d[i].id <= g_since_id)
        d.splice(i--, 1);
    }
  }

  var NEWEST_TWEET_INDEX = 0;
  g_since_id = d[NEWEST_TWEET_INDEX].id;

  show_tweets(d, $("#column_home"));
  return;
}

// Main  {{{1

$(document).ready(function(){
  // Misc.
  $('#column_home').empty();
  $('#i_error_message').empty();
  $('#tweet_box').val('');

  // To post.
    // Add a secret iframe to hide interaction with Twitter.
  var node_iframe = create_element('iframe');
  node_iframe.attr('id', 'post_iframe');
  node_iframe.attr('name', 'xpost');
  node_iframe.attr('src', 'about:blank');
  node_iframe.css('display', 'none');
  $('body').append(node_iframe);
  $('#post_form').attr('target', 'xpost');
    // Event handlers.
  $('#post_form').submit(before_post);
  $('#post_iframe').load(after_post);

  // To update.
  g_update_timer = setInterval(update, UPDATE_INTERVAL);

  if (UPDATE_AT_START_P)
    update();
});

// __END__  {{{1
// vim: expandtab shiftwidth=2 softtabstop=2
// vim: foldmethod=marker
<commit_msg>Refactor - Closurize call_twitter_api()<commit_after>// Core of fnfnen.
// Variables  {{{1

var DUMMY_SINCE_ID = 1;
var MAX_COUNT = 200;
var TWITTER_API_URI = 'http://api.twitter.com/1/';
var TWITTER_UI_URI = 'http://twitter.com/';
var UPDATE_AT_START_P = false;  // FIXME: Should be true for daily use.
var UPDATE_INTERVAL = 5 * 60 * 1000;  // in milliseconds

var g_since_id = null;
var g_update_timer = null;
var g_user = null;

// Code  {{{1
function after_post()  //{{{2
{
  $('#tweet_box').val('');
  return;
}

function authenticate()  //{{{2
{
  call_twitter_api(TWITTER_UI_URI,
                   'account/verify_credentials',
                   {'callback': 'callback_authenticate'});
  return;
}

function callback_authenticate(d)
{
  if (d.error)
    return alert(d.error);

  g_user = d;

  update();
  return;
}

function before_post()  //{{{2
{
  // Update timeline manually.
  if ($('#tweet_box').val() == '') {
    update();
    return false;
  }

  // FIXME: Disable or warn too long tweet.
  return true;
}

call_twitter_api = (function(){  //{{{2
  var s_seq = (new Date).getTime();  // To avoid browser-side caching.
  var s_lcds_nodes = {};  // {api_name: node_script, ...}

  return function(base_uri, api_name, _parameters) {
    parameters = $.extend(false, _parameters, {'seq': s_seq++});

    var ps = [];
    for (var key in parameters)
      ps.push(key + '=' + parameters[key]);

    s_lcds_nodes[api_name] = load_cross_domain_script(
      base_uri + api_name + '.json' + '?' + ps.join('&'),
      s_lcds_nodes[api_name]
   );
  }
})();

function create_element(element_name)  //{{{2
{
  return $(document.createElement(element_name));
}

function html_from_tweet(tweet)  //{{{2
{
  // FIXME: Add a button to reply on a tweet.
  // FIXME: Add a button to retweet a tweet.
  // FIXME: Add a button to toggle "favorite".
  // FIXME: Add a link to the user of a tweet.
  // FIXME: Add the posted time of a tweet.
  // FIXME: Add the user's icon of a tweet.
  // FIXME: Expand abbreviated URIs in a tweet.
  // FIXME: Make links for URIs in a tweet.
  return (''
          /* screen name */
          + ''
          + tweet.user.screen_name
          + ''
          /* text */
          + ''
          + tweet.text
          + ''
         );
}

function load_cross_domain_script(uri, node)  //{{{2
{
  if (node && node.parentNode)
    node.parentNode.removeChild(node);

  node = document.createElement("script");
  node.src = uri;
  node.type = "text/javascript";
  document.body.appendChild(node);

  return node;
}

function scroll(y_coordinate)  //{{{2
{
  scrollTo(0, y_coordinate);
  return;
}

function show_tweets(d, node_column)  //{{{2
{
  // d = [{newest-tweet}, ..., {oldest-tweet}]
  if (d.length == 0)
    return 0;

  var node_tweet_hub = create_element('div');
  var node_dummy_tweet = create_element('div');

  node_tweet_hub.append(node_dummy_tweet);
  node_tweet_hub.addClass('tweet-hub');

  for (var i in d) {
    var node_tweet = create_element('div');
    node_tweet.addClass('tweet');
    node_tweet.attr('id', node_column.attr('id') + '-' + d[i].id);
    node_tweet.html(html_from_tweet(d[i]));
    node_tweet.data('json', d[i]);

    node_tweet_hub.prepend(node_tweet);
  }

  node_dummy_tweet.remove();

  node_column.append(node_tweet_hub);

  // Scroll to the head of the latest tweet hub.
  // FIXME: Customize behavior on this autoscroll.
  scroll(node_column.attr('scrollHeight')
         - node_tweet_hub.attr('scrollHeight'));
  return d.length;
}

function update()  //{{{2
{
  if (!g_user)
    return authenticate();

  call_twitter_api(TWITTER_API_URI,
                   'statuses/home_timeline',
                   {'callback': 'callback_update',
                    'count': MAX_COUNT,
                    'since_id': g_since_id || DUMMY_SINCE_ID});
  return;
}

function callback_update(d)
{
  $('#i_last_updated_time').text('Last updated: ' + new Date().toString());

  if (d.error)
  {
    $('#i_error_message').text(d.error);
    alert(d.error);
    return;
  }

  if (g_since_id) {
    for (var i = 0; i < d.length; i++) {
      if (d[i].id <= g_since_id)
        d.splice(i--, 1);
    }
  }

  var NEWEST_TWEET_INDEX = 0;
  g_since_id = d[NEWEST_TWEET_INDEX].id;

  show_tweets(d, $("#column_home"));
  return;
}

// Main  {{{1

$(document).ready(function(){
  // Misc.
  $('#column_home').empty();
  $('#i_error_message').empty();
  $('#tweet_box').val('');

  // To post.
    // Add a secret iframe to hide interaction with Twitter.
  var node_iframe = create_element('iframe');
  node_iframe.attr('id', 'post_iframe');
  node_iframe.attr('name', 'xpost');
  node_iframe.attr('src', 'about:blank');
  node_iframe.css('display', 'none');
  $('body').append(node_iframe);
  $('#post_form').attr('target', 'xpost');
    // Event handlers.
  $('#post_form').submit(before_post);
  $('#post_iframe').load(after_post);

  // To update.
  g_update_timer = setInterval(update, UPDATE_INTERVAL);

  if (UPDATE_AT_START_P)
    update();
});

// __END__  {{{1
// vim: expandtab shiftwidth=2 softtabstop=2
// vim: foldmethod=marker
<|endoftext|>


<commit_before>var _ = require('lodash'),
    Showdown = require('showdown'),
    converter = new Showdown.converter(),
    startHtml = '',
    endHtml = '';

function renderAllPosts(posts) {
  var html = startHtml;
  posts.forEach(function (post) {
    html += converter.makeHtml(post.intro);
    html += 'read more...';
  });
  html += endHtml;
  return html;
}

function renderSinglePost(post) {
  var html = startHtml;
  html += converter.makeHtml(post.body);
  html += endHtml;
  return html;
}

exports.renderAllPosts = renderAllPosts;
exports.renderSinglePost = renderSinglePost;<commit_msg>add my name to the html snapshot<commit_after>var _ = require('lodash'),
    Showdown = require('showdown'),
    converter = new Showdown.converter(),
    startHtml = '
aaron haurwitz
',
    endHtml = '';

function renderAllPosts(posts) {
  var html = startHtml;
  posts.forEach(function (post) {
    html += converter.makeHtml(post.intro);
    html += 'read more...';
  });
  html += endHtml;
  return html;
}

function renderSinglePost(post) {
  var html = startHtml;
  html += converter.makeHtml(post.body);
  html += endHtml;
  return html;
}

exports.renderAllPosts = renderAllPosts;
exports.renderSinglePost = renderSinglePost;<|endoftext|>


<commit_before>_INJ = new Object();
(function() { //setup
var pre = document.getElementById('edoutput');
var cv = document.getElementById('injectedcanvas');
if (cv == null)
{
	cv = document.createElement('canvas');
	cv.id = 'injectedcanvas';
	cv.width = 800;
	cv.height = 800;
	pre.parentNode.insertBefore(cv, pre);
}
var ctx = cv.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, cv.width, cv.height);
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, 20, 20);
_INJ.element = cv;
_INJ.renderCtx = ctx;
_INJ.linkUpTimer = setInterval(isLinkReady, 1000);
_INJ.linkUp = false;
})();

function isLinkReady()
{
	if (_INJ.element.innerHTML == 'ready')
	{
		clearInterval(_INJ.linkUpTimer);
		delete _INJ.linkUpTimer;
		if (typeof onLinkReady === "function")
		{
			onLinkReady();
		}
	}
}
<commit_msg>Set the link status to 'up' when init done<commit_after>_INJ = new Object();
(function() { //setup
var pre = document.getElementById('edoutput');
var cv = document.getElementById('injectedcanvas');
if (cv == null)
{
	cv = document.createElement('canvas');
	cv.id = 'injectedcanvas';
	cv.width = 800;
	cv.height = 800;
	pre.parentNode.insertBefore(cv, pre);
}
var ctx = cv.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, cv.width, cv.height);
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, 20, 20);
_INJ.element = cv;
_INJ.renderCtx = ctx;
_INJ.linkUpTimer = setInterval(isLinkReady, 1000);
_INJ.linkUp = false;
})();

function isLinkReady()
{
	if (_INJ.element.innerHTML == 'ready')
	{
		clearInterval(_INJ.linkUpTimer);
		delete _INJ.linkUpTimer;
		_INJ.linkUp = true;
		if (typeof onLinkReady === "function")
		{
			onLinkReady();
		}
	}
}
<|endoftext|>


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

// imports
var cmd = require('node-cmd');
var async = require('async');
var fs = require('fs');
var yaml = require('js-yaml');

function preprocessChain(chain){
    if(typeof(chain) === 'object'){
        // try to build chains and mode
        if('series' in chain){
            chain['mode'] = 'series';
            chain['chains'] = chain['series'];
        }
        else if('parallel' in chain){
            chain['mode'] = 'parallel';
            chain['chains'] = chain['parallel'];
        }
    }
    return chain;
}

function preprocessIns(ins){
    if(typeof(ins) === 'string'){
        ins = ins.split(',');
        // trim the spaces
        newIns = [];
        ins.forEach(function(input){
            newIns.push(input.trim());
        });
        ins = newIns;
    }
    return ins;
}

function execute(chainConfigs, argv, presets, executeCallback){
    // don't do anything if chainConfigs is wrong
    if(typeof(chainConfigs) != 'object'){
        console.error('[ERROR] Unable to fetch chain');
        executeCallback('', false);
        return null;
    }

    // preprocessing
    chainConfigs = preprocessChain(chainConfigs);

    // get ins, out, vars, chains, mode, and verbose
    var ins     = 'ins' in chainConfigs? chainConfigs.ins: [];
    var out     = 'out' in chainConfigs? chainConfigs.out: '_';
    var vars    = 'vars' in chainConfigs? chainConfigs.vars: {};
    var chains  = 'chains' in chainConfigs? chainConfigs.chains: [];
    var mode    = 'mode' in chainConfigs? chainConfigs.mode: 'series';
    var verbose = 'verbose' in chainConfigs? chainConfigs.verbose: false;

    // secondary preprocessing in case of the chain config only contains single command
    if(typeof(chainConfigs) == 'object' && ('command' in chainConfigs)){
        chains = [{
            'command' : chainConfigs['command'],
            'ins' : ins,
            'out' : out,
        }];
    }

    // combine vars with presets
    if(typeof presets == 'object'){
        Object.keys(presets).forEach(function(key){
            vars[key] = presets[key];
        });
    }

    // preprocess "ins"
    ins = preprocessIns(ins);

    // populate "vars" based on "ins" and "process.argv"
    ins.forEach(function(key, index){
        if(typeof(argv) != 'array' && typeof(argv) != 'object'){
            argv = [];
        }
        if(index < argv.length){
            vars[key] = argv[index];
        }
        else if(!(key in vars)){
            vars[key] = 0;
        }
    });

    // run the chains
    runChains(chains, mode, true);

    // The sub functions ================================================

    // this will show the output, or use custom callback to process the output
    function lastProcessOutput(err, result){
        var output = 'out' in vars? vars.out: '';
        // execute the callback if defined, or show the output
        if(typeof(executeCallback) === 'function'){
            executeCallback(vars[out], true);
        }
        else{
            console.log(vars[out]);
        }
    }

    // get single chain command's executor
    function getChainRunner(chain){
        return function(callback){
            // get command, ins, and out
            var chainCommand = chain.command;
            var chainIns = 'ins' in chain? chain.ins : [];
            var chainOut = 'out' in chain? chain.out: '_';
            // preprocess "ins"
            chainIns = preprocessIns(chainIns);
            chainIns.forEach(function(key){
                var arg = '';
                if(typeof(vars[key]) == 'object'){
                    arg = JSON.stringify(vars[key]);
                }
                else{
                    arg = String(vars[key]);
                }
                arg = arg.replace(/"/g, '\\\"');
                arg = arg.replace(/\n/g, '\\n');
                chainCommand += ' "' + arg + '"';
            });
            // run the command
            cmd.get(chainCommand, function(data, err, stderr){
                if(verbose){
                    console.info('[INFO] Running: ' + chainCommand);
                }
                if(!err){
                    vars[chainOut] = data.trim();
                    if(verbose){
                        console.info('[INFO] States: ' + JSON.stringify(vars));
                    }
                    // run callback if there is no error
                    callback();
                }
                else{
                    console.info('[ERROR] Message: ' + stderr);
                    executeCallback('', false);
                }
            });
        };
    }

    // get actions that will be used in async process
    function getActions(chains){
        var actions = [];
        chains.forEach(function(chain){
            // preprocess chain if it is a string
            if(typeof(chain) == 'string'){
                chain = {'ins' : [], 'out' : '_', 'command' : chain};
            }
            // preprocess chain
            chain = preprocessChain(chain);
            // determine appropriate action for chain based on it's subChains exixtance
            if('chains' in chain){
                // chain has other subChains
                var subMode = 'mode' in chain? chain.mode: 'series';
                var subChains = 'chains' in chain? chain.chains: [];
                actions.push(function(callback){
                    runChains(subChains, subMode, false, callback);
                });
            }
            else{
                // chain doesn't have subChains
                actions.push(getChainRunner(chain));
            }
        });
        return actions;
    }

    // run async process
    function runChains(chains, mode, isCoreProcess, runCallback){
        // populate actions
        var actions = getActions(chains);
        // run actions
        if(mode == 'series'){
            // series
            if(isCoreProcess){
                async.series(actions, lastProcessOutput);
            }
            else{
                async.series(actions, runCallback);
            }
        }
        else if(mode == 'parallel'){
            // parallel
            if(isCoreProcess){
                async.parallel(actions, lastProcessOutput);
            }
            else{
                async.parallel(actions, runCallback);
            }
        }
    }

}

function executeYaml(parameter, argv, presets, executeCallback){
    fs.readFile(parameter, function(err, data){
        var chainConfigs = {};
        var currentPath = process.cwd();
        if(!err){
            // parameter is a file
            var parameterParts = parameter.split('/');
            if(parameterParts.length > 1){
                // perform chdir if necessary
                var pathParts = parameterParts.slice(0,-1);
                var path = pathParts.join('/');
                process.chdir(path);
            }
            chainConfigs = yaml.safeLoad(data);
        }
        else{
            // parameter is a json, not a file
            chainConfigs = yaml.safeLoad(parameter);
        }
        // ensure we going back to this directory
        alteredCallback = function(response, success){
            // ensure we return to current dir
            process.chdir(currentPath);
            // execute callback
            if(typeof(executeCallback) === 'function'){
                executeCallback(response, success);
            }
        }
        execute(chainConfigs, argv, presets, alteredCallback);
    });
}

// This will be executed when someone run this module manually
if(require.main === module){
    if(process.argv.length > 2){
        // first argument of the program (start from 2) is chain name or json
        var parameter = process.argv[2];
        // second until last arguments are input of the first chain
        var argv = process.argv.slice(3);
        // execute Yaml
        executeYaml(parameter, argv);
    }
    else{
        // show missing arguments warning
        console.error('Missing Arguments');
        console.error('USAGE:');
        console.error('* ' + process.argv[1] + ' [chain-file]');
        console.error('* ' + process.argv[1] + ' [yaml-formatted-chain]');
    }
}

// The exported resources
module.exports = {
    'execute' : execute,
    'executeYaml' : executeYaml
};
<commit_msg>fix minor error<commit_after>#! /usr/bin/env node

// imports
var cmd = require('node-cmd');
var async = require('async');
var fs = require('fs');
var yaml = require('js-yaml');

function preprocessChain(chain){
    if(typeof(chain) === 'object'){
        // try to build chains and mode
        if('series' in chain){
            chain['mode'] = 'series';
            chain['chains'] = chain['series'];
        }
        else if('parallel' in chain){
            chain['mode'] = 'parallel';
            chain['chains'] = chain['parallel'];
        }
    }
    return chain;
}

function preprocessIns(ins){
    if(typeof(ins) === 'string'){
        ins = ins.split(',');
        // trim the spaces
        newIns = [];
        ins.forEach(function(input){
            newIns.push(input.trim());
        });
        ins = newIns;
    }
    return ins;
}

function execute(chainConfigs, argv, presets, executeCallback){
    // don't do anything if chainConfigs is wrong
    if(typeof(chainConfigs) != 'object'){
        console.error('[ERROR] Unable to fetch chain');
        executeCallback('', false);
        return null;
    }

    // preprocessing
    chainConfigs = preprocessChain(chainConfigs);

    // get ins, out, vars, chains, mode, and verbose
    var ins     = 'ins' in chainConfigs? chainConfigs.ins: [];
    var out     = 'out' in chainConfigs? chainConfigs.out: '_';
    var vars    = 'vars' in chainConfigs? chainConfigs.vars: {};
    var chains  = 'chains' in chainConfigs? chainConfigs.chains: [];
    var mode    = 'mode' in chainConfigs? chainConfigs.mode: 'series';
    var verbose = 'verbose' in chainConfigs? chainConfigs.verbose: false;

    // secondary preprocessing in case of the chain config only contains single command
    if(typeof(chainConfigs) == 'object' && ('command' in chainConfigs)){
        chains = [{
            'command' : chainConfigs['command'],
            'ins' : ins,
            'out' : out,
        }];
    }

    // combine vars with presets
    if(typeof presets == 'object'){
        Object.keys(presets).forEach(function(key){
            vars[key] = presets[key];
        });
    }

    // preprocess "ins"
    ins = preprocessIns(ins);

    // populate "vars" based on "ins" and "process.argv"
    ins.forEach(function(key, index){
        if(typeof(argv) != 'array' && typeof(argv) != 'object'){
            argv = [];
        }
        if(index < argv.length){
            vars[key] = argv[index];
        }
        else if(!(key in vars)){
            vars[key] = 0;
        }
    });

    // run the chains
    runChains(chains, mode, true);

    // The sub functions ================================================

    // this will show the output, or use custom callback to process the output
    function lastProcessOutput(err, result){
        var output = 'out' in vars? vars.out: '';
        // execute the callback if defined, or show the output
        if(typeof(executeCallback) === 'function'){
            executeCallback(vars[out], true);
        }
        else{
            console.log(vars[out]);
        }
    }

    // get single chain command's executor
    function getChainRunner(chain){
        return function(callback){
            // get command, ins, and out
            var chainCommand = chain.command;
            var chainIns = 'ins' in chain? chain.ins : [];
            var chainOut = 'out' in chain? chain.out: '_';
            // preprocess "ins"
            chainIns = preprocessIns(chainIns);
            chainIns.forEach(function(key){
                var arg = '';
                if(typeof(vars[key]) == 'object'){
                    arg = JSON.stringify(vars[key]);
                }
                else{
                    arg = String(vars[key]);
                }
                arg = arg.replace(/"/g, '\\\"');
                arg = arg.replace(/\n/g, '\\n');
                chainCommand += ' "' + arg + '"';
            });
            // run the command
            cmd.get(chainCommand, function(data, err, stderr){
                if(verbose){
                    console.info('[INFO] Running: ' + chainCommand);
                }
                if(!err){
                    vars[chainOut] = data.trim();
                    if(verbose){
                        console.info('[INFO] States: ' + JSON.stringify(vars));
                    }
                    // run callback if there is no error
                    callback();
                }
                else{
                    console.info('[ERROR] Message: ' + stderr);
                    executeCallback('', false);
                }
            });
        };
    }

    // get actions that will be used in async process
    function getActions(chains){
        var actions = [];
        chains.forEach(function(chain){
            // preprocess chain if it is a string
            if(typeof(chain) == 'string'){
                chain = {'ins' : [], 'out' : '_', 'command' : chain};
            }
            // preprocess chain
            chain = preprocessChain(chain);
            // determine appropriate action for chain based on it's subChains exixtance
            if('chains' in chain){
                // chain has other subChains
                var subMode = 'mode' in chain? chain.mode: 'series';
                var subChains = 'chains' in chain? chain.chains: [];
                actions.push(function(callback){
                    runChains(subChains, subMode, false, callback);
                });
            }
            else{
                // chain doesn't have subChains
                actions.push(getChainRunner(chain));
            }
        });
        return actions;
    }

    // run async process
    function runChains(chains, mode, isCoreProcess, runCallback){
        // populate actions
        var actions = getActions(chains);
        // run actions
        if(mode == 'series'){
            // series
            if(isCoreProcess){
                async.series(actions, lastProcessOutput);
            }
            else{
                async.series(actions, runCallback);
            }
        }
        else if(mode == 'parallel'){
            // parallel
            if(isCoreProcess){
                async.parallel(actions, lastProcessOutput);
            }
            else{
                async.parallel(actions, runCallback);
            }
        }
    }

}

function executeYaml(parameter, argv, presets, executeCallback){
    fs.readFile(parameter, function(err, data){
        var chainConfigs = {};
        var currentPath = process.cwd();
        if(!err){
            // parameter is a file
            var parameterParts = parameter.split('/');
            if(parameterParts.length > 1){
                // perform chdir if necessary
                var pathParts = parameterParts.slice(0,-1);
                var path = pathParts.join('/');
                process.chdir(path);
            }
            chainConfigs = yaml.safeLoad(data);
        }
        else{
            // parameter is a json, not a file
            chainConfigs = yaml.safeLoad(parameter);
        }
        // ensure we going back to this directory
        alteredCallback = function(response, success){
            // ensure we return to current dir
            process.chdir(currentPath);
            // execute callback
            if(typeof(executeCallback) === 'function'){
                executeCallback(response, success);
            }
        }
        execute(chainConfigs, argv, presets, alteredCallback);
    });
}

// This will be executed when someone run this module manually
if(require.main === module){
    if(process.argv.length > 2){
        // first argument of the program (start from 2) is chain name or json
        var parameter = process.argv[2];
        // second until last arguments are input of the first chain
        var argv = process.argv.slice(3);
        // execute Yaml
        executeYaml(parameter, argv, {}, console.log);
    }
    else{
        // show missing arguments warning
        console.error('Missing Arguments');
        console.error('USAGE:');
        console.error('* ' + process.argv[1] + ' [chain-file]');
        console.error('* ' + process.argv[1] + ' [yaml-formatted-chain]');
    }
}

// The exported resources
module.exports = {
    'execute' : execute,
    'executeYaml' : executeYaml
};
<|endoftext|>


<commit_before>/**
 * Core
 * Created by CreaturePhil - https://github.com/CreaturePhil
 *
 * This is where essential core infrastructure of
 * Pokemon Showdown extensions for private servers.
 * Core contains standard streams, profile infrastructure,
 * elo rating calculations, and polls infrastructure.
 *
 * @license MIT license
 */

var fs = require("fs");
var path = require("path");

var core = exports.core = {

    stdin: function (file, name) {
        var data = fs.readFileSync('config/' + file + '.csv', 'utf8').split('\n');

        var len = data.length;
        while (len--) {
            if (!data[len]) continue;
            var parts = data[len].split(',');
            if (parts[0].toLowerCase() === name) {
                return parts[1];
            }
        }
        return 0;
    },

    stdout: function (file, name, info, callback) {
        var data = fs.readFileSync('config/' + file + '.csv', 'utf8').split('\n');
        var match = false;

        var len = data.length;
        while (len--) {
            if (!data[len]) continue;
            var parts = data[len].split(',');
            if (parts[0] === name) {
                data = data[len];
                match = true;
                break;
            }
        }

        if (match === true) {
            var re = new RegExp(data, 'g');
            fs.readFile('config/' + file + '.csv', 'utf8', function (err, data) {
                if (err) return console.log(err);

                var result = data.replace(re, name + ',' + info);
                fs.writeFile('config/' + file + '.csv', result, 'utf8', function (err) {
                    if (err) return console.log(err);
                    typeof callback === 'function' && callback();
                });
            });
        } else {
            var log = fs.createWriteStream('config/' + file + '.csv', {
                'flags': 'a'
            });
            log.write('\n' + name + ',' + info);
            typeof callback === 'function' && callback();
        }
    },

    profile: {

        color: '#2ECC40',

        avatar: function (online, user, img) {
            if (online === true) {
                if (typeof (img) === typeof ('')) {
                    return '';
                }
                return '';
            }
            for (var name in Config.customAvatars) {
                if (user === name) {
                    return '';
                }
            }
            var trainersprites = [1, 2, 101, 102, 169, 170, 265, 266, 168];
            return '';
        },

        name: function (online, user) {
            if (online === true) {
                return ' Name: ' + user.name;
            }
            return ' Name: ' + user;
        },

        group: function (online, user) {
            if (online === true) {
                if (user.group === ' ') {
                    return '
 Group: ' + 'Regular User';
                }
                return '
 Group: ' + Config.groups[user.group].name;
            }
            var g = Core.stdin('usergroups', user);
            if (g === 0) {
                return '
 Group: ' + 'Regular User';
            }
            return '
 Group: ' + Config.groups[g].name;
        },

        lastSeen: function (online, user) {
            var lastSeen;

            if (online === true) {
                if (user.connected === true) {
                    return '
 Last Seen: Current Online';
                }
                lastSeen = Number(Core.stdin('lastSeen', user.userid));
            } else {
                lastSeen = Number(Core.stdin('lastSeen', user));
            }

            if (lastSeen === 0) return '
 Last Seen: Never';

            var seconds = Math.floor((Date.now() - lastOn) * 0.001);
            var minutes = Math.floor((Date.now() - lastOn) * 1.6667e-5);
            var hours = Math.floor((Date.now() - lastOn) * 2.7778e-7);
            var days = Math.floor(((Date.now() - lastOn) * 2.7778e-7) / 24);

            var time = days + ' days ago';

            if (seconds < 60) {
                if (seconds === 1) {
                    time = seconds + ' second ago';
                }
                time = seconds + ' seconds ago';
            }
            if (minutes < 60) {
                if (minutes === 1) {
                    time = minutes + ' minute ago';
                }
                time = minutes + ' minutes ago';
            }
            if (hours < 24) {
                if (hours === 1) {
                    time = hours + ' hour ago';
                }
                time = hours + ' hours ago';
            }
            if (days === 1) {
                time = days + ' day ago';
            }

            return '
 Last Seen: ' + time;
        },

        about: function (user) {
            return Core.stdin('about', user);
        },

        money: function (user) {
            return Core.stdin('money', user);
        },

        tournamentElo: function (user) {
            var elo = Core.stdin('elo', user);
            if (elo === 0) {
                return 1000;
            }
            return Math.floor(Number(elo));
        },

        rank: function (user) {
            var data = fs.readFileSync('config/elo.csv', 'utf-8');
            var row = ('' + data).split("\n");

            var list = [];

            for (var i = row.length; i > -1; i--) {
                if (!row[i]) continue;
                var parts = row[i].split(",");
                list.push([toId(parts[0]), Number(parts[1])]);
            }

            list.sort(function (a, b) {
                return a[1] - b[1];
            });
            var arr = list.filter(function (el) {
                return !!~el.indexOf(user);
            });

            return ' (Rank ' + (list.length - list.indexOf(arr[0])) + ' out of ' + list.length + ' players)';
        },

        display: function (args, info, option) {
            if (args === 'about') return '
 About: ' + info;
            if (args === 'money') return '
 Money: ' + info;
            if (args === 'elo') return '
 Tournament Elo: ' + info + option;
        },

    },

    calculateElo: function (winner, loser) {
        if (winner === 0) winner = 1000;
        if (loser === 0) loser = 1000;
        var kFactor = 32;
        var ratingDifference = loser - winner;
        var expectedScoreWinner = 1 / (1 + Math.pow(10, ratingDifference / 400));

        var e = kFactor * (1 - expectedScoreWinner);
        winner = winner + e;
        loser = loser - e;

        var arr = [winner, loser];
        return arr;
    },

    ladder: function () {
        var data = fs.readFileSync('config/elo.csv', 'utf-8');
        var row = ('' + data).split("\n");

        var list = [];

        for (var i = row.length; i > -1; i--) {
            if (!row[i]) continue;
            var parts = row[i].split(",");
            list.push([toId(parts[0]), Number(parts[1])]);
        }

        list.sort(function (a, b) {
            return a[1] - b[1];
        });

        if (list.length > 1) {
            var ladder = '

Rank	User	Tournament Elo	Tournament Wins
';
            var len = list.length;
            while (len--) {
                ladder = ladder + '
' + (list.length - len) + '	' + list[len][0] + '	' + Math.floor(list[len][1]) + '	' + this.stdin('tourWins', list[len][0]) + '
';
            }
            ladder += '

';
            return ladder;
        }
        return 0;
    },

    shop: function (showDisplay) {
        var shop = [
            ['Symbol', 'Buys a custom symbol to go infront of name and puts you at top of userlist. (temporary until restart)', 5],
            ['Fix', 'Buys the ability to alter your current custom avatar or trainer card. (don\'t buy if you have neither)', 10],
            ['Poof', 'Buys the ability to add a custom poof.', 15],
            ['Custom', 'Buys a custom avatar to be applied to your name. (you supply)', 20],
            ['Animated', 'Buys an animated avatar to be applied to your name. (you supply)', 25],
            ['Trainer', 'Buys a trainer card which shows information through a command such as /blakjack.', 30],
            ['Room', 'Buys a chatroom for you to own. (within reason, can be refused)', 50]
        ];

        if (showDisplay === false) {
            return shop;
        }

        var shopName = 'Shop';

        var s = '
' + shopName + '

Command	Description	Cost
';
        var start = 0;
        while (start < shop.length) {
            s = s + '
' + shop[start][0] + '	' + shop[start][1] + '	' + shop[start][2] + '
';
            start++;
        }
        s += '

To buy an item from the shop, use /buy command.
';
        return s;
    },

    poll: function () {
        var poll = {};
        var components = {

            reset: function (roomId) {
                poll[roomId] = {
                    question: undefined,
                    optionList: [],
                    options: {},
                    display: ''
                };
            },

            splint: function (target) {
                var parts = target.split(',');
                var len = parts.length;
                while (len--) {
                    parts[len] = parts[len].trim();
                }
                return parts;
            }

        };

        for (var i in components) {
            if (components.hasOwnProperty(i)) {
                poll[i] = components[i];
            }
        }

        for (var id in Rooms.rooms) {
            if (Rooms.rooms[id].type === 'chat' && !poll[id]) {
                poll[id] = {};
                poll.reset(id);
            }
        }

        return poll;
    },

};<commit_msg>More fixes for lastSeen<commit_after>/**
 * Core
 * Created by CreaturePhil - https://github.com/CreaturePhil
 *
 * This is where essential core infrastructure of
 * Pokemon Showdown extensions for private servers.
 * Core contains standard streams, profile infrastructure,
 * elo rating calculations, and polls infrastructure.
 *
 * @license MIT license
 */

var fs = require("fs");
var path = require("path");

var core = exports.core = {

    stdin: function (file, name) {
        var data = fs.readFileSync('config/' + file + '.csv', 'utf8').split('\n');

        var len = data.length;
        while (len--) {
            if (!data[len]) continue;
            var parts = data[len].split(',');
            if (parts[0].toLowerCase() === name) {
                return parts[1];
            }
        }
        return 0;
    },

    stdout: function (file, name, info, callback) {
        var data = fs.readFileSync('config/' + file + '.csv', 'utf8').split('\n');
        var match = false;

        var len = data.length;
        while (len--) {
            if (!data[len]) continue;
            var parts = data[len].split(',');
            if (parts[0] === name) {
                data = data[len];
                match = true;
                break;
            }
        }

        if (match === true) {
            var re = new RegExp(data, 'g');
            fs.readFile('config/' + file + '.csv', 'utf8', function (err, data) {
                if (err) return console.log(err);

                var result = data.replace(re, name + ',' + info);
                fs.writeFile('config/' + file + '.csv', result, 'utf8', function (err) {
                    if (err) return console.log(err);
                    typeof callback === 'function' && callback();
                });
            });
        } else {
            var log = fs.createWriteStream('config/' + file + '.csv', {
                'flags': 'a'
            });
            log.write('\n' + name + ',' + info);
            typeof callback === 'function' && callback();
        }
    },

    profile: {

        color: '#2ECC40',

        avatar: function (online, user, img) {
            if (online === true) {
                if (typeof (img) === typeof ('')) {
                    return '';
                }
                return '';
            }
            for (var name in Config.customAvatars) {
                if (user === name) {
                    return '';
                }
            }
            var trainersprites = [1, 2, 101, 102, 169, 170, 265, 266, 168];
            return '';
        },

        name: function (online, user) {
            if (online === true) {
                return ' Name: ' + user.name;
            }
            return ' Name: ' + user;
        },

        group: function (online, user) {
            if (online === true) {
                if (user.group === ' ') {
                    return '
 Group: ' + 'Regular User';
                }
                return '
 Group: ' + Config.groups[user.group].name;
            }
            var g = Core.stdin('usergroups', user);
            if (g === 0) {
                return '
 Group: ' + 'Regular User';
            }
            return '
 Group: ' + Config.groups[g].name;
        },

        lastSeen: function (online, user) {
            var lastSeen;

            if (online === true) {
                if (user.connected === true) {
                    return '
 Last Seen: Current Online';
                }
                lastSeen = Number(Core.stdin('lastSeen', user.userid));
            } else {
                lastSeen = Number(Core.stdin('lastSeen', user));
            }

            if (lastSeen === 0) return '
 Last Seen: Never';

            var seconds = Math.floor((Date.now() - lastSeen) * 0.001);
            var minutes = Math.floor((Date.now() - lastSeen) * 1.6667e-5);
            var hours = Math.floor((Date.now() - lastSeen) * 2.7778e-7);
            var days = Math.floor(((Date.now() - lastSeen) * 2.7778e-7) / 24);

            var time = days + ' days ago';

            if (seconds < 60) {
                if (seconds === 1) {
                    time = seconds + ' second ago';
                }
                time = seconds + ' seconds ago';
            }
            if (minutes < 60) {
                if (minutes === 1) {
                    time = minutes + ' minute ago';
                }
                time = minutes + ' minutes ago';
            }
            if (hours < 24) {
                if (hours === 1) {
                    time = hours + ' hour ago';
                }
                time = hours + ' hours ago';
            }
            if (days === 1) {
                time = days + ' day ago';
            }

            return '
 Last Seen: ' + time;
        },

        about: function (user) {
            return Core.stdin('about', user);
        },

        money: function (user) {
            return Core.stdin('money', user);
        },

        tournamentElo: function (user) {
            var elo = Core.stdin('elo', user);
            if (elo === 0) {
                return 1000;
            }
            return Math.floor(Number(elo));
        },

        rank: function (user) {
            var data = fs.readFileSync('config/elo.csv', 'utf-8');
            var row = ('' + data).split("\n");

            var list = [];

            for (var i = row.length; i > -1; i--) {
                if (!row[i]) continue;
                var parts = row[i].split(",");
                list.push([toId(parts[0]), Number(parts[1])]);
            }

            list.sort(function (a, b) {
                return a[1] - b[1];
            });
            var arr = list.filter(function (el) {
                return !!~el.indexOf(user);
            });

            return ' (Rank ' + (list.length - list.indexOf(arr[0])) + ' out of ' + list.length + ' players)';
        },

        display: function (args, info, option) {
            if (args === 'about') return '
 About: ' + info;
            if (args === 'money') return '
 Money: ' + info;
            if (args === 'elo') return '
 Tournament Elo: ' + info + option;
        },

    },

    calculateElo: function (winner, loser) {
        if (winner === 0) winner = 1000;
        if (loser === 0) loser = 1000;
        var kFactor = 32;
        var ratingDifference = loser - winner;
        var expectedScoreWinner = 1 / (1 + Math.pow(10, ratingDifference / 400));

        var e = kFactor * (1 - expectedScoreWinner);
        winner = winner + e;
        loser = loser - e;

        var arr = [winner, loser];
        return arr;
    },

    ladder: function () {
        var data = fs.readFileSync('config/elo.csv', 'utf-8');
        var row = ('' + data).split("\n");

        var list = [];

        for (var i = row.length; i > -1; i--) {
            if (!row[i]) continue;
            var parts = row[i].split(",");
            list.push([toId(parts[0]), Number(parts[1])]);
        }

        list.sort(function (a, b) {
            return a[1] - b[1];
        });

        if (list.length > 1) {
            var ladder = '

Rank	User	Tournament Elo	Tournament Wins
';
            var len = list.length;
            while (len--) {
                ladder = ladder + '
' + (list.length - len) + '	' + list[len][0] + '	' + Math.floor(list[len][1]) + '	' + this.stdin('tourWins', list[len][0]) + '
';
            }
            ladder += '

';
            return ladder;
        }
        return 0;
    },

    shop: function (showDisplay) {
        var shop = [
            ['Symbol', 'Buys a custom symbol to go infront of name and puts you at top of userlist. (temporary until restart)', 5],
            ['Fix', 'Buys the ability to alter your current custom avatar or trainer card. (don\'t buy if you have neither)', 10],
            ['Poof', 'Buys the ability to add a custom poof.', 15],
            ['Custom', 'Buys a custom avatar to be applied to your name. (you supply)', 20],
            ['Animated', 'Buys an animated avatar to be applied to your name. (you supply)', 25],
            ['Trainer', 'Buys a trainer card which shows information through a command such as /blakjack.', 30],
            ['Room', 'Buys a chatroom for you to own. (within reason, can be refused)', 50]
        ];

        if (showDisplay === false) {
            return shop;
        }

        var shopName = 'Shop';

        var s = '
' + shopName + '

Command	Description	Cost
';
        var start = 0;
        while (start < shop.length) {
            s = s + '
' + shop[start][0] + '	' + shop[start][1] + '	' + shop[start][2] + '
';
            start++;
        }
        s += '

To buy an item from the shop, use /buy command.
';
        return s;
    },

    poll: function () {
        var poll = {};
        var components = {

            reset: function (roomId) {
                poll[roomId] = {
                    question: undefined,
                    optionList: [],
                    options: {},
                    display: ''
                };
            },

            splint: function (target) {
                var parts = target.split(',');
                var len = parts.length;
                while (len--) {
                    parts[len] = parts[len].trim();
                }
                return parts;
            }

        };

        for (var i in components) {
            if (components.hasOwnProperty(i)) {
                poll[i] = components[i];
            }
        }

        for (var id in Rooms.rooms) {
            if (Rooms.rooms[id].type === 'chat' && !poll[id]) {
                poll[id] = {};
                poll.reset(id);
            }
        }

        return poll;
    },

};<|endoftext|>


<commit_before>/**
 * This 'core' module is the `libffi` wrapper. All required native
 * functionality is instaniated and then exported in this module.
 */

var ffi = require('node-ffi')
  , types = require('./types')
  // TODO: These static ffi bindings could be replaced with native bindings
  //       for a speed boost.
  , objc = new ffi.Library('libobjc', {
      class_copyMethodList: [ 'pointer', [ 'pointer', 'pointer' ] ]
    , class_getClassMethod: [ 'pointer', [ 'pointer', 'pointer' ] ]
    , class_getInstanceMethod: [ 'pointer', [ 'pointer', 'pointer' ] ]
    , class_getInstanceSize: [ 'size_t', [ 'pointer' ] ]
    , class_getName: [ 'string', [ 'pointer' ] ]
    , class_getSuperclass: [ 'pointer', [ 'pointer' ] ]
    , class_getVersion: [ 'pointer', [ 'pointer' ] ]
    , method_getName: [ 'pointer', [ 'pointer' ] ]
    , method_copyReturnType: [ 'pointer', [ 'pointer' ] ]
    , method_copyArgumentType: [ 'pointer', [ 'pointer', 'uint32' ] ]
    , method_getNumberOfArguments: [ 'uint32', [ 'pointer' ] ]
    , objc_allocateClassPair: [ 'pointer', [ 'pointer', 'string', 'size_t' ] ]
    , objc_getClass: [ 'pointer', [ 'string' ] ]
    , objc_getClassList: [ 'int32', [ 'pointer', 'int32' ] ]
    , object_getClass: [ 'pointer', [ 'pointer' ] ]
    , object_getClassName: [ 'string', [ 'pointer' ] ]
    , sel_registerName: [ 'pointer', [ 'string' ] ]
    , sel_getName: [ 'string', [ 'pointer' ] ]
  })
  , msgSendCache = {}

exports.__proto__ = objc;

exports.Pointer = ffi.Pointer;

exports.dlopen = function dlopen (path) {
  return new ffi.DynamicLibrary(path);
}

exports.process = exports.dlopen();

/**
 * Convienience function to return an Array of Strings of the names of every
 * class currently in the runtime. This gets used at the during the import
 * process get a name of the new classes that have been loaded.
 * TODO: Could be replaced with a native binding someday for speed. Not overly
 *       important as this function is only called during import()
 */
exports.getClassList = function getClassList () {
  // First get just the count
  var num = objc.objc_getClassList(null, 0)
    , rtn = []
  if (num > 0) {
    var s = ffi.Bindings.TYPE_SIZE_MAP.pointer
      , c = null
      , classes = new ffi.Pointer(s * num)
      , cursor = classes
    objc.objc_getClassList(classes, num);
    for (var i=0; i<num; i++) {
      c = cursor.getPointer()
      rtn.push(objc.class_getName(c));
      cursor = cursor.seek(s);
    }
    // free() not needed since ffi allocated the buffer, and will free() with V8's GC
  }
  return rtn;
}

/**
 * Convienience function to get the String return type of a Method pointer.
 * Takes care of free()ing the returned pointer, as is required.
 */
exports.getMethodReturnType = function getMethodReturnType (method) {
  return getStringAndFree(objc.method_copyReturnType(method));
}

exports.getMethodArgTypes = function getMethodArgTypes (method) {
  var num = objc.method_getNumberOfArguments(method)
    , rtn = []
  for (var i=2; i<num; i++) {
    rtn.push(getStringAndFree(objc.method_copyArgumentType(method, i)));
  }
  return rtn;
}

function getStringAndFree (ptr) {
  var str = ptr.getCString()
  exports.free(ptr);
  return str;
}

// Creates and/or returns an appropriately wrapped up 'objc_msgSend' function
// based on the given Method description info.
exports.get_objc_msgSend = function get_objc_msgSend (objcTypes) {
  var type = ['pointer', 'pointer'] // id and SEL
    , rtn = [ types.map(objcTypes[0]), type ]
    , args = objcTypes[1]
    , i = 0
    , l = args.length
  for (; i<l; i++) {
    type.push(types.map(args[i]));
  }
  // Stringify the types
  var key = rtn.toString();
  //console.warn('INFO: types key: %s', key);

  // first check the cache
  if (msgSendCache[key]) return msgSendCache[key];
  //console.warn('WARN: key not found in cache, generating new copy: %s', key);

  // If we got here, then create a new objc_msgSend ffi wrapper
  // TODO: Don't use the Library helper, use ffi low-level API
  var lib = new ffi.Library(null, {
    objc_msgSend: rtn
  })
  // return and cache at the same time
  return msgSendCache[key] = lib.objc_msgSend;
}

exports.Function = function buildFunction (name, rtnType, argTypes, async, lib) {
  lib || (lib = exports.process);
  try {
    var symbol = lib.get(name);
    if (symbol.isNull()) throw new Error('Symbol not found: ' + name);
    return ffi.ForeignFunction.build(symbol, rtnType, argTypes, async);
  } catch (e) {
    //console.error(name, e.message);
  }
}

// Wrap the global free() function. Some of the ObjC runtime objects need
// explicit freeing.
exports.free = exports.Function('free', 'void', [ 'pointer' ], false);

exports.wrapValue = function wrapValue (val, type) {
  if (val === null || (val.isNull && val.isNull())) return null;
  if (type == '@') {
    val = exports._idwrap(val);
  } else if (type == '#') {
    val = exports._getClass(objc.class_getName(val));
  }
  return val;
}

exports.unwrapValue = function unwrapValue (val, type) {
  if (type == '@' || type == '#') {
    val = val.pointer;
  }
  return val;
}
<commit_msg>Better wrapValue() and unwrapValue().<commit_after>/**
 * This 'core' module is the `libffi` wrapper. All required native
 * functionality is instaniated and then exported in this module.
 */

var ffi = require('node-ffi')
  , types = require('./types')
  , SEL = require('./sel')
  // TODO: These static ffi bindings could be replaced with native bindings
  //       for a speed boost.
  , objc = new ffi.Library('libobjc', {
      class_copyMethodList: [ 'pointer', [ 'pointer', 'pointer' ] ]
    , class_getClassMethod: [ 'pointer', [ 'pointer', 'pointer' ] ]
    , class_getInstanceMethod: [ 'pointer', [ 'pointer', 'pointer' ] ]
    , class_getInstanceSize: [ 'size_t', [ 'pointer' ] ]
    , class_getName: [ 'string', [ 'pointer' ] ]
    , class_getSuperclass: [ 'pointer', [ 'pointer' ] ]
    , class_getVersion: [ 'pointer', [ 'pointer' ] ]
    , method_getName: [ 'pointer', [ 'pointer' ] ]
    , method_copyReturnType: [ 'pointer', [ 'pointer' ] ]
    , method_copyArgumentType: [ 'pointer', [ 'pointer', 'uint32' ] ]
    , method_getNumberOfArguments: [ 'uint32', [ 'pointer' ] ]
    , objc_allocateClassPair: [ 'pointer', [ 'pointer', 'string', 'size_t' ] ]
    , objc_getClass: [ 'pointer', [ 'string' ] ]
    , objc_getClassList: [ 'int32', [ 'pointer', 'int32' ] ]
    , object_getClass: [ 'pointer', [ 'pointer' ] ]
    , object_getClassName: [ 'string', [ 'pointer' ] ]
    , sel_registerName: [ 'pointer', [ 'string' ] ]
    , sel_getName: [ 'string', [ 'pointer' ] ]
  })
  , msgSendCache = {}

exports.__proto__ = objc;

exports.Pointer = ffi.Pointer;

exports.dlopen = function dlopen (path) {
  return new ffi.DynamicLibrary(path);
}

exports.process = exports.dlopen();

/**
 * Convienience function to return an Array of Strings of the names of every
 * class currently in the runtime. This gets used at the during the import
 * process get a name of the new classes that have been loaded.
 * TODO: Could be replaced with a native binding someday for speed. Not overly
 *       important as this function is only called during import()
 */
exports.getClassList = function getClassList () {
  // First get just the count
  var num = objc.objc_getClassList(null, 0)
    , rtn = []
  if (num > 0) {
    var s = ffi.Bindings.TYPE_SIZE_MAP.pointer
      , c = null
      , classes = new ffi.Pointer(s * num)
      , cursor = classes
    objc.objc_getClassList(classes, num);
    for (var i=0; i<num; i++) {
      c = cursor.getPointer()
      rtn.push(objc.class_getName(c));
      cursor = cursor.seek(s);
    }
    // free() not needed since ffi allocated the buffer, and will free() with V8's GC
  }
  return rtn;
}

/**
 * Convienience function to get the String return type of a Method pointer.
 * Takes care of free()ing the returned pointer, as is required.
 */
exports.getMethodReturnType = function getMethodReturnType (method) {
  return getStringAndFree(objc.method_copyReturnType(method));
}

exports.getMethodArgTypes = function getMethodArgTypes (method) {
  var num = objc.method_getNumberOfArguments(method)
    , rtn = []
  for (var i=2; i<num; i++) {
    rtn.push(getStringAndFree(objc.method_copyArgumentType(method, i)));
  }
  return rtn;
}

function getStringAndFree (ptr) {
  var str = ptr.getCString()
  exports.free(ptr);
  return str;
}

// Creates and/or returns an appropriately wrapped up 'objc_msgSend' function
// based on the given Method description info.
exports.get_objc_msgSend = function get_objc_msgSend (objcTypes) {
  var type = ['pointer', 'pointer'] // id and SEL
    , rtn = [ types.map(objcTypes[0]), type ]
    , args = objcTypes[1]
    , i = 0
    , l = args.length
  for (; i<l; i++) {
    type.push(types.map(args[i]));
  }
  // Stringify the types
  var key = rtn.toString();
  //console.warn('INFO: types key: %s', key);

  // first check the cache
  if (msgSendCache[key]) return msgSendCache[key];
  //console.warn('WARN: key not found in cache, generating new copy: %s', key);

  // If we got here, then create a new objc_msgSend ffi wrapper
  // TODO: Don't use the Library helper, use ffi low-level API
  var lib = new ffi.Library(null, {
    objc_msgSend: rtn
  })
  // return and cache at the same time
  return msgSendCache[key] = lib.objc_msgSend;
}

exports.Function = function buildFunction (name, rtnType, argTypes, async, lib) {
  lib || (lib = exports.process);
  try {
    var symbol = lib.get(name);
    if (symbol.isNull()) throw new Error('Symbol not found: ' + name);
    return ffi.ForeignFunction.build(symbol, rtnType, argTypes, async);
  } catch (e) {
    //console.error(name, e.message);
  }
}

// Wrap the global free() function. Some of the ObjC runtime objects need
// explicit freeing.
exports.free = exports.Function('free', 'void', [ 'pointer' ], false);

exports.wrapValue = function wrapValue (val, type) {
  //console.error('wrapValue(): %s, %s', val, type);
  if (val === null || (val.isNull && val.isNull())) return null;
  var rtn = val;
  if (type == '@') {
    rtn = exports._idwrap(val);
  } else if (type == '#') {
    rtn = exports._getClass(objc.class_getName(val));
  } else if (type == ':') {
    rtn = SEL.toString(val);
  } else if (type == 'B') {
    rtn = val ? true : false;
  }
  return rtn;
}

exports.unwrapValue = function unwrapValue (val, type) {
  //console.error('unwrapValue(): %s, %s', val, type);
  var rtn = val;
  if (type == '@' || type == '#') {
    rtn = val.pointer;
  } else if (type == ':') {
    rtn = SEL.toSEL(val);
  }
  return rtn;
}
<|endoftext|>


<commit_before>angular.module('auction')
  .config(['$translateProvider', function($translateProvider) {
    $translateProvider.translations('en', {
      'Announcement': 'Announcement',
      'Bid': 'Bid',
      'Bidder': 'Bidder',
      'Bidding': 'Bidding',
      'English': 'English',
      'Russian': 'Russian',
      'Ukrainian': 'Ukrainian',
      'Edit': 'Edit',
      'Info': 'Info',
      'Initial bids': 'Initial bids',
      'Login in as viewer': 'Login in as viewer',
      'Login in as': 'Login in as',
      'Place a bid': 'Place a bid',
      'Preliminary bids': 'Preliminary bids',
      'Round': 'Round',
      'Settings': 'Settings',
      'Time': 'Time',
      'You': 'You',
      'All bidders': 'All bidders',
      'Pause': 'Pause',
      'Results Release': 'Results Release',
      'or lower': 'or lower',
      'UAH': 'UAH',
      'shortTime': 'h:mm a',
      'Restart sync': 'Restart sync',
      'To low value': 'To low value',
      'To high value': 'To high value',
      'Not valid bidder': 'Not valid bidder',
      'Stage not for bidding': 'Stage not for bidding',
      'Bid placed': 'Bid placed',
      'Your proposal': 'Your proposal :',
      'Finish': 'Finish',
      'days': 'days',
      'hours': 'hr',
      'minutes': 'min',
      'seconds': 'sec',
      'minimum': 'minimum',
      'until the auction starts': 'until the auction starts',
      'after the auction was completed': 'after the auction was completed',
      'until the round starts': 'until the round starts',
      'Internet connection is lost. Attempt to restart after 1 sec': 'Internet connection is lost. Attempt to restart after 1 sec',
      'Synchronization failed': 'Synchronization failed',
      'Possible results': 'Possible results',
      'In the room came a new user': 'In the room came a new user'
    });

    $translateProvider.translations('uk', {
      'Announcement': 'Оголошення результатів',
      'Bid': 'Заявка',
      'Bidder': 'Учасник',
      'Bidding': 'Торги',
      'English': 'Англійська',
      'Russian': 'Російська',
      'Ukrainian': 'Українська',
      'Edit': 'Змінити',
      'Info': 'Інформація',
      'Initial bids': 'Початкові заявки',
      'Login in as viewer': 'Вхід в якості глядача',
      'Login in as': 'Вхід в якості ',
      'Place a bid': 'Зробити заявку',
      'Preliminary bids': 'Попередні заявки',
      'Round': 'Раунд',
      'Settings': 'Налаштування',
      'Time': 'Час',
      'You': 'Ви',
      'All bidders': 'Всі учасники торгів',
      'Pause': 'Пауза',
      'Results Release': 'Результати',
      'or lower': 'або менше',
      'UAH': 'грн',
      'shortTime': 'HH:mm',
      'Restart sync': 'Перезапуск синхронізації',
      'To low value': 'Надто низька заявка',
      'To high value': 'Надто висока заявка',
      'Not valid bidder': 'Ви не є валідний користувачем',
      'Stage not for bidding': 'Даний етап аукціону не передбачає приймання заявок',
      'Bid placed': 'Заявку прийнято',
      'Your proposal :': 'Ваша заявка:',
      'Finish': 'Завершено',
      'days': 'днів',
      'hours': 'год',
      'minutes': 'хв',
      'seconds': 'сек',
      'minimum': 'мінімум',
      'until the auction starts': 'до початку аукціону',
      'after the auction was completed': 'після завершення аукціону',
      'until the round starts': 'до початку наступного раунду',
      'Internet connection is lost. Attempt to restart after 1 sec': 'З\'єднання з інтернетом втрачено. спроба перезавантаження через 1 сек',
      'Synchronization failed': 'Помилка синхронізації',
      'Possible results': 'Можливі результати',
      'In the room came a new user': 'В кабінет зайшов новий користувач'
    });

    $translateProvider.translations('ru', {
      'Announcement': 'Объявление результатов',
      'Bid': 'Ставка',
      'Bidder': ' Участник',
      'Bidding': 'Торги',
      'English': 'Английский',
      'Russian': 'Русский',
      'Ukrainian': 'Украинский',
      'Edit': 'Изменить',
      'Info': 'Информация',
      'Initial bids': 'Первоначальные ставки',
      'Login in as viewer': 'Вход в качестве зрителя',
      'Login in as': 'Вход в качестве',
      'Place a bid': 'Сделать ставку',
      'Preliminary bids': 'Предварительные ставки',
      'Round': 'Раунд',
      'Settings': 'Настройки',
      'Time': 'Время',
      'You': 'Вы',
      'All bidders': 'Все участники торгов',
      'Pause': 'Пауза',
      'Results Release': 'Результаты',
      'or lower': 'или меньше',
      'UAH': 'грн',
      'shortTime': 'HH:mm',
      'Restart sync': 'Перезапуск синхронизации',
      'To low value': 'Слишком низкая ставка',
      'To high value': 'Слишком высокая ставка',
      'Not valid bidder': ' Вы не являетесь валидный пользователем',
      'Stage not for bidding': 'Данный этап аукциона не предусматривает приема ставок',
      'Bid placed': 'Ставку принято',
      'Your proposal :': 'Ваше предложение:',
      'Finish': 'Окончен',
      'days': 'дней',
      'hours': 'час',
      'minutes': 'мин',
      'seconds': 'сек',
      'minimum': 'минимум',
      'until the auction starts': 'до начала аукциона',
      'after the auction was completed': 'после окончания аукциона',
      'until the round starts': 'до начала раунда',
      'Internet connection is lost. Attempt to restart after 1 sec': 'Cоединения с интернетом потеряно. попытка перезагрузки через 1 сек',
      'Synchronization failed': 'Ошибка синхронизации',
      'Possible results': 'Возможные результаты',
      'In the room came a new user': 'В кабинет зашел новый пользователь'
    });
    $translateProvider.preferredLanguage('uk');
  }])<commit_msg>Added translations<commit_after>angular.module('auction')
  .config(['$translateProvider', function($translateProvider) {
    $translateProvider.translations('en', {
      'Announcement': 'Announcement',
      'Bid': 'Bid',
      'Bidder': 'Bidder',
      'Bidding': 'Bidding',
      'English': 'English',
      'Russian': 'Russian',
      'Ukrainian': 'Ukrainian',
      'Edit': 'Edit',
      'Info': 'Info',
      'Initial bids': 'Initial bids',
      'Login in as viewer': 'Login in as viewer',
      'Login in as': 'Login in as',
      'Place a bid': 'Place a bid',
      'Preliminary bids': 'Preliminary bids',
      'Round': 'Round',
      'Settings': 'Settings',
      'Time': 'Time',
      'You': 'You',
      'All bidders': 'All bidders',
      'Pause': 'Pause',
      'Results Release': 'Results Release',
      'or lower': 'or lower',
      'UAH': 'UAH',
      'shortTime': 'h:mm a',
      'Restart sync': 'Restart sync',
      'To low value': 'To low value',
      'To high value': 'To high value',
      'Not valid bidder': 'Not valid bidder',
      'Stage not for bidding': 'Stage not for bidding',
      'Bid placed': 'Bid placed',
      'Your proposal': 'Your proposal :',
      'Finish': 'Finish',
      'days': 'days',
      'hours': 'hr',
      'minutes': 'min',
      'seconds': 'sec',
      'minimum': 'minimum',
      'Internet connection is lost. Attempt to restart after 1 sec': 'Internet connection is lost. Attempt to restart after 1 sec',
      'Synchronization failed': 'Synchronization failed',
      'Possible results': 'Possible results',
      'In the room came a new user': 'In the room came a new user',
      'until the auction starts': 'until the auction starts',
      'until your turn': 'until your turn',
      'until your turn ends': 'until your turn ends',
      'until the round ends': 'until the round ends',
      'until the results announcement': 'until the results announcement',
      'after the auction was completed': 'after the auction was completed',
    });

    $translateProvider.translations('uk', {
      'Announcement': 'Оголошення результатів',
      'Bid': 'Заявка',
      'Bidder': 'Учасник',
      'Bidding': 'Торги',
      'English': 'Англійська',
      'Russian': 'Російська',
      'Ukrainian': 'Українська',
      'Edit': 'Змінити',
      'Info': 'Інформація',
      'Initial bids': 'Початкові заявки',
      'Login in as viewer': 'Вхід в якості глядача',
      'Login in as': 'Вхід в якості ',
      'Place a bid': 'Зробити заявку',
      'Preliminary bids': 'Попередні заявки',
      'Round': 'Раунд',
      'Settings': 'Налаштування',
      'Time': 'Час',
      'You': 'Ви',
      'All bidders': 'Всі учасники торгів',
      'Pause': 'Пауза',
      'Results Release': 'Результати',
      'or lower': 'або менше',
      'UAH': 'грн',
      'shortTime': 'HH:mm',
      'Restart sync': 'Перезапуск синхронізації',
      'To low value': 'Надто низька заявка',
      'To high value': 'Надто висока заявка',
      'Not valid bidder': 'Ви не є валідний користувачем',
      'Stage not for bidding': 'Даний етап аукціону не передбачає приймання заявок',
      'Bid placed': 'Заявку прийнято',
      'Your proposal :': 'Ваша заявка:',
      'Finish': 'Завершено',
      'days': 'днів',
      'hours': 'год',
      'minutes': 'хв',
      'seconds': 'сек',
      'minimum': 'мінімум',
      'Internet connection is lost. Attempt to restart after 1 sec': 'З\'єднання з інтернетом втрачено. спроба перезавантаження через 1 сек',
      'Synchronization failed': 'Помилка синхронізації',
      'Possible results': 'Можливі результати',
      'In the room came a new user': 'В кабінет зайшов новий користувач',
      'until the auction starts': 'до початку аукціону',
      'until your turn': 'до вашої черги',
      'until your turn ends': 'до закінчення вашої черги',
      'until the round ends': 'до закінчення раунду',
      'until the results announcement': 'до оголошення результатів',
      'after the auction was completed': 'після завершення аукціону'
    });

    $translateProvider.translations('ru', {
      'Announcement': 'Объявление результатов',
      'Bid': 'Ставка',
      'Bidder': ' Участник',
      'Bidding': 'Торги',
      'English': 'Английский',
      'Russian': 'Русский',
      'Ukrainian': 'Украинский',
      'Edit': 'Изменить',
      'Info': 'Информация',
      'Initial bids': 'Первоначальные ставки',
      'Login in as viewer': 'Вход в качестве зрителя',
      'Login in as': 'Вход в качестве',
      'Place a bid': 'Сделать ставку',
      'Preliminary bids': 'Предварительные ставки',
      'Round': 'Раунд',
      'Settings': 'Настройки',
      'Time': 'Время',
      'You': 'Вы',
      'All bidders': 'Все участники торгов',
      'Pause': 'Пауза',
      'Results Release': 'Результаты',
      'or lower': 'или меньше',
      'UAH': 'грн',
      'shortTime': 'HH:mm',
      'Restart sync': 'Перезапуск синхронизации',
      'To low value': 'Слишком низкая ставка',
      'To high value': 'Слишком высокая ставка',
      'Not valid bidder': ' Вы не являетесь валидный пользователем',
      'Stage not for bidding': 'Данный этап аукциона не предусматривает приема ставок',
      'Bid placed': 'Ставку принято',
      'Your proposal :': 'Ваше предложение:',
      'Finish': 'Окончен',
      'days': 'дней',
      'hours': 'час',
      'minutes': 'мин',
      'seconds': 'сек',
      'minimum': 'минимум',
      'Internet connection is lost. Attempt to restart after 1 sec': 'Cоединения с интернетом потеряно. попытка перезагрузки через 1 сек',
      'Synchronization failed': 'Ошибка синхронизации',
      'Possible results': 'Возможные результаты',
      'In the room came a new user': 'В кабинет зашел новый пользователь',
      'until the auction starts': 'до начала аукциона',
      'until your turn': 'до вашей очереди',
      'until your turn ends': 'до завершения вашей очереди',
      'until the round ends': ' до окончания раунда',
      'until the results announcement': 'до объявления результатов',
      'after the auction was completed': 'после окончания аукциона'
    });
    $translateProvider.preferredLanguage('uk');
  }]);<|endoftext|>


<commit_before>var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var webpack = require('webpack');
var UglifyJsPlugin = require('uglifyjs-webpack-plugin')
var getMiniAppCommonConfig = require('./getMiniAppCommonConfig.js');
var merge = require('webpack-merge')
var getMiniAppExportConfig = require("./component_export/getMiniAppExportConfig");

module.exports = function (options) {
  let {type, media} = options;
  var commonConfig = getMiniAppCommonConfig(options);
  var buildConfig = {
    plugins: [
      new webpack.HashedModuleIdsPlugin()
    ]
  }
  const miniMap = {
    wx: {
      cssReg: /(\.wxss|\.css)$/
    },
    alipay: {
      cssReg: /(\.acss|\.css)$/
    },
    baidu: {
      cssReg: /\.css$/
    }
  }
  const targetObj = miniMap[type];
  if (options.minimize) {
    buildConfig.plugins = [
      new OptimizeCSSPlugin({
        assetNameRegExp: targetObj.cssReg,
        cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }
      }),
      new UglifyJsPlugin({})
    ]
  }
  if (media === 'export') {
    return getMiniAppExportConfig(options);
  }
  return merge(commonConfig, buildConfig)
}
<commit_msg>fixbug<commit_after>var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var webpack = require('webpack');
var UglifyJsPlugin = require('uglifyjs-webpack-plugin')
var getMiniAppCommonConfig = require('./getMiniAppCommonConfig.js');
var merge = require('webpack-merge')
var getMiniAppExportConfig = require("./component_export/getMiniAppExportConfig");

module.exports = function (options) {
  let {type, media} = options;
  var commonConfig = getMiniAppCommonConfig(options);
  var buildConfig = {
    plugins: [
      new webpack.HashedModuleIdsPlugin()
    ]
  }
  const miniMap = {
    wx: {
      cssReg: /(\.wxss|\.css)$/
    },
    alipay: {
      cssReg: /(\.acss|\.css)$/
    },
    baidu: {
      cssReg: /\.css$/
    }
  }
  const targetObj = miniMap[type];
  if (options.minimize) {
    buildConfig.plugins = [
      new OptimizeCSSPlugin({
        assetNameRegExp: targetObj.cssReg,
        cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }
      }),
      new UglifyJsPlugin({})
    ]
  }
  if (media === 'export') {
    return getMiniAppExportConfig(merge(commonConfig, buildConfig), options);
  }
  return merge(commonConfig, buildConfig)
}
<|endoftext|>