<commit_before>import { Meteor }      from 'meteor/meteor';
import { FlowRouter }  from 'meteor/ostrio:flow-router-extra';
import { ReactiveVar } from 'meteor/reactive-var';

if (Meteor.isServer) {
  return;
}

const groupReactiveStrTitle    = 'Reactive GROUP TITLE';
const groupReactiveStrTitleNew = 'NEW Reactive GROUP TITLE';
const groupReactiveVarTitle    = new ReactiveVar(groupReactiveStrTitle);

const groupReactiveStrPrefix    = 'Reactive Group > ';
const groupReactiveVarPrefix    = new ReactiveVar(groupReactiveStrPrefix);

Meteor.startup(() => {
  try {
    FlowRouter.go('/');
  } catch (e) {
    // we're good
  }
});

const groupReactive = FlowRouter.group({
  prefix: '/group-reactive',
  title() {
    return groupReactiveVarTitle.get();
  },
  titlePrefix() {
    return groupReactiveVarPrefix.get();
  }
});

groupReactive.route('/groupPage1', {
  name: 'groupReactivePage1',
  action() {
    Meteor.setTimeout(() => {
      groupReactiveVarTitle.set(groupReactiveStrTitleNew);
    }, 256);
  }
});

const groupReactiveStrPage2Title    = 'Reactive Group page 2';
const groupReactiveStrPage2TitleNew = 'NEW Reactive Group page 2';
const groupReactiveVarPage2Title    = new ReactiveVar(groupReactiveStrPage2Title);

groupReactive.route('/groupPage2', {
  name: 'groupReactivePage2',
  title() {
    return groupReactiveVarPage2Title.get();
  },
  action() {
    Meteor.setTimeout(() => {
      groupReactiveVarPage2Title.set(groupReactiveStrPage2TitleNew);
    }, 256);
  }
});

const nestedGroupReactiveStrTitle    = 'LEVEL2 REACTIVE GROUP TITLE';
const nestedGroupReactiveStrTitleNew = 'NEW LEVEL2 REACTIVE GROUP TITLE';
const nestedGroupReactiveVarTitle    = new ReactiveVar(nestedGroupReactiveStrTitle);

const nestedGroupReactiveStrPrefix    = 'Reactive Group Level 2 > ';
const nestedGroupReactiveVarPrefix    = new ReactiveVar(nestedGroupReactiveStrPrefix);

const nestedReactiveGroup = groupReactive.group({
  prefix: '/level2',
  title() {
    return nestedGroupReactiveVarTitle.get();
  },
  titlePrefix() {
    return nestedGroupReactiveVarPrefix.get();
  }
});

nestedReactiveGroup.route('/withoutTitle', {
  name: 'reactivelvl2',
  action() {
    Meteor.setTimeout(() => {
      nestedGroupReactiveVarTitle.set(nestedGroupReactiveStrTitleNew);
    }, 256);
  }
});

const nestedGroupReactiveStrPagelvl2Title    = 'Reactive Level 2 page';
const nestedGroupReactiveStrPagelvl2TitleNew = 'NEW Reactive Level 2 page';
const nestedGroupReactiveVarPagelvl2Title    = new ReactiveVar(nestedGroupReactiveStrPagelvl2Title);

nestedReactiveGroup.route('/witTitle', {
  name: 'reactivelvl2Title',
  title() {
    return nestedGroupReactiveVarPagelvl2Title.get();
  },
  action() {
    Meteor.setTimeout(() => {
      nestedGroupReactiveVarPagelvl2Title.set(nestedGroupReactiveStrPagelvl2TitleNew);
    }, 256);
  }
});

Tinytest.addAsync('Group - Reactive - level 1 - no route title', function (test, next) {
  FlowRouter.go('groupReactivePage1');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrTitle);
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrTitleNew);
      next();
    }, 512);
  }, 10);
});

Tinytest.addAsync('Group - Reactive - level 1 - with route title', function (test, next) {
  FlowRouter.go('groupReactivePage2');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrPrefix + groupReactiveStrPage2Title);
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrPrefix + groupReactiveStrPage2TitleNew);
      next();
    }, 512);
  }, 10);
});

Tinytest.addAsync('Group - Reactive - level 2 - no route title', function (test, next) {
  FlowRouter.go('reactivelvl2');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrTitle);
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrTitleNew);
      next();
    }, 512);
  }, 10);
});

Tinytest.addAsync('Group - Reactive - level 2 - with route title', function (test, next) {
  FlowRouter.go('reactivelvl2Title');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrPrefix + nestedGroupReactiveStrPagelvl2Title, 'before reactive update');
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrPrefix + nestedGroupReactiveStrPagelvl2TitleNew, 'after reactive update');
      next();
    }, 512);
  }, 10);
});
<commit_msg>Tests typo fix<commit_after>import { Meteor }      from 'meteor/meteor';
import { FlowRouter }  from 'meteor/ostrio:flow-router-extra';
import { ReactiveVar } from 'meteor/reactive-var';

if (Meteor.isServer) {
  return;
}

const groupReactiveStrTitle    = 'Reactive GROUP TITLE';
const groupReactiveStrTitleNew = 'NEW Reactive GROUP TITLE';
const groupReactiveVarTitle    = new ReactiveVar(groupReactiveStrTitle);

const groupReactiveStrPrefix    = 'Reactive Group > ';
const groupReactiveVarPrefix    = new ReactiveVar(groupReactiveStrPrefix);

Meteor.startup(() => {
  try {
    FlowRouter.go('/');
  } catch (e) {
    // we're good
  }
});

const groupReactive = FlowRouter.group({
  prefix: '/group-reactive',
  title() {
    return groupReactiveVarTitle.get();
  },
  titlePrefix() {
    return groupReactiveVarPrefix.get();
  }
});

groupReactive.route('/groupPage1', {
  name: 'groupReactivePage1',
  action() {
    Meteor.setTimeout(() => {
      groupReactiveVarTitle.set(groupReactiveStrTitleNew);
    }, 256);
  }
});

const groupReactiveStrPage2Title    = 'Reactive Group page 2';
const groupReactiveStrPage2TitleNew = 'NEW Reactive Group page 2';
const groupReactiveVarPage2Title    = new ReactiveVar(groupReactiveStrPage2Title);

groupReactive.route('/groupPage2', {
  name: 'groupReactivePage2',
  title() {
    return groupReactiveVarPage2Title.get();
  },
  action() {
    Meteor.setTimeout(() => {
      groupReactiveVarPage2Title.set(groupReactiveStrPage2TitleNew);
    }, 256);
  }
});

const nestedGroupReactiveStrTitle    = 'LEVEL2 REACTIVE GROUP TITLE';
const nestedGroupReactiveStrTitleNew = 'NEW LEVEL2 REACTIVE GROUP TITLE';
const nestedGroupReactiveVarTitle    = new ReactiveVar(nestedGroupReactiveStrTitle);

const nestedGroupReactiveStrPrefix    = 'Reactive Group Level 2 > ';
const nestedGroupReactiveVarPrefix    = new ReactiveVar(nestedGroupReactiveStrPrefix);

const nestedReactiveGroup = groupReactive.group({
  prefix: '/level2',
  title() {
    return nestedGroupReactiveVarTitle.get();
  },
  titlePrefix() {
    return nestedGroupReactiveVarPrefix.get();
  }
});

nestedReactiveGroup.route('/withoutTitle', {
  name: 'reactivelvl2',
  action() {
    Meteor.setTimeout(() => {
      nestedGroupReactiveVarTitle.set(nestedGroupReactiveStrTitleNew);
    }, 256);
  }
});

const nestedGroupReactiveStrPagelvl2Title    = 'Reactive Level 2 page';
const nestedGroupReactiveStrPagelvl2TitleNew = 'NEW Reactive Level 2 page';
const nestedGroupReactiveVarPagelvl2Title    = new ReactiveVar(nestedGroupReactiveStrPagelvl2Title);

nestedReactiveGroup.route('/withTitle', {
  name: 'reactivelvl2Title',
  title() {
    return nestedGroupReactiveVarPagelvl2Title.get();
  },
  action() {
    Meteor.setTimeout(() => {
      nestedGroupReactiveVarPagelvl2Title.set(nestedGroupReactiveStrPagelvl2TitleNew);
    }, 256);
  }
});

Tinytest.addAsync('Group - Reactive - level 1 - no route title', function (test, next) {
  FlowRouter.go('groupReactivePage1');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrTitle);
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrTitleNew);
      next();
    }, 512);
  }, 10);
});

Tinytest.addAsync('Group - Reactive - level 1 - with route title', function (test, next) {
  FlowRouter.go('groupReactivePage2');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrPrefix + groupReactiveStrPage2Title);
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrPrefix + groupReactiveStrPage2TitleNew);
      next();
    }, 512);
  }, 10);
});

Tinytest.addAsync('Group - Reactive - level 2 - no route title', function (test, next) {
  FlowRouter.go('reactivelvl2');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrTitle);
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrTitleNew);
      next();
    }, 512);
  }, 10);
});

Tinytest.addAsync('Group - Reactive - level 2 - with route title', function (test, next) {
  FlowRouter.go('reactivelvl2Title');
  setTimeout(() => {
    test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrPrefix + nestedGroupReactiveStrPagelvl2Title, 'before reactive update');
    Meteor.setTimeout(() => {
      test.equal(document.title, groupReactiveStrPrefix + nestedGroupReactiveStrPrefix + nestedGroupReactiveStrPagelvl2TitleNew, 'after reactive update');
      next();
    }, 512);
  }, 10);
});
<|endoftext|>


<commit_before>var dircompare = require('dir-compare');
var path = require('path');
var format = require('util').format;

var options = {
  compareContent: true,
  excludeFilter: '.DS_Store'
};

