<commit_before>import 'bootstrap/scss/bootstrap.scss';
import 'font-awesome/css/font-awesome.min.css';
import './app.scss';

import React, { Component, PropTypes } from 'react';
import { BrowserRouter, Match, Link, Miss, Redirect } from 'react-router';
import { connect } from 'react-redux';

import { authUser, logoutUser, getDefaultDirectories } from '../../actions';

import LoginContainer from './../Login';
import RegisterContainer from './../Register';
import ProfileContainer from './../Profile';
import AccountContainer from './../Account';
import SubContainer from './../Sub';

import Home from '../../components/Home';
import NotFound from '../../components/NotFound';

import NavigationDrawer from '../../components/Navigation';
import Container from '../../components/Container';
import Header from '../../components/Header';
import Footer from '../../components/Footer';
import Spinner from '../../components/Spinner';

class App extends Component {
  state = {
    navOpen: false,
    fixedDrawer: false
  };

  componentWillMount() {
    this.updateDimensions();
    window.addEventListener("resize", this.updateDimensions.bind(this));

    this.props.getDefaultDirectories();

    if(localStorage.getItem('token')){
      this.props.authUser();
    }
  }

  componentWillReceiveProps(nextProps){
    console.log('component will recieve props', nextProps);
  }

  updateDimensions(){
    if(window.innerWidth > 767){
      this.setState({fixedDrawer: true});
    }else{
      this.setState({fixedDrawer: false});
    }
  }

  toggleDrawer(){
    const navOpen = !this.state.navOpen;
    this.setState({navOpen});
  }

  render() {
    const MatchWhenAuthorized = ({ component: Component, ...rest }) => (
      <Match {...rest} render={props => (
        this.props.isAuthenticated ? (
          <Component {...props}/>
        ) : this.props.isAuthenticating ? (
          <Spinner />
        ) : (
          <NotFound />
        )
      )}/>
    )

    const LogoutComponent = ({ component: Component, ...rest }) => {

      this.props.logoutUser();

      return (
        <Redirect to={{
          pathname: '/'
        }}/>
    )}

    return (
      <BrowserRouter>
          <app>
            <NavigationDrawer
              defaultDirectories={this.props.defaultDirectories}
              fixed={this.state.fixedDrawer}
              open={this.state.navOpen}
              onClose={this.toggleDrawer.bind(this)}
            />

              <Match exactly pattern="/" component={Home}/>
              <Match exactly pattern="/profile" component={ProfileContainer}/>
              <Match exactly pattern="/login" component={LoginContainer}/>
              <Match exactly pattern="/register" component={RegisterContainer}/>
              <Match exactly pattern="/logout" component={LogoutComponent}/>
              <Match exactly pattern="/s/:sub" component={SubContainer}/>
              <MatchWhenAuthorized pattern="/account/:setting" component={AccountContainer}/>
              <Miss component={NotFound}/>

          </app>
      </BrowserRouter>
    );
  }
}

const mapStateToProps = state => ({
  title: state.Page.title,
  userInfo: state.Auth.userInfo,
  isAuthenticated: state.Auth.isAuthenticated,
  isAuthenticating: state.Auth.isAuthenticating,
  defaultDirectories: state.Directories.default || []
})

export default connect(mapStateToProps,
  {
    authUser,
    logoutUser,
    getDefaultDirectories
  }
)(App)
<commit_msg>Changed name on directory param<commit_after>import 'bootstrap/scss/bootstrap.scss';
import 'font-awesome/css/font-awesome.min.css';
import './app.scss';

import React, { Component, PropTypes } from 'react';
import { BrowserRouter, Match, Link, Miss, Redirect } from 'react-router';
import { connect } from 'react-redux';

import { authUser, logoutUser, getDefaultDirectories } from '../../actions';

import LoginContainer from './../Login';
import RegisterContainer from './../Register';
import ProfileContainer from './../Profile';
import AccountContainer from './../Account';
import SubContainer from './../Sub';

import Home from '../../components/Home';
import NotFound from '../../components/NotFound';

import NavigationDrawer from '../../components/Navigation';
import Container from '../../components/Container';
import Header from '../../components/Header';
import Footer from '../../components/Footer';
import Spinner from '../../components/Spinner';

class App extends Component {
  state = {
    navOpen: false,
    fixedDrawer: false
  };

  componentWillMount() {
    this.updateDimensions();
    window.addEventListener("resize", this.updateDimensions.bind(this));

    this.props.getDefaultDirectories();

    if(localStorage.getItem('token')){
      this.props.authUser();
    }
  }

  componentWillReceiveProps(nextProps){
    //console.log('component will recieve props', nextProps);
  }

  updateDimensions(){
    if(window.innerWidth > 767){
      this.setState({fixedDrawer: true});
    }else{
      this.setState({fixedDrawer: false});
    }
  }

  toggleDrawer(){
    const navOpen = !this.state.navOpen;
    this.setState({navOpen});
  }

  render() {
    const MatchWhenAuthorized = ({ component: Component, ...rest }) => (
      <Match {...rest} render={props => (
        this.props.isAuthenticated ? (
          <Component {...props}/>
        ) : this.props.isAuthenticating ? (
          <Spinner />
        ) : (
          <NotFound />
        )
      )}/>
    )

    const LogoutComponent = ({ component: Component, ...rest }) => {

      this.props.logoutUser();

      return (
        <Redirect to={{
          pathname: '/'
        }}/>
    )}

    return (
      <BrowserRouter>
          <app>
            <NavigationDrawer
              defaultDirectories={this.props.defaultDirectories}
              fixed={this.state.fixedDrawer}
              open={this.state.navOpen}
              onClose={this.toggleDrawer.bind(this)}
            />

              <Match exactly pattern="/" component={Home}/>
              <Match exactly pattern="/profile" component={ProfileContainer}/>
              <Match exactly pattern="/login" component={LoginContainer}/>
              <Match exactly pattern="/register" component={RegisterContainer}/>
              <Match exactly pattern="/logout" component={LogoutComponent}/>
              <Match exactly pattern="/s/:directory" component={SubContainer}/>
              <MatchWhenAuthorized pattern="/account/:setting" component={AccountContainer}/>
              <Miss component={NotFound}/>

          </app>
      </BrowserRouter>
    );
  }
}

const mapStateToProps = state => ({
  title: state.Page.title,
  userInfo: state.Auth.userInfo,
  isAuthenticated: state.Auth.isAuthenticated,
  isAuthenticating: state.Auth.isAuthenticating,
  defaultDirectories: state.Directories.default || []
})

export default connect(mapStateToProps,
  {
    authUser,
    logoutUser,
    getDefaultDirectories
  }
)(App)
<|endoftext|>


<commit_before>var instantId = 0;

Component = function Component(props, wrapperView, parent) {
  this.id = ++instantId;
  this._instance = new this.componentInstanceClass();
  this._view = this._createView(props);
  this._children = [];
  this._props = props;
  this._parent = parent;

  this.flowContentBlock = wrapperView.templateContentBlock;
  this.flowElseBlock = wrapperView.templateElseBlock;
  this._blockMode = this.flowContentBlock || this.flowElseBlock;
}

Component.prototype.getView = function getView() {
  return this._view;
};

Component.prototype._createView = function(props) {
  var templateIntance = this._getTemplate();
  var view = Blaze._TemplateWith({}, function() {
    return Spacebars.include(templateIntance);
  });

  view.onViewCreated(this._init.bind(this, props, view));
  view._onViewRendered(this._rendered.bind(this));
  view.onViewDestroyed(this._destroyed.bind(this));
  view._component = this;

  return view;
};

Component.prototype._getFn = function(name) {
  var self = this;
  return function() {
    return function() {
      return self._get(name);
    };
  };
};

Component.prototype._get = function(name) {
  var self = this;
  var args = _.toArray(arguments);
  args.pop();
  args.shift();

  if(typeof self.stateDefs[name] == "function") {
    return self.stateDefs[name].apply(self._instance, args);
  } else if(typeof self.stateDefs[name] !== "undefined") {
    return self.stateDefs[name];
  } else {
    var value = self._instance._state.get(name);
    // If we are inside a component rendered as _blockMode, we should allow
    // to access the parent component's data context.
    // This is how we do it.
    if(value === undefined && this._blockMode && self._parent) {
      // we can check it from the parent.
      return self._parent._get(name);
    } else {
      return value;
    }
  }
};

Component.prototype._init = function _init(params, view) {
  if(this.created) {
    this._instance._view = view;
    this.created.call(this._instance, params);
  }

  if(this.destroyed) {
    this._instance.onDestroyed(this.destroyed);
  }

  if(this.rendered) {
    this._instance.onRendered(this.rendered);
  }
};

Component.prototype._getTemplate = function() {
  return Template[this.template || this.name];
};

Component.prototype._rendered = function() {
  _.each(this._instance._renderedCallback, function(cb) {
    // Even though we fired the rendered callback,
    // the DOM is not ready yet!
    // We can make sure DOM is ready with this trick.
    Tracker.afterFlush(cb);
  });
};

Component.prototype._destroyed = function() {
  _.each(this._instance._destroyedCallbacks, function(cb) {
    cb();
  });
};

Component.prototype.emitPrivateAction = function(privateEvent, args) {
  var action = this.actionDefs[privateEvent];
  if(!action) {
    throw new Error("there is no such private action: " + this.name + ".action." + privateEvent);
  }

  action.apply(this._instance, args);
};<commit_msg>Add support to get actions inside a block<commit_after>var instantId = 0;

Component = function Component(props, wrapperView, parent) {
  this.id = ++instantId;
  this._instance = new this.componentInstanceClass();
  this._view = this._createView(props);
  this._children = [];
  this._props = props;
  this._parent = parent;

  this.flowContentBlock = wrapperView.templateContentBlock;
  this.flowElseBlock = wrapperView.templateElseBlock;
  this._blockMode = !!(this.flowContentBlock || this.flowElseBlock);
}

Component.prototype.getView = function getView() {
  return this._view;
};

Component.prototype._createView = function(props) {
  var templateIntance = this._getTemplate();
  var view = Blaze._TemplateWith({}, function() {
    return Spacebars.include(templateIntance);
  });

  view.onViewCreated(this._init.bind(this, props, view));
  view._onViewRendered(this._rendered.bind(this));
  view.onViewDestroyed(this._destroyed.bind(this));
  view._component = this;

  return view;
};

Component.prototype._getFn = function(name) {
  var self = this;
  return function() {
    return function() {
      return self._get(name);
    };
  };
};

Component.prototype._get = function(name) {
  var self = this;
  var args = _.toArray(arguments);
  args.pop();
  args.shift();

  if(typeof self.stateDefs[name] == "function") {
    return self.stateDefs[name].apply(self._instance, args);
  } else if(typeof self.stateDefs[name] !== "undefined") {
    return self.stateDefs[name];
  } else {
    var value = self._instance._state.get(name);
    // If we are inside a component rendered as _blockMode, we should allow
    // to access the parent component's data context.
    // This is how we do it.
    if(value === undefined && this._blockMode && self._parent) {
      // we can check it from the parent.
      return self._parent._get(name);
    } else {
      return value;
    }
  }
};

Component.prototype._init = function _init(params, view) {
  if(this.created) {
    this._instance._view = view;
    this.created.call(this._instance, params);
  }

  if(this.destroyed) {
    this._instance.onDestroyed(this.destroyed);
  }

  if(this.rendered) {
    this._instance.onRendered(this.rendered);
  }
};

Component.prototype._getTemplate = function() {
  return Template[this.template || this.name];
};

Component.prototype._rendered = function() {
  _.each(this._instance._renderedCallback, function(cb) {
    // Even though we fired the rendered callback,
    // the DOM is not ready yet!
    // We can make sure DOM is ready with this trick.
    Tracker.afterFlush(cb);
  });
};

Component.prototype._destroyed = function() {
  _.each(this._instance._destroyedCallbacks, function(cb) {
    cb();
  });
};

Component.prototype._getPrivateAction = function(actionName) {
  var action = this.actionDefs[actionName];

  // When we are inside a block we need to get the action from the parent
  if(!action && this._blockMode && this._parent) {
    action = this._parent._getPrivateAction(actionName);
  }

  return action;
};

Component.prototype.emitPrivateAction = function(privateEvent, args) {
  var action = this._getPrivateAction(privateEvent);

  if(!action) {
    throw new Error("there is no such private action: " + this.name + ".action." + privateEvent);
  }

  action.apply(this._instance, args);
};<|endoftext|>


<commit_before>var md5 = require('./md5.js');
var assert = require('assert');

describe('MD5', function () {
  it('should return the expected MD5 hash for "message"', function () {
    assert.equal('78e731027d8fd50ed642340b7c9a63b3', md5('message'));
  });

  it('should not return the same hash for random numbers twice', function () {
    var msg1 = Math.floor((Math.random() * 100000) + 1) + (new Date).getTime();
    var msg2 = Math.floor((Math.random() * 100000) + 1) + (new Date).getTime();

    if (msg1 !== msg2)
      assert.notEqual(md5(msg1), md5(msg2));
    else
      assert.equal(md5(msg1), md5(msg1));
  });
});
<commit_msg>Buffer test<commit_after>var md5 = require('./md5.js');
var assert = require('assert');

describe('MD5', function () {
  it('should return the expected MD5 hash for "message"', function () {
    assert.equal('78e731027d8fd50ed642340b7c9a63b3', md5('message'));
  });

  it('should not return the same hash for random numbers twice', function () {
    var msg1 = Math.floor((Math.random() * 100000) + 1) + (new Date).getTime();
    var msg2 = Math.floor((Math.random() * 100000) + 1) + (new Date).getTime();

    if (msg1 !== msg2)
      assert.notEqual(md5(msg1), md5(msg2));
    else
      assert.equal(md5(msg1), md5(msg1));
  });

  it('should support Node.js Buffers', function() {
    var buffer = new Buffer('message áßäöü', 'utf8');

    assert.equal(md5(buffer), md5('message áßäöü'));
  })
});
<|endoftext|>


<commit_before>var _ = require('lodash');
var debug = require('debug');
var warn = debug('viewdb:warn');

var defaultOptions = {
  resumeObservesOnReconnect: false // if local writes should be sent over the wire to remote
};

var Client = function (socket, options) {
  if (socket) {
    this.connect(socket);
  }
  _.defaults(options || {}, defaultOptions);
};

Client.prototype.connect = function (socket) {
  this._socket = socket;
  this._requests = {};
  this._requestId = 10;
  var self = this;
  this._socket.on('/vdb/response', function (event) {
    if (event.e) {
      throw new Error(event.e);
    }
    var request = self._requests[event.i];
    if (_.isUndefined(request)) {
      warn('Response for unregistered request', event);
    } else {
      var callback = request.cb;
      callback(null, event.p);
      if (!request.k) { // non persistent request
        delete self._requests[event.i];
      }
    }
  });
};

Client.prototype.request = function (payload, callback, persistent) {
  var req = {
    i: this._requestId++,
    p: payload
  };
  this._requests[req.i] = { cb: callback, k: persistent };
  this._socket.emit('/vdb/request', req);
  return req.i;
};

Client.prototype.subscribe = function (payload, callback) {
  var self = this;
  var i = this.request(payload, callback, true);
  return {
    stop: function () {
      delete self._requests[i];
    }
  };
};

// to signal that a socket reconnection have been made, and that observers need to start over.
// - socket owner is responsible to ensure that proper authentication/setup have been made before calling this function.
Client.prototype.onClientReconnected = function () {
  var self = this;
  _.forEach(this._requests, function (request, index) {
    if (request.k) { // persistent aka observe
      var callback = request.cb;
      callback('reconnected');
    } else {
      delete self._requests[index];
    }
  });
};

module.exports = Client;
<commit_msg>remove unused option<commit_after>var _ = require('lodash');
var debug = require('debug');
var warn = debug('viewdb:warn');

var Client = function (socket) {
  if (socket) {
    this.connect(socket);
  }
};

Client.prototype.connect = function (socket) {
  this._socket = socket;
  this._requests = {};
  this._requestId = 10;
  var self = this;
  this._socket.on('/vdb/response', function (event) {
    if (event.e) {
      throw new Error(event.e);
    }
    var request = self._requests[event.i];
    if (_.isUndefined(request)) {
      warn('Response for unregistered request', event);
    } else {
      var callback = request.cb;
      callback(null, event.p);
      if (!request.k) { // non persistent request
        delete self._requests[event.i];
      }
    }
  });
};

Client.prototype.request = function (payload, callback, persistent) {
  var req = {
    i: this._requestId++,
    p: payload
  };
  this._requests[req.i] = { cb: callback, k: persistent };
  this._socket.emit('/vdb/request', req);
  return req.i;
};

Client.prototype.subscribe = function (payload, callback) {
  var self = this;
  var i = this.request(payload, callback, true);
  return {
    stop: function () {
      delete self._requests[i];
    }
  };
};

// to signal that a socket reconnection have been made, and that observers need to start over.
// - socket owner is responsible to ensure that proper authentication/setup have been made before calling this function.
Client.prototype.onClientReconnected = function () {
  var self = this;
  _.forEach(this._requests, function (request, index) {
    if (request.k) { // persistent aka observe
      var callback = request.cb;
      callback('reconnected');
    } else {
      delete self._requests[index];
    }
  });
};

module.exports = Client;
<|endoftext|>


<commit_before>var chafe = require('./chafe');

var party = function() {
  return {
    guests: [],

    invite: function(name) {
      this.guests.push(name);
    },

    describe: function() {
      return this.guests.join(" and ") + " are dancing";
    }
  };
};

// sane: chain method calls on any object

var birthday = party();
var chain = chafe(birthday)                  // this: { guests: [] }
  .invite("Mary")                            // this: { guests: ["Mary"] }
  .invite("Isla")                            // this: { guests: ["Mary", "Isla"] }
  .invite("Sam");                            // this: { guests: ["Mary", "Isla", "Sam"] }
console.log(chain.describe().chafe.value()); // prints "Mary and Isla and Sam are dancing"

// sanish: switch to pass mode to
//         have each return value be
//         `this` in the next function

chain.chafe.pass()                           // this: "Mary and Isla and Sam are dancing"
  .toUpperCase();                            // this: "MARY AND ISLA AND SAM ARE DANCING"
console.log(chain.chafe.value());            // prints "MARY AND ISLA AND SAM ARE DANCING"

// mental: bind a function as a method
//         to the current `this`

                                             // this: "MARY AND ISLA AND SAM ARE DANCING"
chain.chafe.adhoc(function(punc) {
  return this + punc;
}, "!");                                     // this: "MARY AND ISLA AND SAM ARE DANCING!"
console.log(chain.chafe.value());            // prints "MARY AND ISLA AND SAM ARE DANCING!"
<commit_msg>Remove comments from test now they are in the readme<commit_after>var chafe = require('./chafe');

var party = function() {
  return {
    guests: [],

    invite: function(name) {
      this.guests.push(name);
    },

    describe: function() {
      return this.guests.join(" and ") + " are dancing";
    }
  };
};

 var birthday = party();
    var chain = chafe(birthday);                 // this: { guests: [] }
    chain.invite("Mary")                            // this: { guests: ["Mary"] }
      .invite("Isla")                            // this: { guests: ["Mary", "Isla"] }
      .invite("Sam")                            // this: { guests: ["Mary", "Isla", "Sam"] }
      .describe();
    console.log(chain.chafe.value());

chain.chafe.pass()                           // this: "Mary and Isla and Sam are dancing"
      .toUpperCase();                            // this: "MARY AND ISLA AND SAM ARE DANCING"
    console.log(chain.chafe.value());

                                                 // this: "MARY AND ISLA AND SAM ARE DANCING"
    chain.chafe.adhoc(function(punc) {
      return this + punc;
    }, "!");                                     // this: "MARY AND ISLA AND SAM ARE DANCING!"
    console.log(chain.chafe.value());            // prints "MARY AND ISLA AND SAM ARE DANCING!"
<|endoftext|>


<commit_before>/**
 * Created by tkachenko on 14.04.15.
 */