module.exports = function(testDir) {
  var res = dircompare.compareSync(
    path.join(testDir, '__expected'),
    path.join(testDir, '__output'),
    options
  );

  console.log('equal: ' + res.equal);
  console.log('distinct: ' + res.distinct);
  console.log('left: ' + res.left);
  console.log('right: ' + res.right);
  console.log('differences: ' + res.differences);
  console.log('same: ' + res.same);

  var stateType = {
    'equal' : '==',
    'left' : '->',
    'right' : '<-',
    'distinct' : '<>'
  };

  res.diffSet.forEach(function (entry) {
    var state = stateType[entry.state];
    var name1 = entry.name1 ? entry.name1 : '';
    var name2 = entry.name2 ? entry.name2 : '';

    console.log(format('%s(%s) %s %s(%s)', name1, entry.type1, state, name2, entry.type2));
  });

  if (!res.same) {
    // setTimeout(function() {
      throw new Error('Test [' + testDir + '] was completed unsuccessfully');
      console.log(res);
    // }, 10);
  }
}<commit_msg>Log more info abouts tests failing<commit_after>var dircompare = require('dir-compare');
var path = require('path');
var format = require('util').format;

var options = {
  compareContent: true,
  excludeFilter: '.DS_Store'
};

module.exports = function(testDir) {
  var res = dircompare.compareSync(
    path.join(testDir, '__expected'),
    path.join(testDir, '__output'),
    options
  );

  console.log('equal: ' + res.equal);
  console.log('distinct: ' + res.distinct);
  console.log('left: ' + res.left);
  console.log('right: ' + res.right);
  console.log('differences: ' + res.differences);
  console.log('same: ' + res.same);

  var stateType = {
    'equal' : '==',
    'left' : '->',
    'right' : '<-',
    'distinct' : '<>'
  };

  res.diffSet.forEach(function (entry) {
    var state = stateType[entry.state];
    var name1 = entry.name1 ? entry.name1 : '';
    var name2 = entry.name2 ? entry.name2 : '';

    console.log(format('%s(%s) %s %s(%s)', name1, entry.type1, state, name2, entry.type2));
  });

  if (!res.same) {
    // setTimeout(function() {
      console.log(res);
      throw new Error('Test [' + testDir + '] was completed unsuccessfully');
    // }, 10);
  }
}<|endoftext|>


<commit_before>(function() {
    var KeyEvent = function(data, type) {
        this.keyCode = 'keyCode' in data ? data.keyCode : 0;
        this.charCode = 'charCode' in data ? data.charCode : 0;

        var modifiers = 'modifiers' in data ? data.modifiers : [];

        this.ctrlKey = false;
        this.metaKey = false;
        this.altKey = false;
        this.shiftKey = false;

        for (var i = 0; i < modifiers.length; i++) {
            this[modifiers[i] + 'Key'] = true;
        }

        this.type = type || 'keypress';
    };

    KeyEvent.prototype.toNative = function() {
        var event = document.createEventObject ? document.createEventObject() : document.createEvent('Events');

        if (event.initEvent) {
            event.initEvent(this.type, true, true);
        }

        event.keyCode = this.keyCode;
        event.which = this.charCode || this.keyCode;
        event.shiftKey = this.shiftKey;
        event.metaKey = this.metaKey;
        event.altKey = this.altKey;
        event.ctrlKey = this.ctrlKey;

        return event;
    };

    KeyEvent.prototype.fire = function(element) {
        var event = this.toNative();
        if (element.dispatchEvent) {
            element.dispatchEvent(event);
            return;
        }

        element.fireEvent('on' + this.type, event);
    };

    // simulates complete key event as if the user pressed the key in the browser
    // triggers a keydown, then a keypress, then a keyup
    KeyEvent.simulate = function(charCode, keyCode, modifiers, element, repeat) {
        if (modifiers === undefined) {
            modifiers = [];
        }

        if (element === undefined) {
            element = document;
        }

        if (repeat === undefined) {
            repeat = 1;
        }

        var modifierToKeyCode = {
            'shift': 16,
            'ctrl': 17,
            'alt': 18,
            'meta': 91
        };

        // if the key is a modifier then take it out of the regular
        // keypress/keydown
        if (keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 91) {
            repeat = 0;
        }

        var modifiersToInclude = [];
        var keyEvents = [];

        // modifiers would go down first
        for (var i = 0; i < modifiers.length; i++) {
            modifiersToInclude.push(modifiers[i]);
            keyEvents.push(new KeyEvent({
                charCode: 0,
                keyCode: modifierToKeyCode[modifiers[i]],
                modifiers: modifiersToInclude
            }, 'keydown'));
        }

        // @todo factor in duration for these
        while (repeat > 0) {
            keyEvents.push(new KeyEvent({
                charCode: 0,
                keyCode: keyCode,
                modifiers: modifiersToInclude
            }, 'keydown'));

            if (charCode > 0) {
                keyEvents.push(new KeyEvent({
                    charCode: charCode,
                    keyCode: charCode,
                    modifiers: modifiersToInclude
                }, 'keypress'));
            }

            repeat--;
        }

        keyEvents.push(new KeyEvent({
            charCode: 0,
            keyCode: keyCode,
            modifiers: modifiersToInclude
        }, 'keyup'));

        // now lift up the modifier keys
        for (i = 0; i < modifiersToInclude.length; i++) {
            var modifierKeyCode = modifierToKeyCode[modifiersToInclude[i]];
            modifiersToInclude.splice(i, 1);
            keyEvents.push(new KeyEvent({
                charCode: 0,
                keyCode: modifierKeyCode,
                modifiers: modifiersToInclude
            }, 'keyup'));
        }

        for (i = 0; i < keyEvents.length; i++) {
            // console.log('firing', keyEvents[i].type, keyEvents[i].keyCode, keyEvents[i].charCode);
            keyEvents[i].fire(element);
        }
    };

    window.KeyEvent = KeyEvent;
}) ();
<commit_msg>Should do these all the time<commit_after>(function() {
    var KeyEvent = function(data, type) {
        this.keyCode = 'keyCode' in data ? data.keyCode : 0;
        this.charCode = 'charCode' in data ? data.charCode : 0;

        var modifiers = 'modifiers' in data ? data.modifiers : [];

        this.ctrlKey = false;
        this.metaKey = false;
        this.altKey = false;
        this.shiftKey = false;

        for (var i = 0; i < modifiers.length; i++) {
            this[modifiers[i] + 'Key'] = true;
        }

        this.type = type || 'keypress';
    };

    KeyEvent.prototype.toNative = function() {
        var event = document.createEventObject ? document.createEventObject() : document.createEvent('Events');

        if (event.initEvent) {
            event.initEvent(this.type, true, true);
        }

        event.keyCode = this.keyCode;
        event.which = this.charCode || this.keyCode;
        event.shiftKey = this.shiftKey;
        event.metaKey = this.metaKey;
        event.altKey = this.altKey;
        event.ctrlKey = this.ctrlKey;

        return event;
    };

    KeyEvent.prototype.fire = function(element) {
        var event = this.toNative();
        if (element.dispatchEvent) {
            element.dispatchEvent(event);
            return;
        }

        element.fireEvent('on' + this.type, event);
    };

    // simulates complete key event as if the user pressed the key in the browser
    // triggers a keydown, then a keypress, then a keyup
    KeyEvent.simulate = function(charCode, keyCode, modifiers, element, repeat) {
        if (modifiers === undefined) {
            modifiers = [];
        }

        if (element === undefined) {
            element = document;
        }

        if (repeat === undefined) {
            repeat = 1;
        }

        var modifierToKeyCode = {
            'shift': 16,
            'ctrl': 17,
            'alt': 18,
            'meta': 91
        };

        // if the key is a modifier then take it out of the regular
        // keypress/keydown
        if (keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 91) {
            repeat = 0;
        }

        var modifiersToInclude = [];
        var keyEvents = [];

        // modifiers would go down first
        for (var i = 0; i < modifiers.length; i++) {
            modifiersToInclude.push(modifiers[i]);
            keyEvents.push(new KeyEvent({
                charCode: 0,
                keyCode: modifierToKeyCode[modifiers[i]],
                modifiers: modifiersToInclude
            }, 'keydown'));
        }

        // @todo factor in duration for these
        while (repeat > 0) {
            keyEvents.push(new KeyEvent({
                charCode: 0,
                keyCode: keyCode,
                modifiers: modifiersToInclude
            }, 'keydown'));

            keyEvents.push(new KeyEvent({
                charCode: charCode,
                keyCode: charCode,
                modifiers: modifiersToInclude
            }, 'keypress'));

            repeat--;
        }

        keyEvents.push(new KeyEvent({
            charCode: 0,
            keyCode: keyCode,
            modifiers: modifiersToInclude
        }, 'keyup'));

        // now lift up the modifier keys
        for (i = 0; i < modifiersToInclude.length; i++) {
            var modifierKeyCode = modifierToKeyCode[modifiersToInclude[i]];
            modifiersToInclude.splice(i, 1);
            keyEvents.push(new KeyEvent({
                charCode: 0,
                keyCode: modifierKeyCode,
                modifiers: modifiersToInclude
            }, 'keyup'));
        }

        for (i = 0; i < keyEvents.length; i++) {
            // console.log('firing', keyEvents[i].type, keyEvents[i].keyCode, keyEvents[i].charCode);
            keyEvents[i].fire(element);
        }
    };

    window.KeyEvent = KeyEvent;
}) ();
<|endoftext|>


<commit_before>var sys           = require('sys')
var querystring   = require('querystring')

var oauth         = require('./lib/oauth_client.js')
var authorization = require('./lib/authorization.js')
var data          = require('./lib/data.js')
var Parser        = require('./lib/parser.js')

var merge = function(a, b) {
	var keys = Object.keys(b);

	for (var key in keys) {
		if (typeof(keys[key]) !== 'function') {
			a[keys[key]] = b[keys[key]];
		}
	}

	return a;
};