ATF.controller('SliderController', ['$scope', 'jQuery', 'SliderData'],
    function ($scope, $, data) {
        $scope.$extend({
            items: [],
            data: [],
            itemsShow: {
                768:  3,
                1024: 2
            },
            itemWidth: 314,
            current: 0,
            showingItems: 2,
            span: 5,
            offset: 0,
            currentOffset: 0,
            prevOffset: 0,
            width: 0,
            scrollLeft: 0,
            _handler: null,
            _handler2: null,
            transition: true,
            scrollingEnabled: true,
            scrolling: false,
            animating: false,

            _normalizeIndex: function (_index) {
                var length = this.data.length;
                var index = _index % length;

                if (index < 0) {
                    index = length + index;
                } else if (index >= length) {
                    index = index - length;
                }

                return index;
            },

            _updateOffset: function () {
                var items = [],
                    i, item, cache = {},
                    left = -this.span + this.offset,
                    right = (this.span + 5 + this.offset) - 1;

                for (i = 0; i < this.items.length; i++) {
                    this.items[i].moving = false;
                    if (this.items[i].offset < left ||
                        this.items[i].offset > right) {

                        items.push(i);
                    } else {
                        cache[this.items[i].offset] = true;
                    }
                }

                for (i = -this.span + this.offset; i < (this.span + 5 + this.offset) - 1; i++) {
                    if (!cache[i]) {
                        item = items.pop();

                        this.items[item].offset = i;
                        this.items[item].meta = this._normalizeIndex(i);
                        this.items[item].moving = true;

                        this.checkImage(this.items[item].meta);
                    }
                }
            },

            setOffset: function (value) {
                this.scrollLeft = value;
                if (!this.scrollingEnabled) {
                    return;
                }

                this.scrolling = true;
                this.offset = Math.round(value / this.itemWidth);

                if (this._handler) clearTimeout(this._handler);
                this._handler = setTimeout((function() {
                    this.scrolling = false;
                    var absOffset = Math.abs(value % this.itemWidth);
                    if (absOffset > this.itemWidth / 2) {
                        absOffset = -(this.itemWidth - absOffset);
                    }
                    if (absOffset) {
                        this.transitionScrolling(absOffset);
                    }
                    this.$digest();
                }).bind(this), 100);

                if (this.offset !== this.prevOffset) {
                    var index = this._normalizeIndex(this.offset);
                    this.$emit('slider.slide', index, this.data[index], this.offset - this.prevOffset);
                    this.prevOffset = this.offset;
                    setTimeout((function () {
                        this._updateOffset();
                        this.$digest();
                    }).bind(this), 0);
                }
            },

            transitionScrolling: function (gap, callback) {
                this.targetScrollPosition = this.scrollLeft + gap;
                if (this.scrollLeft < 0) {
                    this.targetScrollPosition = this.scrollLeft + gap;
                } else {
                    this.targetScrollPosition = this.scrollLeft - gap;
                }

                var func = (function () {
                    var gap = this.targetScrollPosition - this.scrollLeft;
                    var absGap = Math.abs(gap);

                    if (absGap < 2) {
                        this.scrollLeft = this.targetScrollPosition;
                        this.timeout = null;
                        setTimeout((function () {
                            this.transitionScrollingInProgress = false;
                            if(callback)callback();
                        }).bind(this), 0);
                    } else if (absGap < 12) {
                        this.scrollLeft += gap >> 1;
                        this.timeout = setTimeout(func, 40);
                    } else {
                        this.scrollLeft += gap >> 2;
                        this.timeout = setTimeout(func, 20);
                    }

                    this.$digest();
                }).bind(this);

                if (!this.timeout) func();

                this.$digest();
            },

            next: function () {
                this.transitionScrolling(this.scrollLeft >= 0 ? -this.itemWidth : this.itemWidth);
            },

            previous: function () {
                this.transitionScrolling(this.scrollLeft >= 0 ? this.itemWidth : -this.itemWidth);
            },

            checkImage: function (index) {
                var img = new Image();
                img.src = this.data[index].previewSrc;
                img.onerror = (function () {
                    this.onImageLoadError(index);
                }).bind(this);
            },

            onTouchStart: function () {
                if (this._handler) {
                    clearTimeout(this._handler);
                    this._handler = null;
                }
                if (this.timeout) {
                    clearTimeout(this.timeout);
                    this.timeout = null;
                }
            },

            onImageLoadError: function (index) {
                var item = this.data.splice(index, 1);
                for (var i = 0; i < this.items.length; i++) {
                    this.items[i].meta = this._normalizeIndex(this.items[i].offset);
                }

                this.$$parent.$apply();
                this.$emit('slider.image-fail', index, item[0]);
            },

            setShowingItems: function (items) {
                items = Math.max(items, 1);
                if (this.showingItems !== items) {
                    this.showingItems = items;

                    this.$apply();
                }
            },

            setItemWidth: function (width) {
                this.itemWidth = width;

                if (this._handler2) clearTimeout(this._handler2);
                this._handler2 = setTimeout((function () {
                    this.$digest();
                    this._handler2 = null;
                }).bind(this), 200);
            },

            goto: function (id) {
                var offset = 0;
                while (this.data[this._normalizeIndex(this.offset + offset)].id !== id) {
                    if (offset === 0) {
                        offset++;
                        continue;
                    }
                    if (offset < 0) offset--;
                    offset = -offset;
                }

                this.scrollLeft = (this.offset + offset) * this.itemWidth;
                this.$digest();
            },

            initialize: function () {
                this.width = this.itemWidth * 1000;
                this.scrollLeft = 0;
                for (var i = -this.span; i < this.span + 5; i++) {
                    var index = this._normalizeIndex(i);
                    this.items.push({
                        offset: i,
                        meta: index
                    });
                    this.checkImage(index);
                }
            }
        });

        var update = function () {
            var width = $(window).width();
            var items = Math.floor(width / 306),
                itemWidth = 306;

            if (width < 732) {
                items = 3;
                itemWidth = Math.floor(width / 3);
            }

            if (width < 480) {
                items = 2;
                itemWidth = Math.floor(width / 2);
            }

            $scope.setShowingItems(Math.max(items, 2));
            $scope.setItemWidth(itemWidth);
        };

        $(window).resize(function () {
            update();
        });

        $scope.$on('goto', function (id) {
            this.goto(id);
        });

        $scope.$watch('data', function () {
            $scope.initialize();
            update();
        });

        data.then(function (data) {
            $scope.data = data.slice(0);
            $scope.$apply();
        });
    }
);<commit_msg>Fixed Bug with Next/Previous<commit_after>/**
 * Created by tkachenko on 14.04.15.
 */

ATF.controller('SliderController', ['$scope', 'jQuery', 'SliderData'],
    function ($scope, $, data) {
        $scope.$extend({
            items: [],
            data: [],
            itemsShow: {
                768:  3,
                1024: 2
            },
            itemWidth: 314,
            current: 0,
            showingItems: 2,
            span: 5,
            offset: 0,
            currentOffset: 0,
            prevOffset: 0,
            width: 0,
            scrollLeft: 0,
            _handler: null,
            _handler2: null,
            transition: true,
            scrollingEnabled: true,
            scrolling: false,
            animating: false,

            _normalizeIndex: function (_index) {
                var length = this.data.length;
                var index = _index % length;

                if (index < 0) {
                    index = length + index;
                } else if (index >= length) {
                    index = index - length;
                }

                return index;
            },

            _updateOffset: function () {
                var items = [],
                    i, item, cache = {},
                    left = -this.span + this.offset,
                    right = (this.span + 5 + this.offset) - 1;

                for (i = 0; i < this.items.length; i++) {
                    this.items[i].moving = false;
                    if (this.items[i].offset < left ||
                        this.items[i].offset > right) {

                        items.push(i);
                    } else {
                        cache[this.items[i].offset] = true;
                    }
                }

                for (i = -this.span + this.offset; i < (this.span + 5 + this.offset) - 1; i++) {
                    if (!cache[i]) {
                        item = items.pop();

                        this.items[item].offset = i;
                        this.items[item].meta = this._normalizeIndex(i);
                        this.items[item].moving = true;

                        this.checkImage(this.items[item].meta);
                    }
                }
            },

            setOffset: function (value) {
                this.scrollLeft = value;
                if (!this.scrollingEnabled) {
                    return;
                }

                this.scrolling = true;
                this.offset = Math.round(value / this.itemWidth);

                if (this._handler) clearTimeout(this._handler);
                this._handler = setTimeout((function() {
                    this.scrolling = false;
                    var absOffset = Math.abs(value % this.itemWidth);
                    if (absOffset > this.itemWidth / 2) {
                        absOffset = -(this.itemWidth - absOffset);
                    }
                    if (absOffset) {
                        this.transitionScrolling(absOffset);
                    }
                    this.$digest();
                }).bind(this), 100);

                if (this.offset !== this.prevOffset) {
                    var index = this._normalizeIndex(this.offset);
                    this.$emit('slider.slide', index, this.data[index], this.offset - this.prevOffset);
                    this.prevOffset = this.offset;
                    setTimeout((function () {
                        this._updateOffset();
                        this.$digest();
                    }).bind(this), 0);
                }
            },

            transitionScrolling: function (gap, callback) {
                if (this.targetScrollPosition === undefined) {
                    this.targetScrollPosition = this.scrollLeft;
                }

                if (this.scrollLeft < 0) {
                    this.targetScrollPosition = this.targetScrollPosition + gap;
                } else {
                    this.targetScrollPosition = this.targetScrollPosition - gap;
                }

                var func = (function () {
                    var gap = this.targetScrollPosition - this.scrollLeft;
                    var absGap = Math.abs(gap);

                    if (absGap < 2) {
                        this.scrollLeft = this.targetScrollPosition;
                        this.timeout = null;
                        setTimeout((function () {
                            this.transitionScrollingInProgress = false;
                            if(callback)callback();
                        }).bind(this), 0);
                    } else if (absGap < 12) {
                        this.scrollLeft += gap >> 1;
                        this.timeout = setTimeout(func, 40);
                    } else {
                        this.scrollLeft += gap >> 2;
                        this.timeout = setTimeout(func, 20);
                    }

                    this.$digest();
                }).bind(this);

                if (!this.timeout) func();

                this.$digest();
            },

            next: function () {
                this.transitionScrolling(this.scrollLeft >= 0 ? -this.itemWidth : this.itemWidth);
            },

            previous: function () {
                this.transitionScrolling(this.scrollLeft >= 0 ? this.itemWidth : -this.itemWidth);
            },

            checkImage: function (index) {
                var img = new Image();
                img.src = this.data[index].previewSrc;
                img.onerror = (function () {
                    this.onImageLoadError(index);
                }).bind(this);
            },

            onTouchStart: function () {
                if (this._handler) {
                    clearTimeout(this._handler);
                    this._handler = null;
                }
                if (this.timeout) {
                    clearTimeout(this.timeout);
                    this.timeout = null;
                }
            },

            onImageLoadError: function (index) {
                var item = this.data.splice(index, 1);
                for (var i = 0; i < this.items.length; i++) {
                    this.items[i].meta = this._normalizeIndex(this.items[i].offset);
                }

                this.$$parent.$apply();
                this.$emit('slider.image-fail', index, item[0]);
            },

            setShowingItems: function (items) {
                items = Math.max(items, 1);
                if (this.showingItems !== items) {
                    this.showingItems = items;

                    this.$apply();
                }
            },

            setItemWidth: function (width) {
                this.itemWidth = width;

                if (this._handler2) clearTimeout(this._handler2);
                this._handler2 = setTimeout((function () {
                    this.$digest();
                    this._handler2 = null;
                }).bind(this), 200);
            },

            goto: function (id) {
                var offset = 0;
                while (this.data[this._normalizeIndex(this.offset + offset)].id !== id) {
                    if (offset === 0) {
                        offset++;
                        continue;
                    }
                    if (offset < 0) offset--;
                    offset = -offset;
                }

                this.scrollLeft = (this.offset + offset) * this.itemWidth;
                this.$digest();
            },

            initialize: function () {
                this.width = this.itemWidth * 1000;
                this.scrollLeft = 0;
                for (var i = -this.span; i < this.span + 5; i++) {
                    var index = this._normalizeIndex(i);
                    this.items.push({
                        offset: i,
                        meta: index
                    });
                    this.checkImage(index);
                }
            }
        });

        var update = function () {
            var width = $(window).width();
            var items = Math.floor(width / 306),
                itemWidth = 306;

            if (width < 732) {
                items = 3;
                itemWidth = Math.floor(width / 3);
            }

            if (width < 480) {
                items = 2;
                itemWidth = Math.floor(width / 2);
            }

            $scope.setShowingItems(Math.max(items, 2));
            $scope.setItemWidth(itemWidth);
        };

        $(window).resize(function () {
            update();
        });

        $scope.$on('goto', function (id) {
            this.goto(id);
        });

        $scope.$watch('data', function () {
            $scope.initialize();
            update();
        });

        data.then(function (data) {
            $scope.data = data.slice(0);
            $scope.$apply();
        });
    }
);<|endoftext|>