var ReflectorDish = function() {
  var self = this

  self.username = null
  self.restClient = null
  self.streamClient = null

  self.init = function(username, onComplete) {
    self.username = username

    self.restClient = oauth.client('http://api.twitter.com/')
    self.streamClient = oauth.client('http://stream.twitter.com/')

    self._loadConsumerTokens(function() {
      self._loadAccessTokens(onComplete)
    })
  }

  self._loadConsumerTokens = function(onComplete) {
    data.loadConsumerTokens(function(consumerKey, consumerSecret) {
      self.restClient.setConsumer(consumerKey, consumerSecret)
      self.streamClient.setConsumer(consumerKey, consumerSecret)
      if (onComplete) onComplete()
    })
  }

  self._loadAccessTokens = function(onComplete) {
    authorization.loadAccessTokens({
      username: self.username
    , client: self.restClient
    , callback: function(accessToken, accessTokenSecret) {
        self.restClient.setAccess(accessToken, accessTokenSecret)
        self.streamClient.setAccess(accessToken, accessTokenSecret)
        if (onComplete) onComplete()
      }
    })
  }

  self._onHTTPError = function(response) {
    console.log(response.statusCode)
    console.log(sys.inspect(response.headers))
    response.addListener('data', function(chunk) {
      console.log(chunk.toString('utf8'))
    })
  }

  self.getMembersOfList = function(listURI, callback) {
    var allMembers = []
    var onMembers = function(members) {
      members.forEach(function(member) {
        allMembers.push(member)
      })
    }
    var onComplete = function() {
      callback(allMembers)
    }

    self._getMembersOfList({
      listURI: listURI
    , members: onMembers
    , complete: onComplete
    })
  }

  self._getMembersOfList = function(options) {
    var listURI    = options.listURI.replace(/^[@/]/, '')
    var cursor     = options.cursor || -1
    var onMembers  = options.members
    var onComplete = options.complete

    var uri = "/1/" + listURI + "/members.json?cursor=" + cursor
    var success = function(body) {
      var response = JSON.parse(body)

      var membersOnPage = response.users
      onMembers(membersOnPage)

      var nextCursor = response.next_cursor
      if (nextCursor > 0) {
        var nextOptions = merge(options, { cursor: nextCursor })
        self._getMembersOfList(nextOptions)
      } else {
        onComplete()
      }
    }

    self.restClient.get({
      uri: uri
    , error: self._onHTTPError
    , complete: success
    })
  }

  self.retweet = function(tweet, onComplete) {
    var uri = '/1/statuses/retweet/' + tweet.id + '.json'
    self.restClient.post({
      uri: uri
    , error: self._onHTTPError
    , complete: onComplete
    })
  }

  self.streamFilter = function(params, onTweet) {
    var parser = new Parser()
    parser.addListener('object', onTweet)

    var body = {}
    if (params.follow)    body.follow    = params.follow.join(',')
    if (params.locations) body.locations = params.locations.join(',')
    if (params.track)     body.track     = params.track.join(',')

    self.streamClient.post({
      uri: '/1/statuses/filter.json'
    , body: body
    , data: function(chunk) { parser.receive(chunk) }
    , error: self._onHTTPError
    })
  }
}

var username = process.argv[2]
var listURI  = process.argv[3]
var hashtag  = process.argv[4]

var tweetIDs = []
var reflectorDish = new ReflectorDish()

var processTweet = function(tweet) {
  // ignore retweets
  if (tweet.retweeted_status) return
  if (tweet.text && tweet.text.search("RT ") == 0) return

  // ignore tweets I've already seen
  if (tweet.id && tweetIDs.indexOf(tweet.id) >= 0) return
  if (tweet.new_id && tweetIDs.indexOf(tweet.new_id) >= 0) return

  if (tweet.entities && tweet.entities.hashtags) {
    var containsHashTag = tweet.entities.hashtags.some(function(ht) {
      return (ht.text == hashtag)
    })
    if (containsHashTag) {
      tweetIDs.push(tweet.id)
      tweetIDs.push(tweet.new_id)
      console.log("  Retweeting: [" + tweet.new_id + "] " + tweet.text)
      reflectorDish.retweet(tweet, function() {
        console.log("    Successfully retweeted " + tweet.new_id)
      })
    }
  }
}

reflectorDish.init(username, function() {
  console.log("Loading members of " + listURI + " ...")
  reflectorDish.getMembersOfList(listURI, function(members) {
    console.log("  Found " + members.length + " members")
    console.log("Streaming tweets from members...")
    var userIDs = members.map(function(member) {
      return member.id
    })
    var params = { follow: userIDs }
    reflectorDish.streamFilter(params, processTweet)
  })
})
<commit_msg>Updated to use id_str instead of new_id<commit_after>var sys           = require('sys')
var querystring   = require('querystring')

var oauth         = require('./lib/oauth_client.js')
var authorization = require('./lib/authorization.js')
var data          = require('./lib/data.js')
var Parser        = require('./lib/parser.js')

var RETWEET_TURNAROUND = 30 * 1000; // 30 seconds

var merge = function(a, b) {
	var keys = Object.keys(b);

	for (var key in keys) {
		if (typeof(keys[key]) !== 'function') {
			a[keys[key]] = b[keys[key]];
		}
	}

	return a;
};

var ReflectorDish = function() {
  var self = this

  self.username = null
  self.restClient = null
  self.streamClient = null

  self.init = function(username, onComplete) {
    self.username = username

    self.restClient = oauth.client('http://api.twitter.com/')
    self.streamClient = oauth.client('http://stream.twitter.com/')

    self._loadConsumerTokens(function() {
      self._loadAccessTokens(onComplete)
    })
  }

  self._loadConsumerTokens = function(onComplete) {
    data.loadConsumerTokens(function(consumerKey, consumerSecret) {
      self.restClient.setConsumer(consumerKey, consumerSecret)
      self.streamClient.setConsumer(consumerKey, consumerSecret)
      if (onComplete) onComplete()
    })
  }

  self._loadAccessTokens = function(onComplete) {
    authorization.loadAccessTokens({
      username: self.username
    , client: self.restClient
    , callback: function(accessToken, accessTokenSecret) {
        self.restClient.setAccess(accessToken, accessTokenSecret)
        self.streamClient.setAccess(accessToken, accessTokenSecret)
        if (onComplete) onComplete()
      }
    })
  }

  self._onHTTPError = function(response) {
    console.log(response.statusCode)
    console.log(sys.inspect(response.headers))
    response.addListener('data', function(chunk) {
      console.log(chunk.toString('utf8'))
    })
  }

  self.getMembersOfList = function(listURI, callback) {
    var allMembers = []
    var onMembers = function(members) {
      members.forEach(function(member) {
        allMembers.push(member)
      })
    }
    var onComplete = function() {
      callback(allMembers)
    }

    self._getMembersOfList({
      listURI: listURI
    , members: onMembers
    , complete: onComplete
    })
  }

  self._getMembersOfList = function(options) {
    var listURI    = options.listURI.replace(/^[@/]/, '')
    var cursor     = options.cursor || -1
    var onMembers  = options.members
    var onComplete = options.complete

    var uri = "/1/" + listURI + "/members.json?cursor=" + cursor
    var success = function(body) {
      var response = JSON.parse(body)

      var membersOnPage = response.users
      onMembers(membersOnPage)

      var nextCursor = response.next_cursor
      if (nextCursor > 0) {
        var nextOptions = merge(options, { cursor: nextCursor })
        self._getMembersOfList(nextOptions)
      } else {
        onComplete()
      }
    }

    self.restClient.get({
      uri: uri
    , error: self._onHTTPError
    , complete: success
    })
  }

  self.retweet = function(tweet, onComplete) {
    var uri = '/1/statuses/retweet/' + tweet.id_str + '.json'
    self.restClient.post({
      uri: uri
    , error: self._onHTTPError
    , complete: onComplete
    })
  }

  self.streamFilter = function(params, onTweet) {
    var parser = new Parser()
    parser.addListener('object', onTweet)

    var body = {}
    if (params.follow)    body.follow    = params.follow.join(',')
    if (params.locations) body.locations = params.locations.join(',')
    if (params.track)     body.track     = params.track.join(',')

    self.streamClient.post({
      uri: '/1/statuses/filter.json'
    , body: body
    , data: function(chunk) { parser.receive(chunk) }
    , error: self._onHTTPError
    })
  }
}

var username = process.argv[2]
var listURI  = process.argv[3]
var hashtag  = process.argv[4]

var tweetIDs = []
var reflectorDish = new ReflectorDish()

var processTweet = function(tweet) {
  // ignore retweets
  if (tweet.retweeted_status) return
  if (tweet.text && tweet.text.search("RT ") == 0) return

  // ignore tweets I've already seen
  if (tweet.id_str && tweetIDs.indexOf(tweet.id_str) >= 0) return

  if (tweet.entities && tweet.entities.hashtags) {
    var containsHashTag = tweet.entities.hashtags.some(function(ht) {
      return (ht.text == hashtag)
    });
    if (containsHashTag) {
      console.log("  Scheduling retweet: [" + tweet.id_str + "] " + tweet.text)
      var retweetIt = function() {
        tweetIDs.push(tweet.id_str);
        console.log("  Retweeting: [" + tweet.id_str + "] " + tweet.text)
        reflectorDish.retweet(tweet, function() {
          console.log("    Successfully retweeted " + tweet.id_str)
        })
      };
      setTimeout(retweetIt, RETWEET_TURNAROUND);
    }
  }
}

reflectorDish.init(username, function() {
  console.log("Loading members of " + listURI + " ...")
  reflectorDish.getMembersOfList(listURI, function(members) {
    console.log("  Found " + members.length + " members")
    console.log("Streaming tweets from members...")
    var userIDs = members.map(function(member) {
      return member.id
    })
    var params = { follow: userIDs }
    reflectorDish.streamFilter(params, processTweet)
  })
})
<|endoftext|>


<commit_before>// Web to Plex - Toloka Plugin
// Aurthor(s) - @chmez (2017)