<commit_before>var assert = require('assert');
var isArrayBuffer = require('./');

it('should return true if it is an ArrayBuffer', function () {
  assert(isArrayBuffer(new ArrayBuffer()));
});

it('should return false if it is not an ArrayBuffer', function () {
  assert(!isArrayBuffer(new Array()));
});
<commit_msg>test: refactor in ES6<commit_after>const assert = require('assert');
const isArrayBuffer = require('./');

it('should return true if it is an ArrayBuffer', () => {
  assert(isArrayBuffer(new ArrayBuffer()));
});

it('should return false if it is not an ArrayBuffer', () => {
  assert(!isArrayBuffer([]));
});
<|endoftext|>


<commit_before>'use strict'

const tapeWithoutPromise = require('tape')
const addPromiseSupport = require('tape-promise').default
const tape = addPromiseSupport(tapeWithoutPromise)
const getStream = require('get-stream').array
const isEqual = require('lodash/isEqual')
const validate = require('validate-fptf')()
const moment = require('moment-timezone')
const isURL = require('is-url-superb')
const fptiTests = require('fpti-tests')

const flix = require('.')
const pkg = require('./package.json')

const when = moment.tz('Europe/Berlin').day(11).startOf('day').add('06', 'hour').toDate() // next thursday, 06:00
const isStationThatBeginsWith = (s, beginsWith) => (s.type === 'station' && s.name.substr(0, beginsWith.length) === beginsWith)

tape('flix fpti tests', async t => {
	await t.doesNotReject(fptiTests.packageJson(pkg), 'valid package.json')
	t.doesNotThrow(() => fptiTests.packageExports(flix, ['stations.all', 'regions.all', 'journeys']), 'valid module exports')
	t.doesNotThrow(() => fptiTests.stationsAllFeatures(flix.stations.all.features, []), 'valid stations.all features')
	t.doesNotThrow(() => fptiTests.regionsAllFeatures(flix.regions.all.features, []), 'valid regions.all features')
	t.doesNotThrow(() => fptiTests.journeysFeatures(flix.journeys.features, ['when', 'departureAfter', 'results', 'interval', 'transfers', 'currency']), 'valid journeys features')
	t.end()
})

tape('flix.stations.all', async t => {
	const stations = await getStream(flix.stations.all())

	// base-check all stations
	t.ok(stations.length > 30, 'number of stations')
	for (const station of stations) t.doesNotThrow(() => validate(station), 'valid fptf')

	// deep-check berlin station
	const berlin = stations.filter((x) => x.id === '1')[0]
	t.ok(berlin.id === '1', 'berlin id')
	t.ok(berlin.name === 'Berlin central bus station', 'berlin name')
	t.ok(berlin.location.street === 'Masurenallee 4-6', 'berlin street')
	t.ok(berlin.location.zip === '14057', 'berlin zip')
	t.ok(berlin.location.address === 'Masurenallee 4-6, 14057 Berlin, Germany', 'berlin address')
	t.ok(isEqual(berlin.location.country, { name: 'Germany', code: 'DE' }), 'berlin country')
	t.ok(berlin.aliases.length >= 0, 'berlin aliases')
	t.ok(isEqual(berlin.regions, ['88']), 'berlin regions')
	t.ok(berlin.connections.length > 20, 'berlin connections')
	t.ok(berlin.slug === 'berlin-zob', 'berlin slug')

	t.end()
})

tape('flix.regions.all', async t => {
	const regions = await getStream(flix.regions.all())

	// base-check all regions
	t.ok(regions.length > 30, 'number of regions')
	// @todo fptf validation is disabled until a validate-fptf bug is fixed
	//  that only allows objects in region.stations, but no ids
	// for (let region of regions) t.doesNotThrow(() => validate(region), 'valid fptf')

	// deep-check berlin region
	const berlin = regions.filter((x) => x.id === '88')[0]
	t.ok(berlin.id === '88', 'berlin id')
	t.ok(berlin.name === 'Berlin', 'berlin name')
	t.ok(isEqual(berlin.location.country, { name: 'Germany', code: 'DE' }), 'berlin country')
	t.ok(berlin.class === 'A', 'berlin class')
	t.ok(berlin.stations.length > 4, 'berlin stations')
	t.ok(berlin.connections.length > 20, 'berlin connections')
	t.ok(berlin.slug === 'berlin', 'berlin slug')

	t.end()
})

tape('flix.journeys between stations', async t => {
	const hamburg = { type: 'station', id: '36' }
	const hannover = '64'

	const journeys = await flix.journeys(hamburg, hannover, { when })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		t.ok(isStationThatBeginsWith(journey.legs[0].origin, 'Hamburg'), 'origin')
		t.ok(isStationThatBeginsWith(journey.legs[journey.legs.length - 1].destination, 'Hanover'), 'destination')
		t.ok(+new Date(journey.legs[0].departure) >= +when, 'departure')
		t.ok(journey.price.amount > 0, 'price amount')
		t.ok(journey.price.currency === 'EUR', 'price currency')
		t.ok(isURL(journey.price.url), 'price url')
	}
})

tape('flix.journeys between regions', async t => {
	const hamburg = { type: 'region', id: '118' }
	const hannover = { type: 'region', id: '146' }

	const journeys = await flix.journeys(hamburg, hannover, { when })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		t.ok(isStationThatBeginsWith(journey.legs[0].origin, 'Hamburg'), 'origin')
		t.ok(isStationThatBeginsWith(journey.legs[journey.legs.length - 1].destination, 'Hanover'), 'destination')
		t.ok(+new Date(journey.legs[0].departure) >= +when, 'departure')
		t.ok(journey.price.amount > 0, 'price amount')
		t.ok(journey.price.currency === 'EUR', 'price currency')
		t.ok(isURL(journey.price.url), 'price url')
	}
})

tape('flix.journeys bus only, opt.currency', async t => {
	const berlin = { id: '88', type: 'region' }
	const szczecin = { id: '2125', type: 'region' }

	const journeys = await flix.journeys(berlin, szczecin, { when, currency: 'PLN' })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		for (const leg of journey.legs) {
			t.ok(leg.mode === 'bus', 'leg mode')
			t.ok(['mfb', 'flix', 'flixpl', 'interglo'].includes(leg.operator.id), 'leg operator id')
		}
		t.ok(journey.price.amount > 0, 'price amount')
		t.ok(journey.price.currency === 'PLN', 'price currency')
	}
})

tape('flix.journeys train only, opt.departureAfter', async t => {
	const berlin = { id: '88', type: 'region' }
	const stuttgart = { id: '101', type: 'region' }

	const journeys = await flix.journeys(berlin, stuttgart, { departureAfter: when })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		t.ok(+new Date(journey.legs[0].departure) >= +when, 'departure')
	}

	// journey without transfers, starting at Berlin-Lichtenberg
	const journey = journeys.find(x => x.legs.length === 1 && x.legs[0].origin.id === '20718')
	t.ok(!!journey, 'journey')
	for (const leg of journey.legs) {
		t.ok(leg.mode === 'train', 'leg mode')
		t.ok(['train'].includes(leg.operator.id), 'leg operator id')
	}
})

tape('flix.journeys opt.results', async t => {
	const berlin = { id: '88', type: 'region' }
	const stuttgart = { id: '101', type: 'region' }

	const journeys = await flix.journeys(berlin, stuttgart, { when, results: 2 })
	t.ok(journeys.length === 2, 'number of journeys')
})

tape('flix.journeys opt.transfers', async t => {
	const berlin = { id: '88', type: 'region' }
	const rome = { id: '2075', type: 'region' }

	const journeysWithoutTransfer = await flix.journeys(berlin, rome, { when, transfers: 0 })
	t.ok(journeysWithoutTransfer.length === 0, 'number of journeys')

	const journeysWithTransfer = await flix.journeys(berlin, rome, { when, transfers: 2 })
	t.ok(journeysWithTransfer.length > 0, 'number of journeys')
	for (const journey of journeysWithTransfer) t.doesNotThrow(() => validate(journey), 'valid fptf')
})

tape('flix.journeys opt.interval', async t => {
	const berlin = '1'
	const strasbourg = '23'

	const journeysWithoutInterval = await flix.journeys(berlin, strasbourg, { when, transfers: 0 })
	t.ok(journeysWithoutInterval.length === 1, 'number of journeys')
	for (const journey of journeysWithoutInterval) t.doesNotThrow(() => validate(journey), 'valid fptf')

	const journeysWithInterval = await flix.journeys(berlin, strasbourg, { when, transfers: 0, interval: 3 * 24 * 60 })
	t.ok(journeysWithInterval.length === 3, 'number of journeys')
	for (const journey of journeysWithInterval) t.doesNotThrow(() => validate(journey), 'valid fptf')
})
<commit_msg>fix tests<commit_after>'use strict'

const tapeWithoutPromise = require('tape')
const addPromiseSupport = require('tape-promise').default
const tape = addPromiseSupport(tapeWithoutPromise)
const getStream = require('get-stream').array
const isEqual = require('lodash/isEqual')
const validate = require('validate-fptf')()
const moment = require('moment-timezone')
const isURL = require('is-url-superb')
const fptiTests = require('fpti-tests')

const flix = require('.')
const pkg = require('./package.json')

const when = moment.tz('Europe/Berlin').day(11).startOf('day').add('06', 'hour').toDate() // next thursday, 06:00
const isStationThatBeginsWith = (s, beginsWith) => (s.type === 'station' && s.name.substr(0, beginsWith.length) === beginsWith)

tape('flix fpti tests', async t => {
	await t.doesNotReject(fptiTests.packageJson(pkg), 'valid package.json')
	t.doesNotThrow(() => fptiTests.packageExports(flix, ['stations.all', 'regions.all', 'journeys']), 'valid module exports')
	t.doesNotThrow(() => fptiTests.stationsAllFeatures(flix.stations.all.features, []), 'valid stations.all features')
	t.doesNotThrow(() => fptiTests.regionsAllFeatures(flix.regions.all.features, []), 'valid regions.all features')
	t.doesNotThrow(() => fptiTests.journeysFeatures(flix.journeys.features, ['when', 'departureAfter', 'results', 'interval', 'transfers', 'currency']), 'valid journeys features')
	t.end()
})

tape('flix.stations.all', async t => {
	const stations = await getStream(flix.stations.all())

	// base-check all stations
	t.ok(stations.length > 30, 'number of stations')
	for (const station of stations) t.doesNotThrow(() => validate(station), 'valid fptf')

	// deep-check berlin station
	const berlin = stations.filter((x) => x.id === '1')[0]
	t.ok(berlin.id === '1', 'berlin id')
	t.ok(berlin.name === 'Berlin central bus station', 'berlin name')
	t.ok(berlin.location.street === 'Masurenallee 4-6', 'berlin street')
	t.ok(berlin.location.zip === '14057', 'berlin zip')
	t.ok(berlin.location.address === 'Masurenallee 4-6, 14057 Berlin, Germany', 'berlin address')
	t.ok(isEqual(berlin.location.country, { name: 'Germany', code: 'DE' }), 'berlin country')
	t.ok(berlin.aliases.length >= 0, 'berlin aliases')
	t.ok(isEqual(berlin.regions, ['88']), 'berlin regions')
	t.ok(berlin.connections.length > 20, 'berlin connections')
	t.ok(berlin.slug === 'berlin-zob', 'berlin slug')

	t.end()
})

tape('flix.regions.all', async t => {
	const regions = await getStream(flix.regions.all())

	// base-check all regions
	t.ok(regions.length > 30, 'number of regions')
	// @todo fptf validation is disabled until a validate-fptf bug is fixed
	//  that only allows objects in region.stations, but no ids
	// for (let region of regions) t.doesNotThrow(() => validate(region), 'valid fptf')

	// deep-check berlin region
	const berlin = regions.filter((x) => x.id === '88')[0]
	t.ok(berlin.id === '88', 'berlin id')
	t.ok(berlin.name === 'Berlin', 'berlin name')
	t.ok(isEqual(berlin.location.country, { name: 'Germany', code: 'DE' }), 'berlin country')
	t.ok(berlin.class === 'A', 'berlin class')
	t.ok(berlin.stations.length > 4, 'berlin stations')
	t.ok(berlin.connections.length > 20, 'berlin connections')
	t.ok(berlin.slug === 'berlin', 'berlin slug')

	t.end()
})

tape('flix.journeys between stations', async t => {
	const hamburg = { type: 'station', id: '36' }
	const hannover = '64'

	const journeys = await flix.journeys(hamburg, hannover, { when })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		t.ok(isStationThatBeginsWith(journey.legs[0].origin, 'Hamburg'), 'origin')
		t.ok(isStationThatBeginsWith(journey.legs[journey.legs.length - 1].destination, 'Hanover'), 'destination')
		t.ok(+new Date(journey.legs[0].departure) >= +when, 'departure')
		t.ok(journey.price.amount > 0, 'price amount')
		t.ok(journey.price.currency === 'EUR', 'price currency')
		t.ok(isURL(journey.price.url), 'price url')
	}
})

tape('flix.journeys between regions', async t => {
	const hamburg = { type: 'region', id: '118' }
	const hannover = { type: 'region', id: '146' }

	const journeys = await flix.journeys(hamburg, hannover, { when })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		t.ok(isStationThatBeginsWith(journey.legs[0].origin, 'Hamburg'), 'origin')
		t.ok(isStationThatBeginsWith(journey.legs[journey.legs.length - 1].destination, 'Hanover'), 'destination')
		t.ok(+new Date(journey.legs[0].departure) >= +when, 'departure')
		t.ok(journey.price.amount > 0, 'price amount')
		t.ok(journey.price.currency === 'EUR', 'price currency')
		t.ok(isURL(journey.price.url), 'price url')
	}
})

tape('flix.journeys bus only, opt.currency', async t => {
	const berlin = { id: '88', type: 'region' }
	const szczecin = { id: '2125', type: 'region' }

	const journeys = await flix.journeys(berlin, szczecin, { when, currency: 'PLN' })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		for (const leg of journey.legs) {
			t.ok(leg.mode === 'bus', 'leg mode')
			t.ok(['mfb', 'flix', 'flixpl', 'interglo'].includes(leg.operator.id), 'leg operator id')
		}
		t.ok(journey.price.amount > 0, 'price amount')
		t.ok(journey.price.currency === 'PLN', 'price currency')
	}
})

tape('flix.journeys train only, opt.departureAfter', async t => {
	const berlin = { id: '88', type: 'region' }
	const stuttgart = { id: '101', type: 'region' }

	const journeys = await flix.journeys(berlin, stuttgart, { departureAfter: when })
	t.ok(journeys.length >= 3, 'number of journeys')
	for (const journey of journeys) {
		t.doesNotThrow(() => validate(journey), 'valid fptf')
		t.ok(+new Date(journey.legs[0].departure) >= +when, 'departure')
	}

	// journey without transfers, starting at Berlin-Zoo
	const journey = journeys.find(x => x.legs.length === 1 && x.legs[0].origin.id === '20678')
	t.ok(!!journey, 'journey')
	for (const leg of journey.legs) {
		t.ok(leg.mode === 'train', 'leg mode')
		t.ok(['train'].includes(leg.operator.id), 'leg operator id')
	}
})

tape('flix.journeys opt.results', async t => {
	const berlin = { id: '88', type: 'region' }
	const stuttgart = { id: '101', type: 'region' }

	const journeys = await flix.journeys(berlin, stuttgart, { when, results: 2 })
	t.ok(journeys.length === 2, 'number of journeys')
})

tape('flix.journeys opt.transfers', async t => {
	const berlin = { id: '88', type: 'region' }
	const rome = { id: '2075', type: 'region' }

	const journeysWithoutTransfer = await flix.journeys(berlin, rome, { when, transfers: 0 })
	t.ok(journeysWithoutTransfer.length === 0, 'number of journeys')

	const journeysWithTransfer = await flix.journeys(berlin, rome, { when, transfers: 2 })
	t.ok(journeysWithTransfer.length > 0, 'number of journeys')
	for (const journey of journeysWithTransfer) t.doesNotThrow(() => validate(journey), 'valid fptf')
})

tape('flix.journeys opt.interval', async t => {
	const berlin = '1'
	const strasbourg = '23'

	const journeysWithoutInterval = await flix.journeys(berlin, strasbourg, { when, transfers: 0 })
	t.ok(journeysWithoutInterval.length === 1, 'number of journeys')
	for (const journey of journeysWithoutInterval) t.doesNotThrow(() => validate(journey), 'valid fptf')

	const journeysWithInterval = await flix.journeys(berlin, strasbourg, { when, transfers: 0, interval: 3 * 24 * 60 })
	t.ok(journeysWithInterval.length === 3, 'number of journeys')
	for (const journey of journeysWithInterval) t.doesNotThrow(() => validate(journey), 'valid fptf')
})
<|endoftext|>


<commit_before>const mockRes = require('jest-mock-express').response
const health = require('.')
const passingCheck = () => new Promise((resolve, reject) => resolve())
const failingCheck = () => new Promise((resolve, reject) => reject())

describe('Health check', () => {
  beforeEach(() => {
    health.reset()
  })
  it('should register checks', () => {
    health.register(passingCheck)
    return expect(health.getChecks().pop()).toBe(passingCheck)
  })
  it('should resolve if all checks pass', () => {
    health.register(passingCheck)
    health.register(passingCheck)
    return expect(health.check()).resolves.toBeTruthy()
  })
  it('should reject if a check fails', () => {
    health.register(passingCheck)
    health.register(failingCheck)
    return expect(health.check()).rejects.toBeUndefined()
  })
  it('should respond to connect/express request correctly', () => {
    const passRes = new mockRes()
    const failRes = new mockRes()

    health.register(passingCheck)
    health.route(jest.fn(), passRes)
    .then(() => {
      expect(passRes.status).toHaveBeenCalledWith(200)
      expect(passRes.send).toHaveBeenCalled()
    })

    health.register(failingCheck)
    return health.route(jest.fn(), failRes)
    .then(() => {
      expect(failRes.status).toHaveBeenCalledWith(500)
      expect(failRes.send).toHaveBeenCalled()
    })
  })
})
<commit_msg>test: Added test for getChecks() method<commit_after>const mockRes = require('jest-mock-express').response
const health = require('.')
const passingCheck = () => new Promise((resolve, reject) => resolve())
const failingCheck = () => new Promise((resolve, reject) => reject())

describe('Health check', () => {
  beforeEach(() => {
    health.reset()
  })
  it('should register checks', () => {
    health.register(passingCheck)
    return expect(health.getChecks().pop()).toBe(passingCheck)
  })
  it('should resolve if all checks pass', () => {
    health.register(passingCheck)
    health.register(passingCheck)
    return expect(health.check()).resolves.toBeTruthy()
  })
  it('should reject if a check fails', () => {
    health.register(passingCheck)
    health.register(failingCheck)
    return expect(health.check()).rejects.toBeUndefined()
  })
  it('should respond to connect/express request correctly', () => {
    const passRes = new mockRes()
    const failRes = new mockRes()

    health.register(passingCheck)
    health.route(jest.fn(), passRes)
    .then(() => {
      expect(passRes.status).toHaveBeenCalledWith(200)
      expect(passRes.send).toHaveBeenCalled()
    })

    health.register(failingCheck)
    return health.route(jest.fn(), failRes)
    .then(() => {
      expect(failRes.status).toHaveBeenCalledWith(500)
      expect(failRes.send).toHaveBeenCalled()
    })
  })
  it('should return list of checks', () => {
    const initialCount = health.getChecks().length
    health.register(passingCheck)
    health.register(passingCheck)
    expect(health.getChecks()).toHaveLength(initialCount + 2)
  })
})
<|endoftext|>


<commit_before>'use babel'

import _ from 'underscore'
import {exec} from 'child_process'

/*
  This is a serial command runner.
*/
export default class CommandExecutor {

  constructor(options = {}) {
    this.nextCommand = this.nextCommand.bind(this)

    this.options = _.defaults(options, {
      // callback method to call with command output as it is available
      onOutput: null,
      // callback method to call when command sends to stderr
      onError: null,
      // callback method to call on command failure. returning true or options.stopOnFail will stop
      onFail: null,
      // set the currentWorking directory for command execution
      cwd: null,
      // when true, stop a first command failure, you can manually resume afterwards
      // by calling .nextCommand()
      stopOnFail: true,
      // when true, commands are not really executed
      dryRun: false,
    })
    this.commandQueue = []
    this.draining = false
  }

  /*
    commands argument is an array of shell commands to execute serially.

    Commands array can also have function members. If a command is a function
    that function is called after the command before it finishes.

    If a shell command returns an exit code !== 0, then it is considered a fail.
    If a command function returns false it is considered a fail.

    When a fail occurs and constructor option stopOnFail is true (default), then
    all commands and command functions after the fail are cleared (the queue
    is reset) and the onFail construction option is called if set.

    Example - run three commands and then call and then alert the user:
    ```coffeescript
      executor = new CommandExecutor()
      excutor.executeCommands [
        "cp somepath/somefiles someOtherPath/"
        "gzip somefile"
        (-> alert('All finished'))
      ]
    ```
  */
  executeCommands(commands) {
    if (!_.isArray(commands)) { commands = [commands] }
    this.commandQueue = this.commandQueue.concat(commands)

    if (!this.draining) {
      this.nextCommand()
    }
  }

  cancelCommands(options = {}) {
    options = _.defaults(options,
      {quiet: false})

    if (this.commandQueue == null || this.commandQueue.length <= 0) {
      return
    }

    this.commandQueue = []
    this.draining = false

    if (!options.quiet) {
      if (typeof this.options.onError === 'function') {
        this.options.onError('Canceled')
      }
      if (typeof this.options.onFail === 'function') {
        this.options.onFail(1)
      }
    }
  }