// REQUIRED [plugin:object]: The plugin object
let plugin = {
    // REQUIRED [plugin.url]: this is what you ask Web to Plex access to; currently limited to a single domain
    "url": "https://toloka.to",

    // OPTIONAL: this is purely for your code functionality
    "getID": () => {
        let links = document.querySelectorAll('.postlink'),
            regex = /^https?\:\/\/(?:w{3}\.)?imdb\.com\/title\/(tt\d+)/i;

        for(let link in links)
            if(regex.test(links[link]))
                return RegExp.$1;
    },

    // REQUIRED [plugin.init]: this is what Web to Plex will call on when the url is detected
    // it will always be fired after the page and Web to Plex have been loaded
    "init": () => {
        let title = document.querySelector('.maintitle').textContent.replace(/[^\/]+\/\s+([^\(]+)\(([\d]{4})\)\s*$/, '$1').trim(),
                // REQUIRED [title:string]
            year = RegExp.$2,
                // PREFERRED [year:number, null, undefined]
            image = document.querySelector('.postbody img').src,
                // OPTIONAL [image:string]
            IMDbID = plugin.getID();
                // the rest of the code is up to you, but should be limited to a layout similar to this

        // REQUIRED [{ type:'movie', 'show'; title:string; year:number }]
        // PREFERRED [{ image:string; IMDbID:string; TMDbID:string, number; TVDbID:string, number }]
        return { type: 'movie', title, year, image, IMDbID };
    }
};
<commit_msg>Update toloka.js<commit_after>// Web to Plex - Toloka Plugin
// Aurthor(s) - @chmez (2017)

// REQUIRED [plugin:object]: The plugin object
let plugin = {
    // REQUIRED [plugin.url]: this is what you ask Web to Plex access to; currently limited to a single domain
    "url": "https://toloka.to",

    // OPTIONAL: this is purely for your code functionality
    "getID": () => {
        let links = document.querySelectorAll('.postlink'),
            regex = /^https?\:\/\/(?:w{3}\.)?imdb\.com\/title\/(tt\d+)/i;

        for(let link in links)
            if(regex.test(links[link]))
                return RegExp.$1;
    },

    // REQUIRED [plugin.init]: this is what Web to Plex will call on when the url is detected
    // it will always be fired after the page and Web to Plex have been loaded
    "init": () => {
        let title = document.querySelector('.maintitle').textContent.replace(/^.+\/(.+?)\(([\d]{4})\)\s*$/, '$1').trim(),
                // REQUIRED [title:string]
            year = RegExp.$2,
                // PREFERRED [year:number, null, undefined]
            image = document.querySelector('.postbody img').src,
                // OPTIONAL [image:string]
            IMDbID = plugin.getID();
                // the rest of the code is up to you, but should be limited to a layout similar to this

        // REQUIRED [{ type:'movie', 'show'; title:string; year:number }]
        // PREFERRED [{ image:string; IMDbID:string; TMDbID:string, number; TVDbID:string, number }]
        return { type: 'movie', title, year, image, IMDbID };
    }
};
<|endoftext|>


<commit_before>var editor;

NUM_LEVEL_ROWS = 30;
NUM_LEVEL_COLS = 40;
var level = new Array(NUM_LEVEL_ROWS);

// init the global level data structure
for (var i = 0; i < NUM_LEVEL_ROWS; i++) {
  level[i] = "0000000000000000000000000000000000000000";
}

if (levelParam.length == (NUM_LEVEL_COLS * NUM_LEVEL_ROWS)) {
  for (var c = 0; c < (NUM_LEVEL_COLS * NUM_LEVEL_ROWS); c += NUM_LEVEL_COLS) {
    level[c/NUM_LEVEL_COLS] = levelParam.substr(c, NUM_LEVEL_COLS);
  }
}

function setLevel(lvl) {
  level = lvl;

  editor.drawCanvas(editor.camx, editor.camy);
}

function loadLevelState(level) {
  setLevel(level);
  reloadMap();
  $('#last_saved').text(getCurrentTimestamp());
}

function getLevelDataForSaveFile() {
  return JSON.stringify(getLevelData());
}

function getLevelData() {
  return level;
}

function getLevelName() {
  return $('#level_name input').val();
}

function getFilenameForSave() {
  return getLevelName().toLowerCase().replace(/ /g, '_') + '_' + getCurrentTimestampForFile() + '.json';
}

function initEditor() {
  editor = new Editor();

  // Find the elements
  editor.brushes = $(".brush");

  editor.brushes.each(function(i) {
    editor.brushes_img[i] = new Image();
    editor.brushes_img[i].src = this.src;
  });

  editor.brushes.live('click', function() {
    editor.currentBrush = this.id.replace('brush', '');
    if (editor.currentBrush > editor.total_brushes) {
      editor.currentBrush = String.fromCharCode(editor.currentBrush);
    }
  });

  if (!editor.canvas) {
    alert('Error: I cannot find the canvas element!');
    return;
  } else if (!editor.canvas.getContext) {
    alert('Error: no canvas.getContext!');
    return;
  } else {
    // Get the 2D canvas context.
    editor.context = editor.canvas.getContext('2d');
    if (!editor.context) {
      alert('Error: failed to getContext!');
      return;
    }
  }

  var actions = ['mousedown', 'mousemove'];
  $(actions).each(function(i, action) {
    $(editor.canvas).bind(action, function(ev) {
      ev._x = ev.pageX - $(this).offset().left;
      ev._y = ev.pageY - $(this).offset().top;
      editor.tool[action](ev);
    });
  });

  $('body').mouseup(function(e) {
    e._x = e.pageX - $(editor.canvas).offset().left;
    e._y = e.pageY - $(editor.canvas).offset().top;
    editor.tool.mouseup(e);
  }).mouseout(function() {
    editor.isMouseOut = true;
    editor.mouseOverDelay = 0;
  });

  editor.drawCanvas(editor.camx, editor.camy);

  if (!UpdateMap.priorOldValue) {
    UpdateMap.priorOldValue = getLevelCopy();
  }

  $('.inline_help[title]').tooltip().dynamic({ bottom: { direction: 'down' } });

  setInterval (function() { editor.mouseOverDelay++; }, 100);
}

function replaceOneChar(s, c, n) {
  (s = s.split(''))[n] = c;
  return s.join('');
}

// This painting tool works like a drawing pencil which tracks the mouse
// movements.
function tool_pencil () {
  tool = this;
  this.started = false;

  // This is called when you start holding down the mouse button.
  this.mousedown = function (ev) {
      level[Math.floor(ev._y/32) + editor.camy] = replaceOneChar(level[Math.floor(ev._y/32) + editor.camy], editor.currentBrush, [Math.floor(ev._x/32) + editor.camx]);
      tool.started = true;
      editor.drawCanvas(editor.camx, editor.camy);
  };

  // This function is called every time you move the mouse. Obviously, it only
  // draws if the tool.started state is set to true (when you are holding down
  // the mouse button).
  this.mousemove = function (ev) {

  editor.isMouseOut = false;

  if (!tool.started && !editor.isMouseOut) {

    if ( !((ev._x > 600 && editor.camx < 20) || (ev._x < 40 && editor.camx > 0) || (ev._y > 440 && editor.camy < 15) || (ev._y < 40 && editor.camy > 0)) )
      editor.mouseOverDelay = 0;

    // move the camera when you hit the edge of the screen
    if (ev._x > 600 && editor.camx < 20) {
      if (editor.mouseOverDelay >= 2) editor.camx += 1;
    }
    else if (ev._x < 40 && editor.camx > 0) {
      if (editor.mouseOverDelay >= 2) editor.camx -= 1;
      }
    if (ev._y > 440 && editor.camy < 15) {
      if (editor.mouseOverDelay >= 2) editor.camy += 1;
    }
    else if (ev._y < 40 && editor.camy > 0) {
      if (editor.mouseOverDelay >= 2) editor.camy -= 1;
      }
   }

    if (tool.started) {
      level[Math.floor(ev._y/32)+editor.camy] = replaceOneChar(level[Math.floor(ev._y/32)+editor.camy], editor.currentBrush, [Math.floor(ev._x/32) + editor.camx]);
      }
     editor.drawCanvas(editor.camx, editor.camy);
     editor.context.lineWidth = 2;
  editor.context.strokeStyle = '#800';
  editor.context.strokeRect((Math.floor(ev._x/32))*32, Math.floor(ev._y/32)*32, 32, 32);

  };

  // This is called when you release the mouse button.
  this.mouseup = function (ev) {
    if (editor.minimapCanvasContext) { genMiniMap(); }
    if (tool.started) {
      tool.mousemove(ev);
      tool.started = false;
    }
  };
}

function genMiniMap () {
  reloadMap();
  editor.minimap = editor.minimapCanvasContext.getImageData(0, 0, 640*2, 480*2);
  var pix = editor.minimap.data;

  // Loop over pixels, skipping every Nth since we're shrinking the image
  for (var i = 0, n = pix.length; i < n; i += 4)
    if (i % 32 == 0) {
      pix[(i/8)  ] = pix[i  ]; // r
      pix[(i/8)+1] = pix[i+1]; // g
      pix[(i/8)+2] = pix[i+2]; // b
      pix[(i/8)+3] = pix[i+3]; // a
    }
}

var Editor = Klass.extend({
  init: function(dom_base, options) {
    this.currentBrush  = '4';
    this.total_brushes = 10;
    this.brushes       = new Array(this.total_brushes);
    this.brushes_img   = new Array(this.total_brushes);
    this.tool          = new tool_pencil();
    this.camx = 0;
    this.camy = 0;
    this.canvas = document.getElementById('imageView');
    this.mouseOverDelay = 0;
    this.isMouseOut = false;
  },

  drawCanvas: function(cx, cy) {
    for (var y = cy; y < cy + 15; y++) {
      for (var x = cx; x < cx + 20; x++) {
        var brush = jQuery('#brush' + level[y][x]);
        if (brush.length) {
          this.context.drawImage(brush[0], (x - this.camx) * 32, (y - this.camy) * 32);
        } else {
          // We didnt find the brush the normal way, check out the char code then...
          var id = level[y][x].charCodeAt(0);
          var brush = jQuery('#brush' + id);
          if (brush.length) {
            this.context.drawImage(brush[0], (x - this.camx) * 32, (y - this.camy) * 32);
          } else {
            console.log("Could not find brush for: " + level[y][x]);
          }
        }
      }
    }

    if (this.minimap) {
      var tc = document.createElement('canvas');
      tc.setAttribute('width', 160);
      tc.setAttribute('height', 120);

      var pix = this.minimap.data;
      var a = tc.getContext('2d').getImageData(0, 0, 160, 120);
      var apix = a.data;

      for (var j = 0; j < pix.length/8; j += 640*2*4)
        for (var i = j; i <  j+160*4; i += 4) {
          var b = (i-j)+(j/(640*2*4)*160*4);
          apix[(b)  ] = pix[i  ]; // r
          apix[(b)+1] = pix[i+1]; // g
          apix[(b)+2] = pix[i+2]; // b
          apix[(b)+3] = pix[i+3]; // a
        }

      this.context.putImageData(a,480,0,0,0,160,120);
    }

    this.context.strokeStyle = '#000';
    this.context.strokeRect(480,0,160,120);
    this.context.strokeRect(480+((this.camx*32)/8), 0+((this.camy*32)/8), 640/8, 480/8);
  }
});

function getLevelParams() {
  var levelParam = '';
  for (var i = 0; i < 30; i++) {
    levelParam += level[i];
  }
  return levelParam;
}

function redrawMap() {
  new UpdateMap(getLevelCopy());
  historyManager.addLevelState({ name: getLevelName(), date: getCurrentTimestampForFile(), level: getLevelData() });
}

function getLongURL() {
  var url_params = {
    name:  getLevelName(),
    level: getLevelParams(),
  g:1,
  plugins: getPluginsForURL()
  };
  return window.location.protocol + "//" + window.location.host + window.location.pathname + '?encoded='+compressObject(url_params);
}

function mouseOut() {
  editor.isMouseOut = true;
  editor.mouseOverDelay = 0;
}

var UpdateMap = UndoableAction.extend({
  init: function(value, options) {
    var self = this;
    self.value = value;

    this._super(function() {
      // The "do" method:

      self.oldValue = UpdateMap.priorOldValue;
      loadLevelState(getLevelCopy(self.value));
      UpdateMap.priorOldValue = self.value;
      // reportLevel(self.value, 'new');
      // reportLevel(level, 'current');
      // reportLevel(self.oldValue, 'old');
    }, function() {
      // The "undo" method:

      loadLevelState(self.oldValue);
      UpdateMap.priorOldValue = getLevelCopy(self.oldValue);
    });

    self.redo();
  }
});

function addEditorHelper() {
   var editorHelper = gbox.addObject({
    id:    'editor_helper',
    group: 'game',

    // initialize: this.init.bind(this),
    // first:      this.step.bind(this),
    // blit:       this.draw.bind(this)
    initialize: function() {},
    first:      function() {
      if (gbox._keyboard[KEY_D] == 1 && editor.camx < 20) { // 'd'
        editor.camx += 1;
        editor.drawCanvas(editor.camx, editor.camy);
      } else if (gbox._keyboard[KEY_A] == 1 && editor.camx > 0) { // 'a'
        editor.camx -= 1;
        editor.drawCanvas(editor.camx, editor.camy);
      }

      if (gbox._keyboard[KEY_S] == 1 && editor.camy < 15) { // 's'
        editor.camy += 1;
        editor.drawCanvas(editor.camx, editor.camy);
      } else if (gbox._keyboard[KEY_W] == 1 && editor.camy > 0) { // 'w'
        editor.camy -= 1;
        editor.drawCanvas(editor.camx,editor.camy);
      }
    },
    blit: function() {}
  });
}<commit_msg>More refactoring of code into Editor<commit_after>var editor;

NUM_LEVEL_ROWS = 30;
NUM_LEVEL_COLS = 40;
var level = new Array(NUM_LEVEL_ROWS);

// init the global level data structure
for (var i = 0; i < NUM_LEVEL_ROWS; i++) {
  level[i] = "0000000000000000000000000000000000000000";
}

if (levelParam.length == (NUM_LEVEL_COLS * NUM_LEVEL_ROWS)) {
  for (var c = 0; c < (NUM_LEVEL_COLS * NUM_LEVEL_ROWS); c += NUM_LEVEL_COLS) {
    level[c/NUM_LEVEL_COLS] = levelParam.substr(c, NUM_LEVEL_COLS);
  }
}

function setLevel(lvl) {
  level = lvl;

  editor.drawCanvas(editor.camx, editor.camy);
}

function loadLevelState(level) {
  setLevel(level);
  reloadMap();
  $('#last_saved').text(getCurrentTimestamp());
}

function getLevelDataForSaveFile() {
  return JSON.stringify(getLevelData());
}

function getLevelData() {
  return level;
}

function getLevelName() {
  return $('#level_name input').val();
}

function getFilenameForSave() {
  return getLevelName().toLowerCase().replace(/ /g, '_') + '_' + getCurrentTimestampForFile() + '.json';
}

function initEditor() {
  editor = new Editor();

  // Find the elements
  editor.brushes = $(".brush");

  editor.brushes.each(function(i) {
    editor.brushes_img[i] = new Image();
    editor.brushes_img[i].src = this.src;
  });

  editor.brushes.live('click', function() {
    editor.currentBrush = this.id.replace('brush', '');
    if (editor.currentBrush > editor.total_brushes) {
      editor.currentBrush = String.fromCharCode(editor.currentBrush);
    }
  });

  if (!editor.canvas) {
    alert('Error: I cannot find the canvas element!');
    return;
  } else if (!editor.canvas.getContext) {
    alert('Error: no canvas.getContext!');
    return;
  } else {
    // Get the 2D canvas context.
    editor.context = editor.canvas.getContext('2d');
    if (!editor.context) {
      alert('Error: failed to getContext!');
      return;
    }
  }

  var actions = ['mousedown', 'mousemove'];
  $(actions).each(function(i, action) {
    $(editor.canvas).bind(action, function(ev) {
      ev._x = ev.pageX - $(this).offset().left;
      ev._y = ev.pageY - $(this).offset().top;
      editor.tool[action](ev);
    });
  });

  $('body').mouseup(function(e) {
    e._x = e.pageX - $(editor.canvas).offset().left;
    e._y = e.pageY - $(editor.canvas).offset().top;
    editor.tool.mouseup(e);
  }).mouseout(function() {
    editor.isMouseOut = true;
    editor.mouseOverDelay = 0;
  });

  editor.drawCanvas(editor.camx, editor.camy);

  if (!UpdateMap.priorOldValue) {
    UpdateMap.priorOldValue = getLevelCopy();
  }

  $('.inline_help[title]').tooltip().dynamic({ bottom: { direction: 'down' } });

  setInterval (function() { editor.mouseOverDelay++; }, 100);
}

function replaceOneChar(s, c, n) {
  (s = s.split(''))[n] = c;
  return s.join('');
}

// This painting tool works like a drawing pencil which tracks the mouse
// movements.
function tool_pencil () {
  tool = this;
  this.started = false;

  // This is called when you start holding down the mouse button.
  this.mousedown = function (ev) {
    level[Math.floor(ev._y/32) + editor.camy] = replaceOneChar(level[Math.floor(ev._y/32) + editor.camy], editor.currentBrush, [Math.floor(ev._x/32) + editor.camx]);
    tool.started = true;
    editor.drawCanvas(editor.camx, editor.camy);
  };

  // This function is called every time you move the mouse. Obviously, it only
  // draws if the tool.started state is set to true (when you are holding down
  // the mouse button).
  this.mousemove = function (ev) {
    editor.isMouseOut = false;

    if (!tool.started && !editor.isMouseOut) {
      if (!((ev._x > 600 && editor.camx < 20) || (ev._x < 40 && editor.camx > 0) || (ev._y > 440 && editor.camy < 15) || (ev._y < 40 && editor.camy > 0)))
        editor.mouseOverDelay = 0;

      // move the camera when you hit the edge of the screen
      if (ev._x > 600 && editor.camx < 20 && editor.mouseOverDelay >= 2) {
        editor.camx += 1;
      } else if (ev._x < 40 && editor.camx > 0 && editor.mouseOverDelay >= 2) {
        editor.camx -= 1;
      }

      if (ev._y > 440 && editor.camy < 15 && editor.mouseOverDelay >= 2) {
        editor.camy += 1;
      } else if (ev._y < 40 && editor.camy > 0 && editor.mouseOverDelay >= 2) {
        editor.camy -= 1;
      }
    }

    if (tool.started) {
      level[Math.floor(ev._y/32)+editor.camy] = replaceOneChar(level[Math.floor(ev._y/32)+editor.camy], editor.currentBrush, [Math.floor(ev._x/32) + editor.camx]);
    }

    editor.drawCanvas(editor.camx, editor.camy);
    editor.context.lineWidth = 2;
    editor.context.strokeStyle = '#800';
    editor.context.strokeRect((Math.floor(ev._x/32))*32, Math.floor(ev._y/32)*32, 32, 32);
  };

  // This is called when you release the mouse button.
  this.mouseup = function (ev) {
    if (editor.minimapCanvasContext) { editor.genMiniMap(); }
    if (tool.started) {
      tool.mousemove(ev);
      tool.started = false;
    }
  };
}

var Editor = Klass.extend({
  init: function(dom_base, options) {
    this.currentBrush  = '4';
    this.total_brushes = 10;
    this.brushes       = new Array(this.total_brushes);
    this.brushes_img   = new Array(this.total_brushes);
    this.tool          = new tool_pencil();
    this.camx = 0;
    this.camy = 0;
    this.canvas = document.getElementById('imageView');
    this.mouseOverDelay = 0;
    this.isMouseOut = false;
  },

  drawCanvas: function(cx, cy) {
    for (var y = cy; y < cy + 15; y++) {
      for (var x = cx; x < cx + 20; x++) {
        var brush = jQuery('#brush' + level[y][x]);
        if (brush.length) {
          this.context.drawImage(brush[0], (x - this.camx) * 32, (y - this.camy) * 32);
        } else {
          // We didnt find the brush the normal way, check out the char code then...
          var id = level[y][x].charCodeAt(0);
          var brush = jQuery('#brush' + id);
          if (brush.length) {
            this.context.drawImage(brush[0], (x - this.camx) * 32, (y - this.camy) * 32);
          } else {
            console.log("Could not find brush for: " + level[y][x]);
          }
        }
      }
    }

    if (this.minimap) {
      var tc = document.createElement('canvas');
      tc.setAttribute('width', 160);
      tc.setAttribute('height', 120);

      var pix = this.minimap.data;
      var a = tc.getContext('2d').getImageData(0, 0, 160, 120);
      var apix = a.data;

      for (var j = 0; j < pix.length/8; j += 640*2*4)
        for (var i = j; i <  j+160*4; i += 4) {
          var b = (i-j)+(j/(640*2*4)*160*4);
          apix[(b)  ] = pix[i  ]; // r
          apix[(b)+1] = pix[i+1]; // g
          apix[(b)+2] = pix[i+2]; // b
          apix[(b)+3] = pix[i+3]; // a
        }

      this.context.putImageData(a,480,0,0,0,160,120);
    }

    this.context.strokeStyle = '#000';
    this.context.strokeRect(480,0,160,120);
    this.context.strokeRect(480+((this.camx*32)/8), 0+((this.camy*32)/8), 640/8, 480/8);
  },

  genMiniMap: function() {
    reloadMap();
    editor.minimap = editor.minimapCanvasContext.getImageData(0, 0, 640*2, 480*2);
    var pix = editor.minimap.data;

    // Loop over pixels, skipping every Nth since we're shrinking the image
    for (var i = 0, n = pix.length; i < n; i += 4)
      if (i % 32 == 0) {
        pix[(i/8)  ] = pix[i  ]; // r
        pix[(i/8)+1] = pix[i+1]; // g
        pix[(i/8)+2] = pix[i+2]; // b
        pix[(i/8)+3] = pix[i+3]; // a
      }
  }
});

function getLevelParams() {
  var levelParam = '';
  for (var i = 0; i < 30; i++) {
    levelParam += level[i];
  }
  return levelParam;
}

function redrawMap() {
  new UpdateMap(getLevelCopy());
  historyManager.addLevelState({ name: getLevelName(), date: getCurrentTimestampForFile(), level: getLevelData() });
}

function getLongURL() {
  var url_params = {
    name:    getLevelName(),
    level:   getLevelParams(),
    g:       1,
    plugins: getPluginsForURL()
  };
  return window.location.protocol + "//" + window.location.host + window.location.pathname + '?encoded=' + compressObject(url_params);
}

function mouseOut() {
  editor.isMouseOut = true;
  editor.mouseOverDelay = 0;
}

var UpdateMap = UndoableAction.extend({
  init: function(value, options) {
    var self = this;
    self.value = value;

    this._super(function() {
      // The "do" method:

      self.oldValue = UpdateMap.priorOldValue;
      loadLevelState(getLevelCopy(self.value));
      UpdateMap.priorOldValue = self.value;
      // reportLevel(self.value, 'new');
      // reportLevel(level, 'current');
      // reportLevel(self.oldValue, 'old');
    }, function() {
      // The "undo" method:

      loadLevelState(self.oldValue);
      UpdateMap.priorOldValue = getLevelCopy(self.oldValue);
    });

    self.redo();
  }
});

function addEditorHelper() {
   var editorHelper = gbox.addObject({
    id:    'editor_helper',
    group: 'game',

    // initialize: this.init.bind(this),
    // first:      this.step.bind(this),
    // blit:       this.draw.bind(this)
    initialize: function() {},
    first:      function() {
      if (gbox._keyboard[KEY_D] == 1 && editor.camx < 20) { // 'd'
        editor.camx += 1;
        editor.drawCanvas(editor.camx, editor.camy);
      } else if (gbox._keyboard[KEY_A] == 1 && editor.camx > 0) { // 'a'
        editor.camx -= 1;
        editor.drawCanvas(editor.camx, editor.camy);
      }

      if (gbox._keyboard[KEY_S] == 1 && editor.camy < 15) { // 's'
        editor.camy += 1;
        editor.drawCanvas(editor.camx, editor.camy);
      } else if (gbox._keyboard[KEY_W] == 1 && editor.camy > 0) { // 'w'
        editor.camy -= 1;
        editor.drawCanvas(editor.camx,editor.camy);
      }
    },
    blit: function() {}
  });
}<|endoftext|>


<commit_before>'use strict';

var assert = require('assert'),
    generate = require('../index.js');

// Called without argument
assert.equal(generate().length, 10);

// Called with number less than 10
assert.equal(generate(4).length, 4);

// Called with number greater than 10
assert.equal(generate(34).length, 34);

// Called with string instead of number
// Argument should be ignored
assert.equal(generate('JCZC.7UP').length, 10);

// Called with object instead of number
// Argument should be ignored
assert.equal(generate({
  'MlodybeTomal': 'Najlepszy rap z Jelonek'
}).length, 10);

// Called with array instead of number
// Argument should be ignored
assert.equal(generate([3,2,1,6,7]).length, 10);

// Called with '0' should throw an error
assert.throws(function(){
  generate(0)
});
<commit_msg>[RANDOM-ID] - lint error fixed<commit_after>'use strict';

var assert = require('assert'),
    generate = require('../index.js');

// Called without argument
assert.equal(generate().length, 10);

// Called with number less than 10
assert.equal(generate(4).length, 4);

// Called with number greater than 10
assert.equal(generate(34).length, 34);

// Called with string instead of number
// Argument should be ignored
assert.equal(generate('JCZC.7UP').length, 10);

// Called with object instead of number
// Argument should be ignored
assert.equal(generate({
  'MlodybeTomal': 'Najlepszy rap z Jelonek'
}).length, 10);

// Called with array instead of number
// Argument should be ignored
assert.equal(generate([3,2,1,6,7]).length, 10);

// Called with '0' should throw an error
assert.throws(function(){
  generate(0);
});
<|endoftext|>


<commit_before>console.log('hurgh');
describe("JanusWeb Scripting", function() {
  jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
  var client, janusweb, canvas;
  var resolution = '800x600';
  var browser = 'chrome'; // FIXME - don't hardcode this

  beforeEach(function(done) {
    jasmine.addMatchers(imagediff.jasmine);
    done();
  });

  it("should initialize client", function(done) {
    try {
      elation.janusweb.init({homepage: 'http://www.janusvr.com/index.html', resolution: resolution}).then(function(newclient) {
        client = newclient;
        janusweb = client.janusweb;
        expect(client).toBeDefined();
        expect(janusweb).toBeDefined();
        done();
      });
    } catch (e) {
      console.log('exception happened!', e.stack);
    }
  });

  it("added canvas to document", function(done) {
    var canvases = document.getElementsByTagName('canvas');
    expect(canvases.length).toEqual(1);
    canvas = canvases[0];
    done();
  });

  it("should have a global janus object", function(done) {
    expect(window.janus).toBeDefined();
    done();
  });
  it("should return a URL for janus.currenturl()", function(done) {
    expect(window.janus.currenturl).toBeDefined();
    expect(window.janus.currenturl()).toBeDefined();
    done();
  });
});
<commit_msg>Remove debug print<commit_after>describe("JanusWeb Scripting", function() {
  jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
  var client, janusweb, canvas;
  var resolution = '800x600';
  var browser = 'chrome'; // FIXME - don't hardcode this

  beforeEach(function(done) {
    jasmine.addMatchers(imagediff.jasmine);
    done();
  });

  it("should initialize client", function(done) {
    try {
      elation.janusweb.init({homepage: 'http://www.janusvr.com/index.html', resolution: resolution}).then(function(newclient) {
        client = newclient;
        janusweb = client.janusweb;
        expect(client).toBeDefined();
        expect(janusweb).toBeDefined();
        done();
      });
    } catch (e) {
      console.log('exception happened!', e.stack);
    }
  });

  it("added canvas to document", function(done) {
    var canvases = document.getElementsByTagName('canvas');
    expect(canvases.length).toEqual(1);
    canvas = canvases[0];
    done();
  });

  it("should have a global janus object", function(done) {
    expect(window.janus).toBeDefined();
    done();
  });
  it("should return a URL for janus.currenturl()", function(done) {
    expect(window.janus.currenturl).toBeDefined();
    expect(window.janus.currenturl()).toBeDefined();
    done();
  });
});
<|endoftext|>


<commit_before>module('Methods', {
    setup: function(){
        this.input = $('<input type="text" value="31-03-2011">')
                        .appendTo('#qunit-fixture')
                        .datepicker({format: "dd-mm-yyyy"});
        this.dp = this.input.data('datepicker')
    },
    teardown: function(){
        this.dp.remove();
    }
});

test('remove', function(){
    var returnedObject = this.dp.remove();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('show', function(){
    var returnedObject = this.dp.show();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('hide', function(){
    var returnedObject = this.dp.hide();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('update - String', function(){
    var returnedObject = this.dp.update('13-03-2012');
    datesEqual(this.dp.dates[0], UTCDate(2012, 2, 13));
    var date = this.dp.picker.find('.datepicker-days td:contains(13)');
    ok(date.is('.active'), 'Date is selected');
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('update - Date', function(){
    var returnedObject = this.dp.update(new Date(2012, 2, 13));
    datesEqual(this.dp.dates[0], UTCDate(2012, 2, 13));
    var date = this.dp.picker.find('.datepicker-days td:contains(13)');
    ok(date.is('.active'), 'Date is selected');
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('update - null', function(){
    var returnedObject = this.dp.update(null);
    equal(this.dp.dates[0], undefined);
    var selected = this.dp.picker.find('.datepicker-days td.active');
    equal(selected.length, 0, 'No date is selected');
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setDate', function(){
    var date_in = new Date(2013, 1, 1),
        expected_date = new Date(Date.UTC(2013, 1, 1)),
        returnedObject;

    notEqual(this.dp.dates[0], date_in);
    returnedObject = this.dp.setDate(date_in);
    strictEqual(returnedObject, this.dp, "is chainable");
    datesEqual(this.dp.dates[0], expected_date);
});

test('setUTCDate', function(){
    var date_in = new Date(Date.UTC(2012, 3, 5)),
        expected_date = date_in,
        returnedObject;

    notEqual(this.dp.dates[0], date_in);
    returnedObject = this.dp.setUTCDate(date_in);
    strictEqual(returnedObject, this.dp, "is chainable");
    datesEqual(this.dp.dates[0], expected_date);
});

test('setStartDate', function(){
    var date_in = new Date(Date.UTC(2012, 3, 5)),
        expected_date = date_in,
        returnedObject = this.dp.setStartDate(date_in);
    // ...
    datesEqual(this.dp.o.startDate, expected_date);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setEndDate', function(){
    var date_in = new Date(Date.UTC(2012, 3, 5)),
        expected_date = date_in,
        returnedObject = this.dp.setEndDate(date_in);
    // ...
    datesEqual(this.dp.o.endDate, expected_date);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setDaysOfWeekDisabled - String', function(){
    var days_in = "0,6",
        expected_days = [0,6],
        returnedObject = this.dp.setDaysOfWeekDisabled(days_in);
    // ...
    deepEqual(this.dp.o.daysOfWeekDisabled, expected_days);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setDaysOfWeekDisabled - Array', function(){
    var days_in = [0,6],
        expected_days = days_in,
        returnedObject = this.dp.setDaysOfWeekDisabled(days_in);
    // ...
    deepEqual(this.dp.o.daysOfWeekDisabled, expected_days);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setValue', function(){
    var returnedObject = this.dp.setValue();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('place', function(){
    var returnedObject = this.dp.place();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('moveMonth - can handle invalid date', function(){
    // any input which results in an invalid date, f.e. an incorrectly formatted.
    var invalidDate = new Date("invalid"),
        returnedObject = this.dp.moveMonth(invalidDate, 1);
    // ...
    equal(returnedObject, undefined, "returnedObject");
});
<commit_msg>Fixed test to assert intended outcome<commit_after>module('Methods', {
    setup: function(){
        this.input = $('<input type="text" value="31-03-2011">')
                        .appendTo('#qunit-fixture')
                        .datepicker({format: "dd-mm-yyyy"});
        this.dp = this.input.data('datepicker')
    },
    teardown: function(){
        this.dp.remove();
    }
});

test('remove', function(){
    var returnedObject = this.dp.remove();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('show', function(){
    var returnedObject = this.dp.show();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('hide', function(){
    var returnedObject = this.dp.hide();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('update - String', function(){
    var returnedObject = this.dp.update('13-03-2012');
    datesEqual(this.dp.dates[0], UTCDate(2012, 2, 13));
    var date = this.dp.picker.find('.datepicker-days td:contains(13)');
    ok(date.is('.active'), 'Date is selected');
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('update - Date', function(){
    var returnedObject = this.dp.update(new Date(2012, 2, 13));
    datesEqual(this.dp.dates[0], UTCDate(2012, 2, 13));
    var date = this.dp.picker.find('.datepicker-days td:contains(13)');
    ok(date.is('.active'), 'Date is selected');
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('update - null', function(){
    var returnedObject = this.dp.update(null);
    equal(this.dp.dates[0], undefined);
    var selected = this.dp.picker.find('.datepicker-days td.active');
    equal(selected.length, 0, 'No date is selected');
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setDate', function(){
    var date_in = new Date(2013, 1, 1),
        expected_date = new Date(Date.UTC(2013, 1, 1)),
        returnedObject;

    notEqual(this.dp.dates[0], date_in);
    returnedObject = this.dp.setDate(date_in);
    strictEqual(returnedObject, this.dp, "is chainable");
    datesEqual(this.dp.dates[0], expected_date);
});

test('setUTCDate', function(){
    var date_in = new Date(Date.UTC(2012, 3, 5)),
        expected_date = date_in,
        returnedObject;

    notEqual(this.dp.dates[0], date_in);
    returnedObject = this.dp.setUTCDate(date_in);
    strictEqual(returnedObject, this.dp, "is chainable");
    datesEqual(this.dp.dates[0], expected_date);
});

test('setStartDate', function(){
    var date_in = new Date(Date.UTC(2012, 3, 5)),
        expected_date = date_in,
        returnedObject = this.dp.setStartDate(date_in);
    // ...
    datesEqual(this.dp.o.startDate, expected_date);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setEndDate', function(){
    var date_in = new Date(Date.UTC(2012, 3, 5)),
        expected_date = date_in,
        returnedObject = this.dp.setEndDate(date_in);
    // ...
    datesEqual(this.dp.o.endDate, expected_date);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setDaysOfWeekDisabled - String', function(){
    var days_in = "0,6",
        expected_days = [0,6],
        returnedObject = this.dp.setDaysOfWeekDisabled(days_in);
    // ...
    deepEqual(this.dp.o.daysOfWeekDisabled, expected_days);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setDaysOfWeekDisabled - Array', function(){
    var days_in = [0,6],
        expected_days = days_in,
        returnedObject = this.dp.setDaysOfWeekDisabled(days_in);
    // ...
    deepEqual(this.dp.o.daysOfWeekDisabled, expected_days);
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('setValue', function(){
    var returnedObject = this.dp.setValue();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('place', function(){
    var returnedObject = this.dp.place();
    // ...
    strictEqual(returnedObject, this.dp, "is chainable");
});

test('moveMonth - can handle invalid date', function(){
    // any input which results in an invalid date, f.e. an incorrectly formatted.
    var invalidDate = new Date("invalid"),
        returnedObject = this.dp.moveMonth(invalidDate, 1);
    // ...
    equal(this.input.val(), "31-03-2011", "date is reset");
});
<|endoftext|>


<commit_before>/*jshint regexp:false*/

'use strict';

var fs           = require('fs');
var async        = require('async');
var path         = require('path');
var utils        = require('amd-utils');
var expand       = require('./cp').expand;
var relativePath = require('./cp').relativePath;

var task = {
    id          : 'mv',
    author      : 'Indigo United',
    name        : 'Move',
    description : 'Move a file or set of files.',
    options: {
        files: {
            description: 'Which files to move. Accepts an object in which keys are the source files and values the destination. Source values support minimatch.'
        },
        glob: {
            description: 'The options to pass to glob (check https://npmjs.org/package/glob for details).',
            'default': null
        }
    },
    tasks      :
    [
        {
            task: function (opt, ctx, next) {
                // TODO: standardize behavior with unix mv
                //       - If dst does not exist, give error
                //       - Moving a directory into a file should give error
                //       - Moving a directory/file, into another directory that exists
                //         but does not end with a /, it should act like it did
                //       - Moving a file into a file is obvious
                opt.glob = opt.glob || {};
                var sources = Object.keys(opt.files);

                // Foreach source file..
                // Note that series is used to avoid conflicts between each pattern
                async.forEachSeries(sources, function (pattern, next) {
                    var dsts = utils.lang.isArray(opt.files[pattern]) ? opt.files[pattern] : [opt.files[pattern]];
                    dsts = utils.array.unique(dsts.map(function (dst) { return path.normalize(dst); }));

                    // If the user specified a /**/* pattern, optimize it
                    if (!opt.glob || !opt.glob.noglobstar) {
                        pattern = pattern.replace(/(\/\*\*\/\*)+$/g, '/*');
                    }

                    // Expand the files to get an array of files and directories
                    // The files do not overlap directories and directories do not overlay eachother
                    expand(pattern, opt.glob, function (err, files, dirs, directMatch) {
                        // If the source pattern was a direct match
                        // Move directly to the dests
                        if (directMatch) {
                            return async.forEach(dsts, function (dst, next) {
                                var src = dirs[0] || files[0];
                                // If the source is a directory
                                // or a file which dst ends with /, concatenate the source basename.
                                if (/[\/\\]$/.test(dst)) {
                                    dst = path.join(dst, path.basename(src));
                                }

                                return fs.rename(src, dst, next);
                            }, next);
                        }

                        // Create a batch of files and folders
                        var batch = [],
                            cache;

                        batch.push.apply(batch, files);
                        batch.push.apply(batch, dirs);

                        // Analyze the structure of the source entries,
                        // generating a cache of stat's
                        cache = analyzeStructure(batch, pattern, null, function (err) {
                            if (err) {
                                return next(err);
                            }

                            // For each dst, replicate the structure before actually proceed to the rename
                            async.forEach(dsts, function (dst, next) {
                                replicateStructure(dst, cache, pattern, function (err) {
                                    if (err) {
                                        return next(err);
                                    }

                                    // Rename everything
                                    async.forEach(batch, function (src, next) {
                                        var finalDst = path.join(dst, relativePath(src, pattern));
                                        fs.rename(src, finalDst, next);
                                    }, next);
                                });
                            }, next);
                        });
                    });
                }, next);
            }
        }
    ]
};

/**
 * Analyzes the structure of an array of files,
 * generating a stat cache (mode only) for each subpath found.
 *
 * @param {Array}    files    The files
 * @param {String}   pattern  The original path used in glob
 * @param {Object}   [cache]  The cache to be used, will create one if not specified.
 * @param {Function} callback The function to call when done, following the node convetion
 *
 * @return {Object}  The cache object
 */
function analyzeStructure(files, pattern, cache, callback) {
    cache = cache || {};

    if (!files.length) {
        return callback();
    }

    // Extract the base path
    var currPath = files[0],
        length = currPath.length,
        basePath,
        x,
        remaining = [];

    for (x = 0; x < length; ++x) {
        if (currPath[x] !== pattern[x]) {
            basePath = path.normalize(currPath.substr(0, x)).replace(/[\/\\]+$/, '');
            break;
        }
    }

    // Then, find paths that have not being stated yet
    length = files.length;
    for (x = 0; x < length; x++) {
        currPath = files[x];

        while ((currPath = path.dirname(currPath)) && currPath !== basePath) {
            if (cache[currPath]) {
                break;
            } else {
                cache[currPath] = -1;
                remaining.push(currPath);
            }
        }
    }

    // Finally, stat them and add them to the cache
    async.forEachSeries(remaining, function (entry, next) {
        var parts = entry.split(path.sep),
            partsLength = parts.length,
            i = 1;

        async.until(function () { return i > partsLength; }, function (next) {
            var curr = path.join.apply(path, parts.slice(0, i));
            ++i;

            if (cache[curr] !== -1) {
                return next();
            }

            cache[curr] = true;
            fs.stat(curr, function (err, stat) {
                if (err) {
                    return next(err);
                }

                cache[curr] = stat.mode;
                next();
            });
        }, next);
    }, callback);

    return cache;
}

/**
 * Replicates the structure present in the cache into dst.
 *
 * @param {String}   dst      The dst path
 * @param {String}   pattern  The original path used in glob
 * @param {Object}   cache    The cache.
 * @param {Function} callback The function to call when done, following the node convetion
 */
function replicateStructure(dst, pattern, cache, callback) {
    var basePathPos = 0,
        paths = Object.keys(cache),
        currPath,
        length,
        x;

    if (!paths.length) {
        return callback();
    }

    // Find the base path pos
    pattern = path.normalize(pattern);
    currPath = paths[0];
    length = currPath.length;
    for (x = 0; x < length; ++x) {
        if (currPath[x] !== pattern[x]) {
            basePathPos = x;
            break;
        }
    }

    // Order the paths from small to large
    paths.sort(sortFunc);

    // For each path in the cache, create the correspondent directory
    // in the dst, respecting the mode stored in the cache
    length = paths.length;
    async.forEachSeries(paths, function (currPath, next) {
        var dstPath = path.join(dst, currPath.substr(basePathPos));
        fs.mkdir(dstPath, cache[currPath], next);
    }, callback);
}

/**
 * Sort function used in the replicate structure.
 */
function sortFunc(first, second) {
    var firstLength = first.length;
    var secondLength = second.length;

    if (firstLength > secondLength) {
        return 1;
    }
    if (firstLength < secondLength) {
        return -1;
    }

    return 0;
}

module.exports = task;<commit_msg>Refactor the mv task (similar to cp).<commit_after>'use strict';

var glob    = require('glob');
var async   = require('async');
var path    = require('path');
var fs      = require('fs');
var utils   = require('amd-utils');
var mkdirp  = require('mkdirp');

var task = {
    id          : 'mv',
    author      : 'Indigo United',
    name        : 'Move',
    description : 'Move a file or set of files.',
    options: {
        files: {
            description: 'Which files should be moved. Accepts an object in which keys are the source files and values the destination. Source values support minimatch.'
        },
        glob: {
            description: 'The options to pass to glob (check https://npmjs.org/package/glob for details).',
            'default': null
        }
    },
    tasks:
    [
        {
            task: function (opt, ctx, next) {
                opt.glob = opt.glob || {};
                var sources = Object.keys(opt.files);
                var error;

                // Cycle through each source
                // Note that series is used to avoid conflicts between each pattern
                async.forEachSeries(sources, function (pattern, next) {
                    var dsts = utils.lang.isArray(opt.files[pattern]) ? opt.files[pattern] : [opt.files[pattern]];
                    dsts = utils.array.unique(dsts.map(function (dst) { return path.normalize(dst); }));
                    pattern = path.normalize(pattern);

                    // Expand the files to get an array of files and directories
                    expand(pattern, opt.glob, function (err, files, dirs, directMatch) {
                        if (err) {
                            return next(err);
                        }

                        if (!files.length && !dirs.length) {
                            error = new Error('ENOENT, no such file or directory \'' + pattern + '\'');
                            error.code = 'ENOENT';
                            return next(error);
                        }

                        // Process the matches for each dst
                        async.forEach(dsts, function (dst, next) {
                            if (directMatch) {
                                processDirectMatch(files, dirs, dst, next);
                            } else {
                                processPatternMatch(pattern, files, dirs, dst, next);
                            }
                        }, next);
                    });
                }, next);
            }
        }
    ]
};

/**
 * Processes a direct match.
 *
 * @param {Array}    files The files
 * @param {Array}    dirs  The directories
 * @param {String}   dst   The destination
 * @param {Function} next  The callback to call with the files and folders (follows node conventions)
 */
function processDirectMatch(files, dirs, dst, next) {
    var src = files[0] || dirs[0];
    var srcType = files[0] === src ? 'file' : 'dir';
    var dstType;
    var error;

    // Check if dirname of the dst exists
    fs.stat(path.dirname(dst), function (err) {
        if (err) {
            return next(err);
        }

        // Dst is a folder if:
        //  - if exists and is a folder
        //  - ends with /
        fs.stat(dst, function (err, stat) {
            if (stat) {
                dstType = stat.isFile() ? 'file' : 'dir';
            } else {
                dstType = utils.string.endsWith(dst, '/') ? 'dir' : srcType;
            }

            // Check if move is possible
            if (srcType === 'dir' && dstType === 'file') {
                error = new Error('ENODIR, not a directory: \'' + dst + '\'');
                error.code = 'ENODIR';
                return next(error);
            }

            // Folder to folder
            if (srcType === 'dir' && dstType === 'dir') {
                // When moving to a folder that already exists
                // or ends with a /, the user is trying to move the folder
                // inside it
                if (stat || utils.string.endsWith(dst, '/')) {
                    dst = path.join(dst, path.basename(src));
                }

                mkdirp(dst, function (err) {
                    if (err) {
                        return err;
                    }

                    move(src, dst, next);
                });
            // File to folder
            } else if (srcType === 'file' && dstType === 'dir') {
                // If moving file to dir, ensure that the dir is created
                // and perform a file to file move afterwards
                if (!stat) {
                    fs.mkdir(dst, function (err) {
                        if (err) {
                            return err;
                        }

                        dst = path.join(dst, path.basename(src));
                        move(src, dst, next);
                    });
                } else {
                    dst = path.join(dst, path.basename(src));
                    move(src, dst, next);
                }
            // File to file is simple
            } else {
                move(src, dst, next);
            }
        });
    });
}

/**
 * Processes a pattern match.
 *
 * @param {String}   pattern The pattern
 * @param {Array}    files   The files
 * @param {Array}    dirs    The directories
 * @param {String}   dst     The destination
 * @param {Function} next    The callback to call with the files and folders (follows node conventions)
 */
function processPatternMatch(pattern, files, dirs, dst, next) {
    files.push.apply(files, dirs);

    async.forEachLimit(files, 30, function (file, next) {
        var currDst = path.join(dst, relativePath(file, pattern));

        mkdirp(path.dirname(currDst), function (err) {
            if (err) {
                return next(err);
            }

            move(file, currDst, next);
        });
    }, next);
}

/**
 * Moves a file or directory.
 *
 * @param {String}   src  The source
 * @param {String}   dst  The destination
 * @param {Function} next The function to call when done (follows node conventions)
 */
function move(src, dst, next) {
    fs.rename(src, dst, next);
}

/**
 * Expands the given minimatch pattern to an array of files and an array of dirs.
 * The dirs are guaranteed to not overlap files.
 *
 * @param {String}   pattern The pattern
 * @param {Object}   options The options to pass to the glob
 * @param {Function} next    The callback to call with the files and folders (follows node conventions)
 */
function expand(pattern, options, next) {
    var files = [];
    var dirs = [];
    var lastMatch;

    options = options || {};

    // TODO: throw an error on commas

    // If the user specified a /**/* pattern, optimize it
    if (!options.glob || !options.glob.noglobstar) {
        pattern = pattern.replace(/(\/\*\*\/\*)+$/g, '/*');
    }

    // Mark option is bugged for single * patterns
    // See: https://github.com/isaacs/node-glob/issues/50
    // For now we stat ourselves
    //options.mark = true;
    glob(pattern, options, function (err, matches) {
        if (err) {
            return next(err);
        }

        async.forEach(matches, function (match, next) {
            fs.stat(match, function (err, stat) {
                if (err) {
                    return next(err);
                }

                match = path.normalize(match);

                if (stat.isFile()) {
                    lastMatch = match;
                    files.push(lastMatch);
                } else {
                    lastMatch = match.replace(/[\/\\]+$/, '');
                    dirs.push(lastMatch);
                }

                next();
            });
        }, function (err) {
            if (err) {
                return next(err);
            }

            // If we only got one match and it was the same as the original pattern,
            // then it was a direct match
            var directMatch = matches.length === 1 && lastMatch === path.normalize(pattern).replace(/[\/\\]+$/, '');
            if (!directMatch) {
                cleanup(files, dirs);
            }

            next(null, files, dirs, directMatch);
        });
    });
}

/**
 * Takes an array of files and folders and takes care of overlapping.
 * See the expand function for more info.
 *
 * @param {Array} files The array of files
 * @param {Array} dirs  The array of dirs
 */
function cleanup(files, dirs) {
    var x, y;

    // Cleanup files that overlap dirs
    dirs.forEach(function (dir) {
        for (x = files.length - 1; x >= 0; --x) {
            if (path.dirname(files[x]).indexOf(dir) === 0) {
                files.splice(x, 1);
            }
        }
    });

    // Cleanup dirs that overlap eachother
    for (x = 0; x < dirs.length; ++x) {
        for (y = x + 1; y < dirs.length; ++y) {
            if (dirs[y].indexOf(dirs[x]) === 0) {
                dirs.splice(y, 1);
                --x;
                --y;
            }
        }
    }
}

/**
 * Gets the relative path of a file relative to the pattern.
 * For instance:
 *   file = /a/b.js
 *   pattern = /a/*
 *
 * Should return b.js
 *
 * @param {String} file    The file
 * @param {String} pattern The pattern
 *
 * @return {String} The relative path
 */
function relativePath(file, pattern) {
    var length = file.length,
        x;

    pattern = path.normalize(pattern);

    for (x = 0; x < length; ++x) {
        if (file[x] !== pattern[x]) {
            return file.substr(x);
        }
    }

    return path.basename(file);
}

module.exports = task;<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
const define  = require('../define');

const { GuessPlugin } = require('guess-webpack');
const environment = require('../environment').config;
const WebpackChunkHash = require('webpack-chunk-hash');
const WebpackManifestPlugin = require('webpack-manifest-plugin');

const plugins = [
    GuessPlugin({ GA: environment.GOOGLE_ANALYTICS_ID }),

    new WebpackManifestPlugin({
        basePath: define.rs_output_path,
        fileName: "../webpack-manifest.json"
    }),

    new WebpackChunkHash(),

    new webpack.HashedModuleIdsPlugin(),

    new webpack.optimize.ModuleConcatenationPlugin(),
    new webpack.optimize.AggressiveMergingPlugin()
];

module.exports.config = plugins;
<commit_msg>upgrade dependencies<commit_after>'use strict';

const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
const define  = require('../define');

// const { GuessPlugin } = require('guess-webpack');
// const environment = require('../environment').config;
const WebpackChunkHash = require('webpack-chunk-hash');
const WebpackManifestPlugin = require('webpack-manifest-plugin');

const plugins = [
    // GuessPlugin({ GA: environment.GOOGLE_ANALYTICS_ID }),

    new WebpackManifestPlugin({
        basePath: define.rs_output_path,
        fileName: "../webpack-manifest.json"
    }),

    new WebpackChunkHash(),

    new webpack.HashedModuleIdsPlugin(),

    new webpack.optimize.ModuleConcatenationPlugin(),
    new webpack.optimize.AggressiveMergingPlugin()
];

module.exports.config = plugins;
<|endoftext|>