  nextCommand(options = {}) {
    options = _.defaults(options, {
      cwd: this.options.cwd,
      timeout: 10000,
    })

    if (this.commandQueue == null || this.commandQueue.length <= 0) {
      // TODO - add @options onDrained callback?
      this.draining = false
      return
    }
    this.draining = true

    const cmd = this.commandQueue.shift()
    if (_.isFunction(cmd)) {
      if (cmd(this) !== false) {
        this.nextCommand()
        return
      }
    }

    if (typeof this.options.onOutput === 'function') {
      if (this.options.dryRun) {
        this.options.onOutput('# DRY RUN: (not really running)')
      }
      // echo command prefaced by $
      this.options.onOutput(`$ ${cmd}`)
    }

    if (this.options.dryRun) {
      exec(cmd, options, (error, stdout, stderr) => {
        if ((stderr != null ? stderr.lenth : undefined) > 0) {
          this.options.onError(stderr)
        }
        if ((stdout != null ? stdout.length : undefined) > 0) {
          this.options.onOutput(stdout)
        }
        if (error) {
          if (typeof this.options.onFail === 'function') {
            this.options.onFail(error)
          }
          if (this.options.stopOnFail) {
            this.cancelCommands({quiet: true}) // we already reported the error, just flush the queue
          }
        }
        this.nextCommand()
      })
    } else {
      this.nextCommand()
    }
  }
}

// # I tried doing the above with BufferedProcess, but it was a pain to have to break up args
// #    and I would have had to make the commands passed in be broken up into cmd and each arg...
// #    Really, this how class is overly complicated because of async exec.  Why not just
// #    loop over an array and execSync until one fails.  No queue, no draining....
// # The only possible better thing is that with the child_process.spawn that buffered process
// # uses, you can get output before the command finishes

// new BufferedProcess
//   command: cmd
//   args: [args]
//   options: options
//   stdout: @options.onOutput
//   stderr: @options.onError
//   exit: (code) =>
//     if code && (@options.onFail?(code) == false || @options.stopOnFail)
//       @cancelCommands(quiet: true)  # we already reported the error, just flush the queue
//     @nextCommand()  # let continue to stop draining
<commit_msg>dryRun prop on command-executor works<commit_after>'use babel'

import _ from 'underscore'
import {exec} from 'child_process'

/*
  This is a serial command runner.
*/
export default class CommandExecutor {

  constructor(options = {}) {
    this.nextCommand = this.nextCommand.bind(this)

    this.options = _.defaults(options, {
      // callback method to call with command output as it is available
      onOutput: null,
      // callback method to call when command sends to stderr
      onError: null,
      // callback method to call on command failure. returning true or options.stopOnFail will stop
      onFail: null,
      // set the currentWorking directory for command execution
      cwd: null,
      // when true, stop a first command failure, you can manually resume afterwards
      // by calling .nextCommand()
      stopOnFail: true,
      // when true, commands are not really executed
      dryRun: false,
    })
    this.commandQueue = []
    this.draining = false
  }

  /*
    commands argument is an array of shell commands to execute serially.

    Commands array can also have function members. If a command is a function
    that function is called after the command before it finishes.

    If a shell command returns an exit code !== 0, then it is considered a fail.
    If a command function returns false it is considered a fail.

    When a fail occurs and constructor option stopOnFail is true (default), then
    all commands and command functions after the fail are cleared (the queue
    is reset) and the onFail construction option is called if set.

    Example - run three commands and then call and then alert the user:
    ```coffeescript
      executor = new CommandExecutor()
      excutor.executeCommands [
        "cp somepath/somefiles someOtherPath/"
        "gzip somefile"
        (-> alert('All finished'))
      ]
    ```
  */
  executeCommands(commands) {
    if (!_.isArray(commands)) { commands = [commands] }
    this.commandQueue = this.commandQueue.concat(commands)

    if (!this.draining) {
      this.nextCommand()
    }
  }

  cancelCommands(options = {}) {
    options = _.defaults(options,
      {quiet: false})

    if (this.commandQueue == null || this.commandQueue.length <= 0) {
      return
    }

    this.commandQueue = []
    this.draining = false

    if (!options.quiet) {
      if (typeof this.options.onError === 'function') {
        this.options.onError('Canceled')
      }
      if (typeof this.options.onFail === 'function') {
        this.options.onFail(1)
      }
    }
  }

  nextCommand(options = {}) {
    options = _.defaults(options, {
      cwd: this.options.cwd,
      timeout: 10000,
    })

    if (this.commandQueue == null || this.commandQueue.length <= 0) {
      // TODO - add @options onDrained callback?
      this.draining = false
      return
    }
    this.draining = true

    const cmd = this.commandQueue.shift()
    if (_.isFunction(cmd)) {
      if (cmd(this) !== false) {
        this.nextCommand()
        return
      }
    }

    if (typeof this.options.onOutput === 'function') {
      if (this.options.dryRun) {
        this.options.onOutput('# DRY RUN: (not really running)')
      }
      // echo command prefaced by $
      this.options.onOutput(`$ ${cmd}`)
    }

    if (!this.options.dryRun) {
      exec(cmd, options, (error, stdout, stderr) => {
        if ((stderr != null ? stderr.lenth : undefined) > 0) {
          this.options.onError(stderr)
        }
        if ((stdout != null ? stdout.length : undefined) > 0) {
          this.options.onOutput(stdout)
        }
        if (error) {
          if (typeof this.options.onFail === 'function') {
            this.options.onFail(error)
          }
          if (this.options.stopOnFail) {
            this.cancelCommands({quiet: true}) // we already reported the error, just flush the queue
          }
        }
        this.nextCommand()
      })
    } else {
      this.nextCommand()
    }
  }
}

// # I tried doing the above with BufferedProcess, but it was a pain to have to break up args
// #    and I would have had to make the commands passed in be broken up into cmd and each arg...
// #    Really, this how class is overly complicated because of async exec.  Why not just
// #    loop over an array and execSync until one fails.  No queue, no draining....
// # The only possible better thing is that with the child_process.spawn that buffered process
// # uses, you can get output before the command finishes

// new BufferedProcess
//   command: cmd
//   args: [args]
//   options: options
//   stdout: @options.onOutput
//   stderr: @options.onError
//   exit: (code) =>
//     if code && (@options.onFail?(code) == false || @options.stopOnFail)
//       @cancelCommands(quiet: true)  # we already reported the error, just flush the queue
//     @nextCommand()  # let continue to stop draining
<|endoftext|>


<commit_before>var test = require('tape');

test('compose redux reducer from fluxury stores', function(t) {

  var createStore = require('fluxury').createStore
  var createReducer = require('./lib/index').createReducer
  var createReduxStore = require('redux').createStore

  t.plan(4)

  var MessageStore = createStore('MessageStore', [], function(state, action) {
    switch(action.type) {
      case 'loadMessage':
      return state.concat(action.data)
      default:
      return state
    }
  })

  var MessageCountStore = createStore(
    'MessageCountStore',
    0,
    function(state, action, waitFor) {
      // ensure that MessageStore reducer is executed before continuing
      waitFor([MessageStore.dispatchToken])
      switch(action.type) {
        case 'loadMessage':
        return state+1
        default:
        return state
      }
    }
  )

  var reducer = createReducer(MessageStore, MessageCountStore)
  var store = createReduxStore( reducer )

  store.dispatch( { type: 'loadMessage', data: 'Test Message'} )

  t.deepEqual( store.getState(), [ [ 'Test Message' ], 1 ])

  store.dispatch( { type: 'loadMessage', data: 'Test Message 2'} )

  t.deepEqual( store.getState(), [ [ 'Test Message', 'Test Message 2' ], 2 ])

  store.dispatch( { type: 'noHandler', data: 'Test Message 2'} )

  t.deepEqual( store.getState(), [ [ 'Test Message', 'Test Message 2' ], 2 ])

  store.dispatch( { type: 'loadMessage', data: 'Test Message 3'} )

  t.deepEqual( store.getState(), [ [ 'Test Message', 'Test Message 2', 'Test Message 3' ], 3 ])

})

test('compose redux reducer from fluxury stores', function(t) {

  var createStore = require('fluxury').createStore
  var createReducer = require('./lib/index').createReducer
  var createReduxStore = require('redux').createStore

  t.plan(1)

  var MessageStore = createStore(
    'MessageStore',
    [],
    {
      loadMessage: (state, data) => state.concat(data)
    })

  var MessageCountStore = createStore(
    'MessageCountStore',
    0,
    {
      loadMessage: (state, data, waitFor) => {
        waitFor([MessageStore.dispatchToken])
        return state+1
      }
    }
  )

  var reducer = createReducer({
    messages: MessageStore,
    count: MessageCountStore
  })

  var store = createReduxStore( reducer )

  store.dispatch( { type: 'loadMessage', data: 'Test Message'} )
  t.deepEqual( store.getState(), { messages: ['Test Message'], count: 1 } )

})

test('create master store from fluxury stores', function(t) {

  // Single-store concept without Redux
  var createStore = require('fluxury').createStore
  var dispatch = require('fluxury').dispatch
  var createMasterStore = require('./lib/index').createMasterStore

  t.plan(1)

  var MessageStore = createStore(
    'MessageStore',
    [],
    {
      loadMessage: function(state, data) {
        return state.concat(data)
      }
    })

  var MessageCountStore = createStore(
    'MessageCountStore',
    0,
    {
      loadMessage: function(state, data, waitFor){
        waitFor([MessageStore.dispatchToken])
        return state+1
      }
    }
  )

  var store = createMasterStore( MessageCountStore, MessageStore )

  dispatch('loadMessage', 'Test Message' )

  t.deepEqual( store.getState(), [ 1, [ 'Test Message' ]])

})
<commit_msg>Downgrade more ES6<commit_after>var test = require('tape');

test('compose redux reducer from fluxury stores', function(t) {

  var createStore = require('fluxury').createStore
  var createReducer = require('./lib/index').createReducer
  var createReduxStore = require('redux').createStore

  t.plan(4)

  var MessageStore = createStore('MessageStore', [], function(state, action) {
    switch(action.type) {
      case 'loadMessage':
      return state.concat(action.data)
      default:
      return state
    }
  })

  var MessageCountStore = createStore(
    'MessageCountStore',
    0,
    function(state, action, waitFor) {
      // ensure that MessageStore reducer is executed before continuing
      waitFor([MessageStore.dispatchToken])
      switch(action.type) {
        case 'loadMessage':
        return state+1
        default:
        return state
      }
    }
  )

  var reducer = createReducer(MessageStore, MessageCountStore)
  var store = createReduxStore( reducer )

  store.dispatch( { type: 'loadMessage', data: 'Test Message'} )

  t.deepEqual( store.getState(), [ [ 'Test Message' ], 1 ])

  store.dispatch( { type: 'loadMessage', data: 'Test Message 2'} )

  t.deepEqual( store.getState(), [ [ 'Test Message', 'Test Message 2' ], 2 ])

  store.dispatch( { type: 'noHandler', data: 'Test Message 2'} )

  t.deepEqual( store.getState(), [ [ 'Test Message', 'Test Message 2' ], 2 ])

  store.dispatch( { type: 'loadMessage', data: 'Test Message 3'} )

  t.deepEqual( store.getState(), [ [ 'Test Message', 'Test Message 2', 'Test Message 3' ], 3 ])

})

test('compose redux reducer from fluxury stores', function(t) {

  var createStore = require('fluxury').createStore
  var createReducer = require('./lib/index').createReducer
  var createReduxStore = require('redux').createStore

  t.plan(1)

  var MessageStore = createStore(
    'MessageStore',
    [],
    {
      loadMessage: function(state, data) {
        return state.concat(data)
      }
    })

  var MessageCountStore = createStore(
    'MessageCountStore',
    0,
    {
      loadMessage: function(state, data, waitFor) {
        waitFor([MessageStore.dispatchToken])
        return state+1
      }
    }
  )

  var reducer = createReducer({
    messages: MessageStore,
    count: MessageCountStore
  })

  var store = createReduxStore( reducer )

  store.dispatch( { type: 'loadMessage', data: 'Test Message'} )
  t.deepEqual( store.getState(), { messages: ['Test Message'], count: 1 } )

})

test('create master store from fluxury stores', function(t) {

  // Single-store concept without Redux
  var createStore = require('fluxury').createStore
  var dispatch = require('fluxury').dispatch
  var createMasterStore = require('./lib/index').createMasterStore

  t.plan(1)

  var MessageStore = createStore(
    'MessageStore',
    [],
    {
      loadMessage: function(state, data) {
        return state.concat(data)
      }
    })

  var MessageCountStore = createStore(
    'MessageCountStore',
    0,
    {
      loadMessage: function(state, data, waitFor) {
        waitFor([MessageStore.dispatchToken])
        return state+1
      }
    }
  )

  var store = createMasterStore( MessageCountStore, MessageStore )

  dispatch('loadMessage', 'Test Message' )

  t.deepEqual( store.getState(), [ 1, [ 'Test Message' ]])

})
<|endoftext|>


<commit_before>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import '../../third_party/babel/custom-babel-helpers';
import '../../src/polyfills';
import {assert} from '../../src/asserts';
import {getCookie, setCookie} from '../../src/cookies';
import {isExperimentOn, toggleExperiment} from '../../src/experiments';
import {listenOnce} from '../../src/event-helper';
import {onDocumentReady} from '../../src/document-state';

const COOKIE_MAX_AGE_DAYS = 180;  // 6 month

/**
 * @typedef {{
 *   id: string,
 *   name: string,
 *   spec: string
 * }}
 */
let ExperimentDef;

/**
 * This experiment is special because it uses a different mechanism that is
 * interpreted by the server to deliver a different version of the AMP
 * JS libraries.
 */
const CANARY_EXPERIMENT_ID = 'dev-channel';

/** @const {!Array<!ExperimentDef>} */
const EXPERIMENTS = [
  // Canary (Dev Channel)
  {
    id: CANARY_EXPERIMENT_ID,
    name: 'AMP Dev Channel (more info)',
    spec: 'https://github.com/ampproject/amphtml/blob/master/' +
        'DEVELOPING.md#amp-dev-channel-experimental',
  },

  // AMP Access
  {
    id: 'amp-access',
    name: 'AMP Access',
    spec: 'https://github.com/ampproject/amphtml/blob/master/extensions/' +
        'amp-access/amp-access-spec.md',
  },

  // AMP Access Analytics
  {
    id: 'amp-access-analytics',
    name: 'AMP Access Analytics',
    spec: 'https://github.com/ampproject/amphtml/issues/1556',
  },

  // Dynamic CSS Classes
  {
    id: 'dynamic-css-classes',
    name: 'Dynamic CSS Classes',
    spec: 'https://github.com/ampproject/amphtml/blob/master/extensions/' +
        'amp-dynamic-css-classes/amp-dynamic-css-classes.md',
  },
];

/**
 * Builds the expriments tbale.
 */
function build() {
  const table = document.getElementById('experiments-table');
  EXPERIMENTS.forEach(function(experiment) {
    table.appendChild(buildExperimentRow(experiment));
  });
}

/**
 * Builds one row of the experiments table.
 * @param {!ExperimentDef} experiment
 */
function buildExperimentRow(experiment) {
  const tr = document.createElement('tr');
  tr.id = 'exp-tr-' + experiment.id;

  const tdId = document.createElement('td');
  tdId.appendChild(buildLinkMaybe(experiment.id, experiment.spec));
  tr.appendChild(tdId);

  const tdName = document.createElement('td');
  tdName.appendChild(buildLinkMaybe(experiment.name, experiment.spec));
  tr.appendChild(tdName);

  const tdOn = document.createElement('td');
  tdOn.classList.add('button-cell');
  tr.appendChild(tdOn);

  const button = document.createElement('button');
  tdOn.appendChild(button);

  const buttonOn = document.createElement('div');
  buttonOn.classList.add('on');
  buttonOn.textContent = 'On';
  button.appendChild(buttonOn);

  const buttonOff = document.createElement('div');
  buttonOff.classList.add('off');
  buttonOff.textContent = 'Off';
  button.appendChild(buttonOff);

  button.addEventListener('click', toggleExperiment_.bind(null, experiment.id,
      experiment.name, undefined));

  return tr;
}

/**
 * If link is available, builds the anchor. Otherwise, it'd return a basic span.
 * @param {string} text
 * @param {?string} link
 * @return {!Element}
 */
function buildLinkMaybe(text, link) {
  let element;
  if (link) {
    element = document.createElement('a');
    element.setAttribute('href', link);
    element.setAttribute('target', '_blank');
  } else {
    element = document.createElement('span');
  }
  element.textContent = text;
  return element;
}

/**
 * Updates states of all experiments in the table.
 */
function update() {
  EXPERIMENTS.forEach(function(experiment) {
    updateExperimentRow(experiment);
  });
}

/**
 * Updates the state of a single experiment.
 * @param {!ExperimentDef} experiment
 */
function updateExperimentRow(experiment) {
  const tr = document.getElementById('exp-tr-' + experiment.id);
  if (!tr) {
    return;
  }
  tr.setAttribute('data-on', isExperimentOn_(experiment.id) ? 1 : 0);
}

/**
 * Returns whether the experiment is on or off.
 * @param {string} id
 * @return {boolean}
 */
function isExperimentOn_(id) {
  if (id == CANARY_EXPERIMENT_ID) {
    return getCookie(window, 'AMP_CANARY') == '1';
  }
  return isExperimentOn(window, id);
}

/**
 * Toggles the experiment.
 * @param {string} id
 * @param {boolean=} opt_on
 */
function toggleExperiment_(id, name, opt_on) {
  const currentlyOn = isExperimentOn_(id);
  const on = opt_on === undefined ? !currentlyOn : opt_on;
  // Protect against click jacking.
  const confirmMessage = on ?
      'Do you really want to activate the AMP experiment' :
      'Do you really want to deactivate the AMP experiment';

  showConfirmation_(`${confirmMessage}: "${name}"`, () => {
    if (id == CANARY_EXPERIMENT_ID) {
      const validUntil = new Date().getTime() +
          COOKIE_MAX_AGE_DAYS * 24 * 60 * 60 * 1000;
      setCookie(window, 'AMP_CANARY', (on ? '1' : '0'), (on ? validUntil : 0));
    } else {
      toggleExperiment(window, id, on);
    }
    update();
  });
}

/**
 * Shows confirmation and calls callback if it's approved.
 * @param {string} message
 * @param {function()} callback
 */
function showConfirmation_(message, callback) {
  const container = assert(document.getElementById('popup-container'));
  const messageElement = assert(document.getElementById('popup-message'));
  const confirmButton = assert(document.getElementById('popup-button-ok'));
  const cancelButton = assert(document.getElementById('popup-button-cancel'));
  const unlistenSet = [];
  const closePopup = affirmative => {
    container.classList.remove('show');
    unlistenSet.forEach(unlisten => unlisten());
    if (affirmative) {
      callback();
    }
  };

  messageElement.textContent = message;
  unlistenSet.push(listenOnce(confirmButton, 'click',
      () => closePopup(true)));
  unlistenSet.push(listenOnce(cancelButton, 'click',
      () => closePopup(false)));
  container.classList.add('show');
}

// Start up.
onDocumentReady(document, () => {
  build();
  update();
});
<commit_msg>amp-access experiment removed<commit_after>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import '../../third_party/babel/custom-babel-helpers';
import '../../src/polyfills';
import {assert} from '../../src/asserts';
import {getCookie, setCookie} from '../../src/cookies';
import {isExperimentOn, toggleExperiment} from '../../src/experiments';
import {listenOnce} from '../../src/event-helper';
import {onDocumentReady} from '../../src/document-state';

const COOKIE_MAX_AGE_DAYS = 180;  // 6 month

/**
 * @typedef {{
 *   id: string,
 *   name: string,
 *   spec: string
 * }}
 */
let ExperimentDef;

/**
 * This experiment is special because it uses a different mechanism that is
 * interpreted by the server to deliver a different version of the AMP
 * JS libraries.
 */
const CANARY_EXPERIMENT_ID = 'dev-channel';

/** @const {!Array<!ExperimentDef>} */
const EXPERIMENTS = [
  // Canary (Dev Channel)
  {
    id: CANARY_EXPERIMENT_ID,
    name: 'AMP Dev Channel (more info)',
    spec: 'https://github.com/ampproject/amphtml/blob/master/' +
        'DEVELOPING.md#amp-dev-channel-experimental',
  },

  // AMP Access Analytics
  {
    id: 'amp-access-analytics',
    name: 'AMP Access Analytics',
    spec: 'https://github.com/ampproject/amphtml/issues/1556',
  },

  // Dynamic CSS Classes
  {
    id: 'dynamic-css-classes',
    name: 'Dynamic CSS Classes',
    spec: 'https://github.com/ampproject/amphtml/blob/master/extensions/' +
        'amp-dynamic-css-classes/amp-dynamic-css-classes.md',
  },
];

/**
 * Builds the expriments tbale.
 */
function build() {
  const table = document.getElementById('experiments-table');
  EXPERIMENTS.forEach(function(experiment) {
    table.appendChild(buildExperimentRow(experiment));
  });
}

/**
 * Builds one row of the experiments table.
 * @param {!ExperimentDef} experiment
 */
function buildExperimentRow(experiment) {
  const tr = document.createElement('tr');
  tr.id = 'exp-tr-' + experiment.id;

  const tdId = document.createElement('td');
  tdId.appendChild(buildLinkMaybe(experiment.id, experiment.spec));
  tr.appendChild(tdId);

  const tdName = document.createElement('td');
  tdName.appendChild(buildLinkMaybe(experiment.name, experiment.spec));
  tr.appendChild(tdName);

  const tdOn = document.createElement('td');
  tdOn.classList.add('button-cell');
  tr.appendChild(tdOn);

  const button = document.createElement('button');
  tdOn.appendChild(button);

  const buttonOn = document.createElement('div');
  buttonOn.classList.add('on');
  buttonOn.textContent = 'On';
  button.appendChild(buttonOn);

  const buttonOff = document.createElement('div');
  buttonOff.classList.add('off');
  buttonOff.textContent = 'Off';
  button.appendChild(buttonOff);

  button.addEventListener('click', toggleExperiment_.bind(null, experiment.id,
      experiment.name, undefined));

  return tr;
}

/**
 * If link is available, builds the anchor. Otherwise, it'd return a basic span.
 * @param {string} text
 * @param {?string} link
 * @return {!Element}
 */
function buildLinkMaybe(text, link) {
  let element;
  if (link) {
    element = document.createElement('a');
    element.setAttribute('href', link);
    element.setAttribute('target', '_blank');
  } else {
    element = document.createElement('span');
  }
  element.textContent = text;
  return element;
}

/**
 * Updates states of all experiments in the table.
 */
function update() {
  EXPERIMENTS.forEach(function(experiment) {
    updateExperimentRow(experiment);
  });
}

/**
 * Updates the state of a single experiment.
 * @param {!ExperimentDef} experiment
 */
function updateExperimentRow(experiment) {
  const tr = document.getElementById('exp-tr-' + experiment.id);
  if (!tr) {
    return;
  }
  tr.setAttribute('data-on', isExperimentOn_(experiment.id) ? 1 : 0);
}

/**
 * Returns whether the experiment is on or off.
 * @param {string} id
 * @return {boolean}
 */
function isExperimentOn_(id) {
  if (id == CANARY_EXPERIMENT_ID) {
    return getCookie(window, 'AMP_CANARY') == '1';
  }
  return isExperimentOn(window, id);
}

/**
 * Toggles the experiment.
 * @param {string} id
 * @param {boolean=} opt_on
 */
function toggleExperiment_(id, name, opt_on) {
  const currentlyOn = isExperimentOn_(id);
  const on = opt_on === undefined ? !currentlyOn : opt_on;
  // Protect against click jacking.
  const confirmMessage = on ?
      'Do you really want to activate the AMP experiment' :
      'Do you really want to deactivate the AMP experiment';

  showConfirmation_(`${confirmMessage}: "${name}"`, () => {
    if (id == CANARY_EXPERIMENT_ID) {
      const validUntil = new Date().getTime() +
          COOKIE_MAX_AGE_DAYS * 24 * 60 * 60 * 1000;
      setCookie(window, 'AMP_CANARY', (on ? '1' : '0'), (on ? validUntil : 0));
    } else {
      toggleExperiment(window, id, on);
    }
    update();
  });
}

/**
 * Shows confirmation and calls callback if it's approved.
 * @param {string} message
 * @param {function()} callback
 */
function showConfirmation_(message, callback) {
  const container = assert(document.getElementById('popup-container'));
  const messageElement = assert(document.getElementById('popup-message'));
  const confirmButton = assert(document.getElementById('popup-button-ok'));
  const cancelButton = assert(document.getElementById('popup-button-cancel'));
  const unlistenSet = [];
  const closePopup = affirmative => {
    container.classList.remove('show');
    unlistenSet.forEach(unlisten => unlisten());
    if (affirmative) {
      callback();
    }
  };

  messageElement.textContent = message;
  unlistenSet.push(listenOnce(confirmButton, 'click',
      () => closePopup(true)));
  unlistenSet.push(listenOnce(cancelButton, 'click',
      () => closePopup(false)));
  container.classList.add('show');
}

// Start up.
onDocumentReady(document, () => {
  build();
  update();
});
<|endoftext|>


<commit_before>'use strict'

const assert = require('assert')
const tasks  = require('./index.js')

describe('test taskling', function() {

  it('should complete by calling done()', function(done) {
    tasks({}, [], done)
  })

  it('should run a function', function(done) {
    let ran = false

    tasks({}, [
      function(next) {
        ran = true
        next()
      }
    ], function() {
      assert.equal(ran, true, 'should run function')
      done()
    })
  })

  it('should run functions', function(done) {
    let ran = 0

    tasks({}, [
      function(next) {
        ran++
        next()
      },

      function(next) {
        ran++
        next()
      },

      function(next) {
        ran++
        next()
      },
    ], function() {
      assert.equal(ran, 3, 'should run 3 functions')
      done()
    })
  })

  it('should provide same shared object to functions', function(done) {
    const object = {
      first: false,
      second: false,
      third: false
    }

    tasks(object, [
      function(next, context) {
        context.first = true
        next()
      },

      function(next, context) {
        context.second = true
        next()
      },

      function(next, context) {
        context.third = true
        next()
      },
    ], function() {
      assert.equal(object.first, true)
      assert.equal(object.second, true)
      assert.equal(object.third, true)
      done()
    })
  })

  it('should start later', function(done) {
    let started = false

    tasks({}, [
      function(next) {
        started = true
        next()
      }
    ], done)

    assert.equal(started, false, 'should start async run later')
  })

  it('should stop execution and give error to done()', function(done) {
    let ran = 0

    tasks({}, [
      function(next) {
        ran++
        next('error')
      },

      function(next) {
        ran++
        next()
      },
    ], function(error, result) {
      assert.equal(error, 'error')
      assert.equal(result, null)
      assert.equal(ran, 1, 'should only run first function')
      done()
    })
  })

  it('should prepend functions', function(done) {
    let ran = 0
    let soFar = null

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.prepend([
          fn, fn, fn
        ])
        next()
      },

      function last(next) {
        soFar = ran
        next()
      }
    ], function() {
      assert.equal(ran, 3, 'should run `fn` function 3 times')
      assert.equal(soFar, 3, 'should run `last` after prepended functions')
      done()
    })
  })

  it('should append functions', function(done) {
    let ran = 0
    let soFar = null

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.append([
          fn, fn, fn
        ])
        next()
      },

      function second(next) {
        soFar = ran
        next()
      }
    ], function() {
      assert.equal(ran, 3, 'should run `fn` function 3 times')
      assert.equal(soFar, 0, 'should run `second` before appended functions')
      done()
    })
  })

  it('should clear remaining functions', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.clear()
        next()
      },

      fn,
      fn,
      fn,
    ], function() {
      assert.equal(ran, 0, 'should clear functions')
      done()
    })
  })

  it('should flatten array provided to prepend()', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.prepend(
          [
            [
              fn,
              [fn],
              fn,
            ]
          ]
        )
        next()
      },
    ], function() {
      assert.equal(ran, 3, 'should call all three prepended functions')
      done()
    })
  })

  it('should flatten array provided to append()', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.append(
          [
            [
              fn,
              [fn],
              fn,
            ]
          ]
        )
        next()
      },
    ], function() {
      assert.equal(ran, 3, 'should call all three appended functions')
      done()
    })
  })

  it('should use setImmediate', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      fn,
      fn,
      fn,
    ], function() {
      assert.equal(ran, 3, 'should call function three times')
      done()
    }, setImmediate)
  })

  it('should use custom executor', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    function executor(fn) {
      setTimeout(fn, 100)
    }

    tasks({}, [
      fn,
      fn,
      fn,
    ], function() {
      assert.equal(ran, 3, 'should call function three times')
      done()
    }, executor)
  })

})
<commit_msg>add depth/complexity to the prepend/append arrays<commit_after>'use strict'

const assert = require('assert')
const tasks  = require('./index.js')

describe('test taskling', function() {

  it('should complete by calling done()', function(done) {
    tasks({}, [], done)
  })

  it('should run a function', function(done) {
    let ran = false

    tasks({}, [
      function(next) {
        ran = true
        next()
      }
    ], function() {
      assert.equal(ran, true, 'should run function')
      done()
    })
  })

  it('should run functions', function(done) {
    let ran = 0

    tasks({}, [
      function(next) {
        ran++
        next()
      },

      function(next) {
        ran++
        next()
      },

      function(next) {
        ran++
        next()
      },
    ], function() {
      assert.equal(ran, 3, 'should run 3 functions')
      done()
    })
  })

  it('should provide same shared object to functions', function(done) {
    const object = {
      first: false,
      second: false,
      third: false
    }

    tasks(object, [
      function(next, context) {
        context.first = true
        next()
      },

      function(next, context) {
        context.second = true
        next()
      },

      function(next, context) {
        context.third = true
        next()
      },
    ], function() {
      assert.equal(object.first, true)
      assert.equal(object.second, true)
      assert.equal(object.third, true)
      done()
    })
  })

  it('should start later', function(done) {
    let started = false

    tasks({}, [
      function(next) {
        started = true
        next()
      }
    ], done)

    assert.equal(started, false, 'should start async run later')
  })

  it('should stop execution and give error to done()', function(done) {
    let ran = 0

    tasks({}, [
      function(next) {
        ran++
        next('error')
      },

      function(next) {
        ran++
        next()
      },
    ], function(error, result) {
      assert.equal(error, 'error')
      assert.equal(result, null)
      assert.equal(ran, 1, 'should only run first function')
      done()
    })
  })

  it('should prepend functions', function(done) {
    let ran = 0
    let soFar = null

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.prepend([
          fn, fn, fn
        ])
        next()
      },

      function last(next) {
        soFar = ran
        next()
      }
    ], function() {
      assert.equal(ran, 3, 'should run `fn` function 3 times')
      assert.equal(soFar, 3, 'should run `last` after prepended functions')
      done()
    })
  })

  it('should append functions', function(done) {
    let ran = 0
    let soFar = null

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.append([
          fn, fn, fn
        ])
        next()
      },

      function second(next) {
        soFar = ran
        next()
      }
    ], function() {
      assert.equal(ran, 3, 'should run `fn` function 3 times')
      assert.equal(soFar, 0, 'should run `second` before appended functions')
      done()
    })
  })

  it('should clear remaining functions', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.clear()
        next()
      },

      fn,
      fn,
      fn,
    ], function() {
      assert.equal(ran, 0, 'should clear functions')
      done()
    })
  })

  it('should flatten array provided to prepend()', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.prepend(
          [
            fn,
            [
              fn,
              [fn, fn],
              fn,
            ],
            fn,
            fn
          ]
        )
        next()
      },
    ], function() {
      assert.equal(ran, 7, 'should call all three prepended functions')
      done()
    })
  })

  it('should flatten array provided to append()', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      function(next) {
        this.append(
          [
            fn,
            [
              fn,
              [fn, fn],
              fn,
            ],
            fn,
            fn
          ]
        )
        next()
      },
    ], function() {
      assert.equal(ran, 7, 'should call all three appended functions')
      done()
    })
  })

  it('should use setImmediate', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    tasks({}, [
      fn,
      fn,
      fn,
    ], function() {
      assert.equal(ran, 3, 'should call function three times')
      done()
    }, setImmediate)
  })

  it('should use custom executor', function(done) {
    let ran = 0

    function fn(next) { ran++ ; next() }

    function executor(fn) {
      setTimeout(fn, 100)
    }

    tasks({}, [
      fn,
      fn,
      fn,
    ], function() {
      assert.equal(ran, 3, 'should call function three times')
      done()
    }, executor)
  })

})
<|endoftext|>