<commit_before>let Vue = require("vuejs");
let ApplicationListModel = require("user/ApplicationListModel");
let ApplicationView = require("user/vue-components/ApplicationView");
require("filters");

let model, appView;

QUnit.module("user.app_view", {
  beforeEach: function(assert) {
    let done = assert.async();

    model = new ApplicationListModel();
    appView = new ApplicationView({
      data: function() { return { model: model }; }
    }).$mount();

    model.update().done(function() {
      Vue.nextTick(function() {done();});
    });
  }
});

QUnit.test("rendering title and description", function (assert) {
  let done = assert.async();
  assert.equal(appView.$el.children[0].tagName, 'DIV');
  assert.ok(appView.$el.children[0].classList.contains('row'));

  assert.equal(
    appView.$el.querySelector('.box-title').innerHTML,
    model.appList[0].appData.image.ui_name
  );

  assert.equal(
    appView.$el.querySelector('#app-description').innerHTML,
    model.appList[0].appData.image.description
  );

  // Select other application
  model.selectedIndex = 2;

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.box-title').innerHTML,
      model.appList[2].appData.image.ui_name
    );

    assert.equal(
      appView.$el.querySelector('#app-description').innerHTML,
      model.appList[2].appData.image.description
    );

    done();
  });
});

QUnit.test("rendering policy", function (assert) {
  let done = assert.async();

  assert.equal(
    appView.$el.querySelector('.policy').children[0].innerHTML.trim(),
    'Workspace accessible'
  );

  assert.equal(
    appView.$el.querySelector('.policy').children[1].innerHTML.trim(),
    'No volumes mounted'
  );

  // Select other application
  model.selectedIndex = 2;

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.policy').children[0].innerHTML.trim(),
      'Workspace not accessible'
    );

    assert.notEqual(
      appView.$el.querySelector('.policy').children[1].innerHTML.indexOf('Volume mounted: foo'),
      -1
    );

    assert.notEqual(
      appView.$el.querySelector('.policy').children[1].innerHTML.indexOf(' bar (baz)'),
      -1
    );

    done();
  });
});

QUnit.test("rendering configurables", function (assert) {
  let done = assert.async();

  assert.notEqual(
    appView.$el.querySelector('.configuration').children[0].innerHTML.trim(),
    'No configurable options for this image'
  );

  // Select other application
  model.selectedIndex = 2;

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.configuration').children[0].innerHTML.trim(),
      'No configurable options for this image'
    );

    done();
  });
});

QUnit.test("rendering start button", function (assert) {
  let done = assert.async();

  assert.equal(
    appView.$el.querySelector('.start-button').innerHTML.trim(),
    'Start'
  );

  assert.notOk(
    appView.$el.querySelector('.start-button').disabled
  );

  assert.notOk(
    appView.$el.querySelector('.configuration > fieldset').disabled
  );

  // Simulate application starting
  model.appList[0].status = 'STARTING';

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.start-button').innerHTML.trim(),
      'Starting'
    );

    assert.ok(
      appView.$el.querySelector('.start-button').disabled
    );

    // Simulate application stopping
    model.appList[0].status = 'STOPPING';

    Vue.nextTick(function() {
      assert.equal(
        appView.$el.querySelector('.start-button').innerHTML.trim(),
        'Stopping'
      );

      assert.ok(
        appView.$el.querySelector('.start-button').disabled
      );

      done();
    });
  });
});

QUnit.test("rendering iframe", function (assert) {
  let done = assert.async();
  // Switch to a running application
  model.selectedIndex = 1;

  Vue.nextTick(function() {
    assert.equal(appView.$el.children[0].tagName, 'IFRAME');
    assert.equal(appView.$el.children[0].getAttribute('src'), '/user/lambda/containers/654321/');

    // Render form again by selecting the other application which is stopped
    model.selectedIndex = 0;

    Vue.nextTick(function() {
      assert.equal(
        appView.$el.querySelector('.box-title').innerHTML,
        model.appList[0].appData.image.ui_name
      );

      done();
    });
  });
});
<commit_msg>Add test for the start application method<commit_after>let $ = require("jquery");
let Vue = require("vuejs");
let ApplicationListModel = require("user/ApplicationListModel");
let ApplicationView = require("user/vue-components/ApplicationView");
require("filters");

let model, appView;

QUnit.module("user.app_view", {
  beforeEach: function(assert) {
    let done = assert.async();

    model = new ApplicationListModel();
    appView = new ApplicationView({
      data: function() { return { model: model }; }
    }).$mount();

    model.update().done(function() {
      Vue.nextTick(function() {done();});
    });
  }
});

QUnit.test("rendering title and description", function (assert) {
  let done = assert.async();
  assert.equal(appView.$el.children[0].tagName, 'DIV');
  assert.ok(appView.$el.children[0].classList.contains('row'));

  assert.equal(
    appView.$el.querySelector('.box-title').innerHTML,
    model.appList[0].appData.image.ui_name
  );

  assert.equal(
    appView.$el.querySelector('#app-description').innerHTML,
    model.appList[0].appData.image.description
  );

  // Select other application
  model.selectedIndex = 2;

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.box-title').innerHTML,
      model.appList[2].appData.image.ui_name
    );

    assert.equal(
      appView.$el.querySelector('#app-description').innerHTML,
      model.appList[2].appData.image.description
    );

    done();
  });
});

QUnit.test("rendering policy", function (assert) {
  let done = assert.async();

  assert.equal(
    appView.$el.querySelector('.policy').children[0].innerHTML.trim(),
    'Workspace accessible'
  );

  assert.equal(
    appView.$el.querySelector('.policy').children[1].innerHTML.trim(),
    'No volumes mounted'
  );

  // Select other application
  model.selectedIndex = 2;

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.policy').children[0].innerHTML.trim(),
      'Workspace not accessible'
    );

    assert.notEqual(
      appView.$el.querySelector('.policy').children[1].innerHTML.indexOf('Volume mounted: foo'),
      -1
    );

    assert.notEqual(
      appView.$el.querySelector('.policy').children[1].innerHTML.indexOf(' bar (baz)'),
      -1
    );

    done();
  });
});

QUnit.test("rendering configurables", function (assert) {
  let done = assert.async();

  assert.notEqual(
    appView.$el.querySelector('.configuration').children[0].innerHTML.trim(),
    'No configurable options for this image'
  );

  // Select other application
  model.selectedIndex = 2;

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.configuration').children[0].innerHTML.trim(),
      'No configurable options for this image'
    );

    done();
  });
});

QUnit.test("rendering start button", function (assert) {
  let done = assert.async();

  assert.equal(
    appView.$el.querySelector('.start-button').innerHTML.trim(),
    'Start'
  );

  assert.notOk(
    appView.$el.querySelector('.start-button').disabled
  );

  assert.notOk(
    appView.$el.querySelector('.configuration > fieldset').disabled
  );

  // Simulate application starting
  model.appList[0].status = 'STARTING';

  Vue.nextTick(function() {
    assert.equal(
      appView.$el.querySelector('.start-button').innerHTML.trim(),
      'Starting'
    );

    assert.ok(
      appView.$el.querySelector('.start-button').disabled
    );

    // Simulate application stopping
    model.appList[0].status = 'STOPPING';

    Vue.nextTick(function() {
      assert.equal(
        appView.$el.querySelector('.start-button').innerHTML.trim(),
        'Stopping'
      );

      assert.ok(
        appView.$el.querySelector('.start-button').disabled
      );

      done();
    });
  });
});

QUnit.test("start method", function (assert) {
  let done = assert.async();

  let startCalled = false;
  // Mock model.startApplication
  model.startApplication = function() {
    let startPromise = $.Deferred();
    startCalled = true;
    return startPromise.resolve();
  };

  // Select stopped application
  model.selectedIndex = 0;

  Vue.nextTick(function() {
    // model.startApplication should be called
    appView.startApplication().then(function() {
      assert.ok(startCalled);

      // Select running application
      model.selectedIndex = 1;
      startCalled = false;

      Vue.nextTick(function() {
        // model.startApplication shouldn't be called
        appView.startApplication().then(function() {
          assert.notOk(startCalled);
          done();
        });
      });
    });
  });
});

QUnit.test("rendering iframe", function (assert) {
  let done = assert.async();
  // Switch to a running application
  model.selectedIndex = 1;

  Vue.nextTick(function() {
    assert.equal(appView.$el.children[0].tagName, 'IFRAME');
    assert.equal(appView.$el.children[0].getAttribute('src'), '/user/lambda/containers/654321/');

    // Render form again by selecting the other application which is stopped
    model.selectedIndex = 0;

    Vue.nextTick(function() {
      assert.equal(
        appView.$el.querySelector('.box-title').innerHTML,
        model.appList[0].appData.image.ui_name
      );

      done();
    });
  });
});
<|endoftext|>


<commit_before>/**
 * Copyright IBM Corp. 2016, 2018
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import PropTypes from 'prop-types';
import React from 'react';
import RadioTile from '../RadioTile';
import warning from 'warning';
import { settings } from 'carbon-components';

const { prefix } = settings;

export default class TileGroup extends React.Component {
  state = {
    selected: this.props.valueSelected || this.props.defaultSelected || null,
    prevValueSelected: this.props.valueSelected,
  };

  static propTypes = {
    /**
     * Provide a collection of <RadioTile> components to render in the group
     */
    children: PropTypes.node,

    /**
     * Provide an optional className to be applied to the container node
     */
    className: PropTypes.string,

    /**
     * Specify the the value of <RadioTile> to be selected by default
     */
    defaultSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

    /**
     * Specify the name of the underlying <input> nodes
     */
    name: PropTypes.string.isRequired,

    /**
     * Specify whether the group is disabled
     */
    disabled: PropTypes.bool,

    /**
     * Provide an optional `onChange` hook that is called whenever the value of
     * the group changes
     */
    onChange: PropTypes.func,

    /**
     * Provide an optional legend for this group
     */
    legend: PropTypes.string,

    /**
     * Specify the value that is currently selected in the group
     */
    valueSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  };

  static defaultProps = {
    onChange: /* istanbul ignore next */ () => {},
  };

  static getDerivedStateFromProps({ valueSelected, defaultSelected }, state) {
    const { prevValueSelected } = state;
    return prevValueSelected === valueSelected
      ? null
      : {
          selected: valueSelected || defaultSelected || null,
          prevValueSelected: valueSelected,
        };
  }

  getRadioTiles = () => {
    const childrenArray = React.Children.toArray(this.props.children);
    const children = childrenArray.map(tileRadio => {
      const { value, ...other } = tileRadio.props;
      /* istanbul ignore if */
      if (typeof tileRadio.props.checked !== 'undefined') {
        warning(
          false,
          `Instead of using the checked property on the RadioTile, set
            the defaultSelected property or valueSelected property on the TileGroup.`
        );
      }

      return (
        <RadioTile
          {...other}
          name={this.props.name}
          key={value}
          value={value}
          onChange={this.handleChange}
          checked={value === this.state.selected}
        />
      );
    });

    return children;
  };

  handleChange = (newSelection, value, evt) => {
    if (newSelection !== this.state.selected) {
      this.setState({ selected: newSelection });
      this.props.onChange(newSelection, this.props.name, evt);
    }
  };

  renderLegend = legend => {
    if (legend) {
      return <legend>{legend}</legend>;
    }
  };

  render() {
    const {
      disabled,
      className = `${prefix}--tile-group`,
      legend,
    } = this.props;

    return (
      <fieldset className={className} disabled={disabled}>
        {this.renderLegend(legend)}
        {this.getRadioTiles()}
      </fieldset>
    );
  }
}
<commit_msg>fix(TileGroup): Wrap RadioTiles inside TileGroup (#3947)<commit_after>/**
 * Copyright IBM Corp. 2016, 2018
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import PropTypes from 'prop-types';
import React from 'react';
import RadioTile from '../RadioTile';
import warning from 'warning';
import { settings } from 'carbon-components';

const { prefix } = settings;

export default class TileGroup extends React.Component {
  state = {
    selected: this.props.valueSelected || this.props.defaultSelected || null,
    prevValueSelected: this.props.valueSelected,
  };

  static propTypes = {
    /**
     * Provide a collection of <RadioTile> components to render in the group
     */
    children: PropTypes.node,

    /**
     * Provide an optional className to be applied to the container node
     */
    className: PropTypes.string,

    /**
     * Specify the the value of <RadioTile> to be selected by default
     */
    defaultSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

    /**
     * Specify the name of the underlying <input> nodes
     */
    name: PropTypes.string.isRequired,

    /**
     * Specify whether the group is disabled
     */
    disabled: PropTypes.bool,

    /**
     * Provide an optional `onChange` hook that is called whenever the value of
     * the group changes
     */
    onChange: PropTypes.func,

    /**
     * Provide an optional legend for this group
     */
    legend: PropTypes.string,

    /**
     * Specify the value that is currently selected in the group
     */
    valueSelected: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  };

  static defaultProps = {
    onChange: /* istanbul ignore next */ () => {},
  };

  static getDerivedStateFromProps({ valueSelected, defaultSelected }, state) {
    const { prevValueSelected } = state;
    return prevValueSelected === valueSelected
      ? null
      : {
          selected: valueSelected || defaultSelected || null,
          prevValueSelected: valueSelected,
        };
  }

  getRadioTiles = () => {
    const childrenArray = React.Children.toArray(this.props.children);
    const children = childrenArray.map(tileRadio => {
      const { value, ...other } = tileRadio.props;
      /* istanbul ignore if */
      if (typeof tileRadio.props.checked !== 'undefined') {
        warning(
          false,
          `Instead of using the checked property on the RadioTile, set
            the defaultSelected property or valueSelected property on the TileGroup.`
        );
      }

      return (
        <RadioTile
          {...other}
          name={this.props.name}
          key={value}
          value={value}
          onChange={this.handleChange}
          checked={value === this.state.selected}
        />
      );
    });

    return children;
  };

  handleChange = (newSelection, value, evt) => {
    if (newSelection !== this.state.selected) {
      this.setState({ selected: newSelection });
      this.props.onChange(newSelection, this.props.name, evt);
    }
  };

  renderLegend = legend => {
    if (legend) {
      return <legend>{legend}</legend>;
    }
  };

  render() {
    const {
      disabled,
      className = `${prefix}--tile-group`,
      legend,
    } = this.props;

    return (
      <fieldset className={className} disabled={disabled}>
        {this.renderLegend(legend)}
        <div>
          {this.getRadioTiles()}
        </div>
      </fieldset>
    );
  }
}
<|endoftext|>


<commit_before>import DockerContainer from './docker-container';
import Promise from 'bluebird';
import _ from 'lodash';
import retry from 'bluebird-retry';
import IpResolver from './docker-host-ip-resolver';

const debug = require('debug')('sokoban');

function Sokoban(maybeHostname) {
    this.containers = {};
    this.ipResolver = new IpResolver(maybeHostname);

}

Sokoban.prototype.dockerHostName = function() {
    return this.ipResolver.resolve();
}

Sokoban.prototype.provision = function(imageTag, containerName) {
    this.containers[containerName] = new DockerContainer(imageTag, containerName);
    this.containers[containerName].pullIfNeeded();
};

Sokoban.prototype.run = function({containerName, ports, env, barrier, volumes, links, maxRetries, delayInterval}) {

    const container = this.containers[containerName];
    const host = this.ipResolver.resolve();

    if (!host) {
        return Promise.reject("Could not resolve Docker hostname");
    } else {
        barrier = barrier || function () {
            };
        maxRetries = maxRetries || 5;

        return container.run({ports, env, volumes, links})
            .then(() => retry(() => barrier(host), {
                max_tries: maxRetries,
                interval: delayInterval || 1000,
                backoff: 1.2
            }))
            .then(
            () => {
                const containerInfo = {host};
                debug(containerName, "ready, returning container info", containerInfo);
                return containerInfo;
            },
            e => {
                debug(containerName, "not ready after", maxRetries, "attempts, error is", e);
                throw e;
            }
        );
    }
};

Sokoban.prototype.dumpAllLogs = function() {
    return _.reduce(this.containers, (promise, container) => promise.then(container.printLogs()), Promise.resolve());
};

Sokoban.prototype.killAll = function() {
    return Promise.all(_.map(this.containers, c => c.kill()));
};

export default Sokoban;<commit_msg>fixing a bug where print log was called not as a callback<commit_after>import DockerContainer from './docker-container';
import Promise from 'bluebird';
import _ from 'lodash';
import retry from 'bluebird-retry';
import IpResolver from './docker-host-ip-resolver';

const debug = require('debug')('sokoban');

function Sokoban(maybeHostname) {
    this.containers = {};
    this.ipResolver = new IpResolver(maybeHostname);

}

Sokoban.prototype.dockerHostName = function() {
    return this.ipResolver.resolve();
}

Sokoban.prototype.provision = function(imageTag, containerName) {
    this.containers[containerName] = new DockerContainer(imageTag, containerName);
    this.containers[containerName].pullIfNeeded();
};

Sokoban.prototype.run = function({containerName, ports, env, barrier, volumes, links, maxRetries, delayInterval}) {

    const container = this.containers[containerName];
    const host = this.ipResolver.resolve();

    if (!host) {
        return Promise.reject("Could not resolve Docker hostname");
    } else {
        barrier = barrier || function () {
            };
        maxRetries = maxRetries || 5;

        return container.run({ports, env, volumes, links})
            .then(() => retry(() => barrier(host), {
                max_tries: maxRetries,
                interval: delayInterval || 1000,
                backoff: 1.2
            }))
            .then(
            () => {
                const containerInfo = {host};
                debug(containerName, "ready, returning container info", containerInfo);
                return containerInfo;
            },
            e => {
                debug(containerName, "not ready after", maxRetries, "attempts, error is", e);
                throw e;
            }
        );
    }
};

Sokoban.prototype.dumpAllLogs = function() {
    return _.reduce(this.containers, (promise, container) => promise.then(() => container.printLogs()), Promise.resolve());
};

Sokoban.prototype.killAll = function() {
    return Promise.all(_.map(this.containers, c => c.kill()));
};

export default Sokoban;<|endoftext|>


<commit_before>module.exports = function(grunt) {

  grunt.initConfig({
    stylus: {
      compile: {
        files: {
          'build/site.css' : 'app/styles/*.styl'
        }
      }
    },
    less: {
      compile: {
        files: {
          'build/bootstrap.css' : 'vendor/styles/bootstrap/bootstrap.less'
        }
      }
    },
    component: {
      components: {
        output: 'build',
        config: 'component.json',
        styles: true,
        prefix: './'
      }
    },
    jade: {
      dev: {
        options: {
          data: {
            env: 'development'
          }
        },
        files: {
          'public/dev.html' : 'app/markup/index.jade'
        }
      },
      prod: {
        options: {
          data: {
            env: 'production'
          }
        },
        files: {
          'public/index.html' : 'app/markup/index.jade'
        }
      }
    },
    handlebars: {
      compile: {
        options: {
          namespace: 'app.templates',
          processName: function ( name ) {
            return name.split('/').pop().match(/^(.*)\.hbs$/)[1];
          }
        },
        files: {
          'build/templates.js' : 'app/templates/*.hbs'
        }
      }
    },
    concat: {
      js: {
        src: [
          'vendor/scripts/jquery.js',
          'vendor/scripts/underscore.js',
          'vendor/scripts/backbone.js',
          'vendor/scripts/handlebars.js',
          'build/components.js',
          'app/setup.js',
          'build/templates.js',
          'app/models/*.js',
          'app/collections/*.js',
          'app/routes/*.js',
          'app/views/View.js',
          'app/views/*.js',
          'app/application.js'
        ],
        dest: 'public/js/app.js'
      },
      css: {
        src: [
          'build/components.css',
          'build/bootstrap.css',
          'build/site.css'
        ],
        dest: 'public/css/app.css'
      }
    },
    min: {
      js: {
        src: 'public/js/app.js',
        dest: 'public/js/app.min.js'
      }
    },
    mincss: {
      compress: {
        files: {
          'public/css/app.min.css' : 'public/css/app.css'
        }
      }
    },
    copy: {
      main: {
        files: [{
          src: 'build/web-audio-components-rack/*',
          dest: 'public/css/web-audio-components-rack/'
        }]
      }
    },
    watch: {
      scripts: {
        files: [
          'app/*.js',
          'app/models/*.js',
          'app/collections/*.js',
          'app/routes/*.js',
          'app/views/*.js',
          'app/templates/*.hbs',
          'app/styles/*.styl'
        ],
        tasks: 'less stylus handlebars component jade concat mincss copy min'
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib');
  grunt.loadNpmTasks('grunt-component-build');
  grunt.registerTask('default', 'less stylus handlebars component jade concat mincss copy min');

};
<commit_msg>Add markup to watcher<commit_after>module.exports = function(grunt) {

  grunt.initConfig({
    stylus: {
      compile: {
        files: {
          'build/site.css' : 'app/styles/*.styl'
        }
      }
    },
    less: {
      compile: {
        files: {
          'build/bootstrap.css' : 'vendor/styles/bootstrap/bootstrap.less'
        }
      }
    },
    component: {
      components: {
        output: 'build',
        config: 'component.json',
        styles: true,
        prefix: './'
      }
    },
    jade: {
      dev: {
        options: {
          data: {
            env: 'development'
          }
        },
        files: {
          'public/dev.html' : 'app/markup/index.jade'
        }
      },
      prod: {
        options: {
          data: {
            env: 'production'
          }
        },
        files: {
          'public/index.html' : 'app/markup/index.jade'
        }
      }
    },
    handlebars: {
      compile: {
        options: {
          namespace: 'app.templates',
          processName: function ( name ) {
            return name.split('/').pop().match(/^(.*)\.hbs$/)[1];
          }
        },
        files: {
          'build/templates.js' : 'app/templates/*.hbs'
        }
      }
    },
    concat: {
      js: {
        src: [
          'vendor/scripts/jquery.js',
          'vendor/scripts/underscore.js',
          'vendor/scripts/backbone.js',
          'vendor/scripts/handlebars.js',
          'build/components.js',
          'app/setup.js',
          'build/templates.js',
          'app/models/*.js',
          'app/collections/*.js',
          'app/routes/*.js',
          'app/views/View.js',
          'app/views/*.js',
          'app/application.js'
        ],
        dest: 'public/js/app.js'
      },
      css: {
        src: [
          'build/components.css',
          'build/bootstrap.css',
          'build/site.css'
        ],
        dest: 'public/css/app.css'
      }
    },
    min: {
      js: {
        src: 'public/js/app.js',
        dest: 'public/js/app.min.js'
      }
    },
    mincss: {
      compress: {
        files: {
          'public/css/app.min.css' : 'public/css/app.css'
        }
      }
    },
    copy: {
      main: {
        files: [{
          src: 'build/web-audio-components-rack/*',
          dest: 'public/css/web-audio-components-rack/'
        }]
      }
    },
    watch: {
      scripts: {
        files: [
          'app/*.js',
          'app/models/*.js',
          'app/collections/*.js',
          'app/routes/*.js',
          'app/views/*.js',
          'app/templates/*.hbs',
          'app/styles/*.styl',
          'app/markup/*.jade'
        ],
        tasks: 'less stylus handlebars component jade concat mincss copy min'
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib');
  grunt.loadNpmTasks('grunt-component-build');
  grunt.registerTask('default', 'less stylus handlebars component jade concat mincss copy min');

};
<|endoftext|>


<commit_before>/* @flow */
import type { Action } from '../actions/types'
import type { Message } from 'types'

export type MessagesState = Array<Message>

const initialState = []

export default function reducer (state: MessagesState = initialState, action: Action) {
  switch (action.type) {
    case 'RECEIVE_MESSAGE':
      const isMessageInState = state.findIndex(message => message.key === action.message.key) !== -1
      return (!isMessageInState ? state.concat(action.message) : state)
    default:
      return state
  }
}
<commit_msg>changed ternary to if statement, saved refined action.message type to variable.<commit_after>/* @flow */
import type { Action } from '../actions/types'
import type { Message } from 'types'

export type MessagesState = Array<Message>

const initialState = []

export default function reducer (state: MessagesState = initialState, action: Action) {
  switch (action.type) {
    case 'RECEIVE_MESSAGE':
      const message = action.message
      const isMessageInState = state.findIndex(el => el.key === message.key) !== -1
      if (!isMessageInState) {
        return state.concat(message)
      }
      return state
    default:
      return state
  }
}
<|endoftext|>


<commit_before>/**
 * Avalara © 2017
 * file: test/accounts.spec.js
 */

import Avatax from '../';
import { account, licenseKey } from './test_creds';
import nock from 'nock';
import accountResponse from './fixtures/account_response';

describe('Avatax Accounts', () => {
  const baseUrl = 'https://sandbox-rest.avatax.com';
  const client = new Avatax({ account, licenseKey });

  describe('Getting accounts by id', () => {

    beforeEach(() => {
      nock(baseUrl)
        .get(`/api/v2/accounts/${account}`)
        .reply(200, accountResponse);
    });

    it('should return account by id', () => {
      return client.getAccountById({ id: account })
        .then(res => {
          expect(res).toEqual(accountResponse);
        });
    });
  });
});

<commit_msg>fixing account spec<commit_after>/**
 * Avalara © 2017
 * file: test/accounts.spec.js
 */

import Avatax from '../';
import { account } from './test_creds';
import nock from 'nock';
import accountResponse from './fixtures/account_response';
import loadCreds from './helpers/load_creds';

describe('Avatax Accounts', () => {
  const baseUrl = 'https://sandbox-rest.avatax.com';
  const client = new Avatax(loadCreds());

  describe('Getting accounts by id', () => {

    beforeEach(() => {
      nock(baseUrl)
        .get(`/api/v2/accounts/${account}`)
        .reply(200, accountResponse);
    });

    it('should return account by id', () => {
      return client.getAccount({ id: account })
        .then(res => {
          expect(res).toEqual(accountResponse);
        });
    });
  });
});

<|endoftext|>


<commit_before>const path = require('path');
const webpack = require('webpack');
const CONFIG = require('./webpack.base');

const { CLIENT_ENTRY, CLIENT_OUTPUT, PUBLIC_PATH } = CONFIG;

module.exports = {
  devtool: 'eval',
  entry: {
    main: [
      'webpack/hot/only-dev-server',
      'webpack-hot-middleware/client',
      CLIENT_ENTRY
    ],
    vendor: [
      'react',
      'react-dom',
      'react-router',
      'redux',
      'react-redux'
    ]
  },
  output: {
    filename: '[name].js',
    chunkFilename: '[name].chunk.js',
    publicPath: '/',
    path: CLIENT_OUTPUT
  },
  module: {
    loader: [
      {
        test: /\.js$/,
        loaders: 'babel',
        exclude: /(node_modules|server)/
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development'),
      '__DEV__': true
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js', 2),
    new webpack.NoErrorsPlugin()
  ]
};
<commit_msg>cleap up comma dangles<commit_after>const webpack = require('webpack');
const CONFIG = require('./webpack.base');

const { CLIENT_ENTRY, CLIENT_OUTPUT } = CONFIG;

module.exports = {
  devtool: 'eval',
  entry: {
    main: [
      'webpack/hot/only-dev-server',
      'webpack-hot-middleware/client',
      CLIENT_ENTRY,
    ],
    vendor: [
      'react',
      'react-dom',
      'react-router',
      'redux',
      'react-redux',
    ],
  },
  output: {
    filename: '[name].js',
    chunkFilename: '[name].chunk.js',
    publicPath: '/',
    path: CLIENT_OUTPUT,
  },
  module: {
    loader: [
      {
        test: /\.js$/,
        loaders: 'babel',
        exclude: /(node_modules|server)/,
      },
    ],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development'),
      '__DEV__': true,
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js', 2),
    new webpack.NoErrorsPlugin(),
  ],
};
<|endoftext|>


<commit_before>import test from 'blue-tape'
import { spy } from 'sinon'
import { SEMESTER_LOAD_COMPLETED } from '../../src/constants/actionTypes'
import * as actions from '../../src/actions/semesterActions'

const getEmptyState = () => {
  return {semester: {}}
}

test('fetchSemesterData() dispatches SEMESTER_LOAD_COMPLETED with callback data', t => {
  const searchCallback = (cb) => {
    t.equal(typeof cb, 'function', 'callback receives a callback for response')
    t.end()
  }

  const thunk = actions.fetchSemesterData(searchCallback, new Date())
  const dispatch = () => {}

  t.equal(typeof thunk, 'function', 'fetchSearchResults returns a thunk function immediately')

  thunk(dispatch, getEmptyState)
})

test('fetchSemesterData() dispatch', t => {
  let date = new Date('2015-09-10')
  const semesters = [
    {
      id: '18000-B142',
      semester: 'B142',
      faculty: 18000,
      startsAt: '2015-02-16',
      endsAt: '2015-09-21',
      examsStartsAt: '2015-05-18',
      examsEndsAt: '2015-06-27',
      hourDuration: 45,
      breakDuration: 15,
      dayStartsAtHour: 7.5,
      dayEndsAtHour: 21.25,
    },
    {
      id: '18000-B151',
      semester: 'B151',
      faculty: 18000,
      startsAt: '2015-09-12',
      endsAt: '2016-02-28',
      examsStartsAt: '2015-01-12',
      examsEndsAt: '2015-02-20',
      hourDuration: 45,
      breakDuration: 15,
      dayStartsAtHour: 7.5,
      dayEndsAtHour: 21.25,
    },
  ]

  // faux callback passed from outside application
  const callback = (cb) => cb(semesters)

  let dispatch = spy()
  let thunk = actions.fetchSemesterData(callback, date)
  thunk(dispatch, getEmptyState)

  const expectedCalls = 1
  t.equal(dispatch.callCount, expectedCalls, `dispatch has been called ${expectedCalls} times`)

  t.test('fetchSemesterData() dispatched action', st => {
    const [actualArg,] = dispatch.firstCall.args
    st.equal(actualArg.type, SEMESTER_LOAD_COMPLETED, 'dispatches SEMESTER_LOAD_COMPLETED action')
    st.equal(actualArg.payload.id, '18000-B142', 'sends just the semester for a given date')
    st.equal(actualArg.payload.season, 'summer', 'calculates the semester season')
    st.equal(typeof actualArg.payload.grid, 'object', 'converts semester details for consumption by fittable')
    st.end()
  })
})

test('fetchSemesterData() dispatch with semester loaded', t => {
  const date = new Date('2015-09-10')
  const state = {
    semester: {
      startsOn: '2015-02-18',
      endsOn: '2015-09-21',
      valid: true,
    },
  }

  const dispatch = spy()
  const callback = spy()

  const thunk = actions.fetchSemesterData(callback, date)

  thunk(dispatch, () => state)
  t.equal(callback.callCount, 0, 'does not execute callback if the date is already within current semester')
  t.equal(dispatch.callCount, 0, 'does not dispatches action if the date is already within current semester')
  t.end()
})

test('invalidateSemesterData()', t => {
  const semester = {
    season: 'winter',
    valid: true,
    years: [2015, 2016],
  }

  const expected = {
    season: 'winter',
    valid: false,
    years: [2015, 2016],
  }

  const invalidated = actions.invalidateSemesterData(semester)

  t.deepEqual(invalidated, expected, 'invalidate semester')
  t.deepEqual(actions.invalidateSemesterData(invalidated), expected, 'invalidating invalidated semester does nothing')
  t.end()
})
<commit_msg>Add tests checking semester invalidation while parsing<commit_after>import test from 'blue-tape'
import { spy } from 'sinon'
import { SEMESTER_LOAD_COMPLETED } from '../../src/constants/actionTypes'
import * as actions from '../../src/actions/semesterActions'

const getEmptyState = () => {
  return {semester: {}}
}

test('fetchSemesterData() dispatches SEMESTER_LOAD_COMPLETED with callback data', t => {
  const searchCallback = (cb) => {
    t.equal(typeof cb, 'function', 'callback receives a callback for response')
    t.end()
  }

  const thunk = actions.fetchSemesterData(searchCallback, new Date())
  const dispatch = () => {}

  t.equal(typeof thunk, 'function', 'fetchSearchResults returns a thunk function immediately')

  thunk(dispatch, getEmptyState)
})

test('fetchSemesterData() dispatch', t => {
  let date = new Date('2015-09-10')
  const semesters = [
    {
      id: '18000-B142',
      semester: 'B142',
      faculty: 18000,
      startsAt: '2015-02-16',
      endsAt: '2015-09-21',
      examsStartsAt: '2015-05-18',
      examsEndsAt: '2015-06-27',
      hourDuration: 45,
      breakDuration: 15,
      dayStartsAtHour: 7.5,
      dayEndsAtHour: 21.25,
    },
    {
      id: '18000-B151',
      semester: 'B151',
      faculty: 18000,
      startsAt: '2015-09-12',
      endsAt: '2016-02-28',
      examsStartsAt: '2015-01-12',
      examsEndsAt: '2015-02-20',
      hourDuration: 45,
      breakDuration: 15,
      dayStartsAtHour: 7.5,
      dayEndsAtHour: 21.25,
    },
  ]

  // faux callback passed from outside application
  const callback = (cb) => cb(semesters)
  const callbackEmpty = (cb) => cb({})

  let dispatch = spy()
  let expectedCalls = 1

  // fetch correct data
  let thunk = actions.fetchSemesterData(callback, date)
  thunk(dispatch, getEmptyState)
  t.equal(dispatch.callCount, expectedCalls, `dispatch has been called ${expectedCalls} times`)

  // fetch missing data
  thunk = actions.fetchSemesterData(callbackEmpty, date)
  thunk(dispatch, getEmptyState)
  t.equal(dispatch.callCount, ++expectedCalls, `dispatch has been called ${expectedCalls} times`)

  // fetch correct data with incorrect actual date
  date = new Date('1970-09-10')
  thunk = actions.fetchSemesterData(callback, date)
  thunk(dispatch, getEmptyState)
  t.equal(dispatch.callCount, ++expectedCalls, `dispatch has been called ${expectedCalls} times`)

  t.test('fetchSemesterData() dispatched action', st => {
    const [actualArg,] = dispatch.firstCall.args
    st.equal(actualArg.type, SEMESTER_LOAD_COMPLETED, 'dispatches SEMESTER_LOAD_COMPLETED action')
    st.equal(actualArg.payload.id, '18000-B142', 'sends just the semester for a given date')
    st.equal(actualArg.payload.season, 'summer', 'calculates the semester season')
    st.equal(actualArg.payload.valid, true, 'is valid when the data are complete and current semester')
    st.equal(typeof actualArg.payload.grid, 'object', 'converts semester details for consumption by fittable')
    st.end()
  })

  t.test('fetchSemesterData() dispatched with missing data', st => {
    const [actualArg,] = dispatch.secondCall.args
    st.equal(actualArg.payload.valid, false, 'is invalid because of missing data')
    st.end()
  })

  t.test('fetchSemesterData() dispatched with out-of-semester date', st => {
    const [actualArg,] = dispatch.thirdCall.args
    st.equal(actualArg.payload.valid, false, 'is invalid because of wrong date')
    st.end()
  })
})

test('fetchSemesterData() dispatch with semester loaded', t => {
  const date = new Date('2015-09-10')
  const state = {
    semester: {
      startsOn: '2015-02-18',
      endsOn: '2015-09-21',
      valid: true,
    },
  }

  const dispatch = spy()
  const callback = spy()

  const thunk = actions.fetchSemesterData(callback, date)

  thunk(dispatch, () => state)
  t.equal(callback.callCount, 0, 'does not execute callback if the date is already within current semester')
  t.equal(dispatch.callCount, 0, 'does not dispatches action if the date is already within current semester')
  t.end()
})

test('invalidateSemesterData()', t => {
  const semester = {
    season: 'winter',
    valid: true,
    years: [2015, 2016],
  }

  const expected = {
    season: 'winter',
    valid: false,
    years: [2015, 2016],
  }

  const invalidated = actions.invalidateSemesterData(semester)

  t.deepEqual(invalidated, expected, 'invalidate semester')
  t.deepEqual(actions.invalidateSemesterData(invalidated), expected, 'invalidating invalidated semester does nothing')
  t.end()
})
<|endoftext|>


<commit_before>"use strict";

// Dependencies
const tinyreq = require("tinyreq")
    , ul = require("ul")
    , noop = require("noop6")
    ;

/**
 * jsonRequest
 * Creates the http(s) request and parses the response.
 *
 * @name jsonRequest
 * @function
 * @param {String|Object} options A string representing the request url or an object passed to the `tinyreq` function.
 * @param {Object} data The request data object.
 * @param {Function} callback The callback function.
 * @return {Object} The request object.
 */
module.exports = function jsonRequest (options, data, callback) {

    debugger
    // Handle options as string
    if (typeof options === "string") {
        options = {
            url: options
        };
    }

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    options.data = options.data || data;

    // Stringify the data
    if (typeof options.data === "object") {
        options.data = JSON.stringify(options.data);
    }

    options = ul.deepMerge(options, {
        headers: {
            "Content-Type": "application/json"
        }
    });

    const maybeCallback = callback ? (err, body, res) => {
        if (err) {
            return callback(err, body, res);
        }
        if (body) {
            try {
                body = JSON.parse(body);
            } catch (e) {
                return callback(e, body, res);
            }
        }
        callback(null, body, res);
    } : noop;

    const prom = tinyreq(options, maybeCallback).then(body => {
        return JSON.parse(body);
    });
    prom.catch(noop);
    return prom;
};
<commit_msg>Remove debugger<commit_after>"use strict";

// Dependencies
const tinyreq = require("tinyreq")
    , ul = require("ul")
    , noop = require("noop6")
    ;

/**
 * jsonRequest
 * Creates the http(s) request and parses the response.
 *
 * @name jsonRequest
 * @function
 * @param {String|Object} options A string representing the request url or an object passed to the `tinyreq` function.
 * @param {Object} data The request data object.
 * @param {Function} callback The callback function.
 * @return {Object} The request object.
 */
module.exports = function jsonRequest (options, data, callback) {

    // Handle options as string
    if (typeof options === "string") {
        options = {
            url: options
        };
    }

    if (typeof data === "function") {
        callback = data;
        data = undefined;
    }

    options.data = options.data || data;

    // Stringify the data
    if (typeof options.data === "object") {
        options.data = JSON.stringify(options.data);
    }

    options = ul.deepMerge(options, {
        headers: {
            "Content-Type": "application/json"
        }
    });

    const maybeCallback = callback ? (err, body, res) => {
        if (err) {
            return callback(err, body, res);
        }
        if (body) {
            try {
                body = JSON.parse(body);
            } catch (e) {
                return callback(e, body, res);
            }
        }
        callback(null, body, res);
    } : noop;

    const prom = tinyreq(options, maybeCallback).then(body => {
        return JSON.parse(body);
    });
    prom.catch(noop);
    return prom;
};
<|endoftext|>


<commit_before>require('ember-views/views/container_view');
require('ember-runtime/system/string');

/**
@module ember
@submodule ember-views
*/

var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;

/**
  `Ember.CollectionView` is an `Ember.View` descendent responsible for managing
  a collection (an array or array-like object) by maintaing a child view object
  and associated DOM representation for each item in the array and ensuring
  that child views and their associated rendered HTML are updated when items in
  the array are added, removed, or replaced.

  ## Setting content

  The managed collection of objects is referenced as the `Ember.CollectionView`
  instance's `content` property.

  ```javascript
  someItemsView = Ember.CollectionView.create({
    content: ['A', 'B','C']
  })
  ```

  The view for each item in the collection will have its `content` property set
  to the item.

  ## Specifying itemViewClass

  By default the view class for each item in the managed collection will be an
  instance of `Ember.View`. You can supply a different class by setting the
  `CollectionView`'s `itemViewClass` property.

  Given an empty `<body>` and the following code:

  ```javascript
  someItemsView = Ember.CollectionView.create({
    classNames: ['a-collection'],
    content: ['A','B','C'],
    itemViewClass: Ember.View.extend({
      template: Ember.Handlebars.compile("the letter: {{view.content}}")
    })
  });

  someItemsView.appendTo('body');
  ```

  Will result in the following HTML structure

  ```html
  <div class="ember-view a-collection">
    <div class="ember-view">the letter: A</div>
    <div class="ember-view">the letter: B</div>
    <div class="ember-view">the letter: C</div>
  </div>
  ```

  ## Automatic matching of parent/child tagNames

  Setting the `tagName` property of a `CollectionView` to any of
  "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result
  in the item views receiving an appropriately matched `tagName` property.

  Given an empty `<body>` and the following code:

  ```javascript
  anUndorderedListView = Ember.CollectionView.create({
    tagName: 'ul',
    content: ['A','B','C'],
    itemViewClass: Ember.View.extend({
      template: Ember.Handlebars.compile("the letter: {{view.content}}")
    })
  });

  anUndorderedListView.appendTo('body');
  ```

  Will result in the following HTML structure

  ```html
  <ul class="ember-view a-collection">
    <li class="ember-view">the letter: A</li>
    <li class="ember-view">the letter: B</li>
    <li class="ember-view">the letter: C</li>
  </ul>
  ```

  Additional `tagName` pairs can be provided by adding to
  `Ember.CollectionView.CONTAINER_MAP `

  ```javascript
  Ember.CollectionView.CONTAINER_MAP['article'] = 'section'
  ```

  ## Programatic creation of child views

  For cases where additional customization beyond the use of a single
  `itemViewClass` or `tagName` matching is required CollectionView's
  `createChildView` method can be overidden:

  ```javascript
  CustomCollectionView = Ember.CollectionView.extend({
    createChildView: function(viewClass, attrs) {
      if (attrs.content.kind == 'album') {
        viewClass = App.AlbumView;
      } else {
        viewClass = App.SongView;
      }
      this._super(viewClass, attrs);
    }
  });
  ```

  ## Empty View

  You can provide an `Ember.View` subclass to the `Ember.CollectionView`
  instance as its `emptyView` property. If the `content` property of a
  `CollectionView` is set to `null` or an empty array, an instance of this view
  will be the `CollectionView`s only child.

  ```javascript
  aListWithNothing = Ember.CollectionView.create({
    classNames: ['nothing']
    content: null,
    emptyView: Ember.View.extend({
      template: Ember.Handlebars.compile("The collection is empty")
    })
  });

  aListWithNothing.appendTo('body');
  ```

  Will result in the following HTML structure

  ```html
  <div class="ember-view nothing">
    <div class="ember-view">
      The collection is empty
    </div>
  </div>
  ```

  ## Adding and Removing items

  The `childViews` property of a `CollectionView` should not be directly
  manipulated. Instead, add, remove, replace items from its `content` property.
  This will trigger appropriate changes to its rendered HTML.

  ## Use in templates via the `{{collection}}` `Ember.Handlebars` helper

  `Ember.Handlebars` provides a helper specifically for adding
  `CollectionView`s to templates. See `Ember.Handlebars.collection` for more
  details

  @class CollectionView
  @namespace Ember
  @extends Ember.ContainerView
  @since Ember 0.9
*/
Ember.CollectionView = Ember.ContainerView.extend(
/** @scope Ember.CollectionView.prototype */ {

  /**
    A list of items to be displayed by the `Ember.CollectionView`.

    @property content
    @type Ember.Array
    @default null
  */
  content: null,

  /**
    @private

    This provides metadata about what kind of empty view class this
    collection would like if it is being instantiated from another
    system (like Handlebars)

    @property emptyViewClass
  */
  emptyViewClass: Ember.View,

  /**
    An optional view to display if content is set to an empty array.

    @property emptyView
    @type Ember.View
    @default null
  */
  emptyView: null,

  /**
    @property itemViewClass
    @type Ember.View
    @default Ember.View
  */
  itemViewClass: Ember.View,

  init: function() {
    var ret = this._super();
    this._contentDidChange();
    return ret;
  },

  _contentWillChange: Ember.beforeObserver(function() {
    var content = this.get('content');

    if (content) { content.removeArrayObserver(this); }
    var len = content ? get(content, 'length') : 0;
    this.arrayWillChange(content, 0, len);
  }, 'content'),

  /**
    @private

    Check to make sure that the content has changed, and if so,
    update the children directly. This is always scheduled
    asynchronously, to allow the element to be created before
    bindings have synchronized and vice versa.

    @method _contentDidChange
  */
  _contentDidChange: Ember.observer(function() {
    var content = get(this, 'content');

    if (content) {
      Ember.assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detect(content));
      content.addArrayObserver(this);
    }

    var len = content ? get(content, 'length') : 0;
    this.arrayDidChange(content, 0, null, len);
  }, 'content'),

  willDestroy: function() {
    var content = get(this, 'content');
    if (content) { content.removeArrayObserver(this); }

    this._super();

    if (this._createdEmptyView) {
      this._createdEmptyView.destroy();
    }
  },

  arrayWillChange: function(content, start, removedCount) {
    // If the contents were empty before and this template collection has an
    // empty view remove it now.
    var emptyView = get(this, 'emptyView');
    if (emptyView && emptyView instanceof Ember.View) {
      emptyView.removeFromParent();
    }

    // Loop through child views that correspond with the removed items.
    // Note that we loop from the end of the array to the beginning because
    // we are mutating it as we go.
    var childViews = this._childViews, childView, idx, len;

    len = this._childViews.length;

    var removingAll = removedCount === len;

    if (removingAll) {
      this.currentState.empty(this);
    }

    for (idx = start + removedCount - 1; idx >= start; idx--) {
      childView = childViews[idx];
      if (removingAll) { childView.removedFromDOM = true; }
      childView.destroy();
    }
  },

  /**
    Called when a mutation to the underlying content array occurs.

    This method will replay that mutation against the views that compose the
    `Ember.CollectionView`, ensuring that the view reflects the model.

    This array observer is added in `contentDidChange`.

    @method arrayDidChange
    @param {Array} addedObjects the objects that were added to the content
    @param {Array} removedObjects the objects that were removed from the content
    @param {Number} changeIndex the index at which the changes occurred
  */
  arrayDidChange: function(content, start, removed, added) {
    var itemViewClass = get(this, 'itemViewClass'),
        addedViews = [], view, item, idx, len, itemTagName;

    if ('string' === typeof itemViewClass) {
      itemViewClass = get(itemViewClass);
    }

    Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), Ember.View.detect(itemViewClass));

    len = content ? get(content, 'length') : 0;
    if (len) {
      for (idx = start; idx < start+added; idx++) {
        item = content.objectAt(idx);

        view = this.createChildView(itemViewClass, {
          content: item,
          contentIndex: idx
        });

        addedViews.push(view);
      }
    } else {
      var emptyView = get(this, 'emptyView');
      if (!emptyView) { return; }

      var isClass = Ember.CoreView.detect(emptyView);

      emptyView = this.createChildView(emptyView);
      addedViews.push(emptyView);
      set(this, 'emptyView', emptyView);

      if (isClass) { this._createdEmptyView = emptyView; }
    }
    this.replace(start, 0, addedViews);
  },

  createChildView: function(view, attrs) {
    view = this._super(view, attrs);

    var itemTagName = get(view, 'tagName');
    var tagName = (itemTagName === null || itemTagName === undefined) ? Ember.CollectionView.CONTAINER_MAP[get(this, 'tagName')] : itemTagName;

    set(view, 'tagName', tagName);

    return view;
  }
});

/**
  A map of parent tags to their default child tags. You can add
  additional parent tags if you want collection views that use
  a particular parent tag to default to a child tag.

  @property CONTAINER_MAP
  @type Hash
  @static
  @final
*/
Ember.CollectionView.CONTAINER_MAP = {
  ul: 'li',
  ol: 'li',
  table: 'tr',
  thead: 'tr',
  tbody: 'tr',
  tfoot: 'tr',
  tr: 'td',
  select: 'option'
};
<commit_msg>Fix missing reuturn in CollectionView docs<commit_after>require('ember-views/views/container_view');
require('ember-runtime/system/string');

/**
@module ember
@submodule ember-views
*/

var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;

/**
  `Ember.CollectionView` is an `Ember.View` descendent responsible for managing
  a collection (an array or array-like object) by maintaing a child view object
  and associated DOM representation for each item in the array and ensuring
  that child views and their associated rendered HTML are updated when items in
  the array are added, removed, or replaced.

  ## Setting content

  The managed collection of objects is referenced as the `Ember.CollectionView`
  instance's `content` property.

  ```javascript
  someItemsView = Ember.CollectionView.create({
    content: ['A', 'B','C']
  })
  ```

  The view for each item in the collection will have its `content` property set
  to the item.

  ## Specifying itemViewClass

  By default the view class for each item in the managed collection will be an
  instance of `Ember.View`. You can supply a different class by setting the
  `CollectionView`'s `itemViewClass` property.

  Given an empty `<body>` and the following code:

  ```javascript
  someItemsView = Ember.CollectionView.create({
    classNames: ['a-collection'],
    content: ['A','B','C'],
    itemViewClass: Ember.View.extend({
      template: Ember.Handlebars.compile("the letter: {{view.content}}")
    })
  });

  someItemsView.appendTo('body');
  ```

  Will result in the following HTML structure

  ```html
  <div class="ember-view a-collection">
    <div class="ember-view">the letter: A</div>
    <div class="ember-view">the letter: B</div>
    <div class="ember-view">the letter: C</div>
  </div>
  ```

  ## Automatic matching of parent/child tagNames

  Setting the `tagName` property of a `CollectionView` to any of
  "ul", "ol", "table", "thead", "tbody", "tfoot", "tr", or "select" will result
  in the item views receiving an appropriately matched `tagName` property.

  Given an empty `<body>` and the following code:

  ```javascript
  anUndorderedListView = Ember.CollectionView.create({
    tagName: 'ul',
    content: ['A','B','C'],
    itemViewClass: Ember.View.extend({
      template: Ember.Handlebars.compile("the letter: {{view.content}}")
    })
  });

  anUndorderedListView.appendTo('body');
  ```

  Will result in the following HTML structure

  ```html
  <ul class="ember-view a-collection">
    <li class="ember-view">the letter: A</li>
    <li class="ember-view">the letter: B</li>
    <li class="ember-view">the letter: C</li>
  </ul>
  ```

  Additional `tagName` pairs can be provided by adding to
  `Ember.CollectionView.CONTAINER_MAP `

  ```javascript
  Ember.CollectionView.CONTAINER_MAP['article'] = 'section'
  ```

  ## Programatic creation of child views

  For cases where additional customization beyond the use of a single
  `itemViewClass` or `tagName` matching is required CollectionView's
  `createChildView` method can be overidden:

  ```javascript
  CustomCollectionView = Ember.CollectionView.extend({
    createChildView: function(viewClass, attrs) {
      if (attrs.content.kind == 'album') {
        viewClass = App.AlbumView;
      } else {
        viewClass = App.SongView;
      }
      return this._super(viewClass, attrs);
    }
  });
  ```

  ## Empty View

  You can provide an `Ember.View` subclass to the `Ember.CollectionView`
  instance as its `emptyView` property. If the `content` property of a
  `CollectionView` is set to `null` or an empty array, an instance of this view
  will be the `CollectionView`s only child.

  ```javascript
  aListWithNothing = Ember.CollectionView.create({
    classNames: ['nothing']
    content: null,
    emptyView: Ember.View.extend({
      template: Ember.Handlebars.compile("The collection is empty")
    })
  });

  aListWithNothing.appendTo('body');
  ```

  Will result in the following HTML structure

  ```html
  <div class="ember-view nothing">
    <div class="ember-view">
      The collection is empty
    </div>
  </div>
  ```

  ## Adding and Removing items

  The `childViews` property of a `CollectionView` should not be directly
  manipulated. Instead, add, remove, replace items from its `content` property.
  This will trigger appropriate changes to its rendered HTML.

  ## Use in templates via the `{{collection}}` `Ember.Handlebars` helper

  `Ember.Handlebars` provides a helper specifically for adding
  `CollectionView`s to templates. See `Ember.Handlebars.collection` for more
  details

  @class CollectionView
  @namespace Ember
  @extends Ember.ContainerView
  @since Ember 0.9
*/
Ember.CollectionView = Ember.ContainerView.extend(
/** @scope Ember.CollectionView.prototype */ {

  /**
    A list of items to be displayed by the `Ember.CollectionView`.

    @property content
    @type Ember.Array
    @default null
  */
  content: null,

  /**
    @private

    This provides metadata about what kind of empty view class this
    collection would like if it is being instantiated from another
    system (like Handlebars)

    @property emptyViewClass
  */
  emptyViewClass: Ember.View,

  /**
    An optional view to display if content is set to an empty array.

    @property emptyView
    @type Ember.View
    @default null
  */
  emptyView: null,

  /**
    @property itemViewClass
    @type Ember.View
    @default Ember.View
  */
  itemViewClass: Ember.View,

  init: function() {
    var ret = this._super();
    this._contentDidChange();
    return ret;
  },

  _contentWillChange: Ember.beforeObserver(function() {
    var content = this.get('content');

    if (content) { content.removeArrayObserver(this); }
    var len = content ? get(content, 'length') : 0;
    this.arrayWillChange(content, 0, len);
  }, 'content'),

  /**
    @private

    Check to make sure that the content has changed, and if so,
    update the children directly. This is always scheduled
    asynchronously, to allow the element to be created before
    bindings have synchronized and vice versa.

    @method _contentDidChange
  */
  _contentDidChange: Ember.observer(function() {
    var content = get(this, 'content');

    if (content) {
      Ember.assert(fmt("an Ember.CollectionView's content must implement Ember.Array. You passed %@", [content]), Ember.Array.detect(content));
      content.addArrayObserver(this);
    }

    var len = content ? get(content, 'length') : 0;
    this.arrayDidChange(content, 0, null, len);
  }, 'content'),

  willDestroy: function() {
    var content = get(this, 'content');
    if (content) { content.removeArrayObserver(this); }

    this._super();

    if (this._createdEmptyView) {
      this._createdEmptyView.destroy();
    }
  },

  arrayWillChange: function(content, start, removedCount) {
    // If the contents were empty before and this template collection has an
    // empty view remove it now.
    var emptyView = get(this, 'emptyView');
    if (emptyView && emptyView instanceof Ember.View) {
      emptyView.removeFromParent();
    }

    // Loop through child views that correspond with the removed items.
    // Note that we loop from the end of the array to the beginning because
    // we are mutating it as we go.
    var childViews = this._childViews, childView, idx, len;

    len = this._childViews.length;

    var removingAll = removedCount === len;

    if (removingAll) {
      this.currentState.empty(this);
    }

    for (idx = start + removedCount - 1; idx >= start; idx--) {
      childView = childViews[idx];
      if (removingAll) { childView.removedFromDOM = true; }
      childView.destroy();
    }
  },

  /**
    Called when a mutation to the underlying content array occurs.

    This method will replay that mutation against the views that compose the
    `Ember.CollectionView`, ensuring that the view reflects the model.

    This array observer is added in `contentDidChange`.

    @method arrayDidChange
    @param {Array} addedObjects the objects that were added to the content
    @param {Array} removedObjects the objects that were removed from the content
    @param {Number} changeIndex the index at which the changes occurred
  */
  arrayDidChange: function(content, start, removed, added) {
    var itemViewClass = get(this, 'itemViewClass'),
        addedViews = [], view, item, idx, len, itemTagName;

    if ('string' === typeof itemViewClass) {
      itemViewClass = get(itemViewClass);
    }

    Ember.assert(fmt("itemViewClass must be a subclass of Ember.View, not %@", [itemViewClass]), Ember.View.detect(itemViewClass));

    len = content ? get(content, 'length') : 0;
    if (len) {
      for (idx = start; idx < start+added; idx++) {
        item = content.objectAt(idx);

        view = this.createChildView(itemViewClass, {
          content: item,
          contentIndex: idx
        });

        addedViews.push(view);
      }
    } else {
      var emptyView = get(this, 'emptyView');
      if (!emptyView) { return; }

      var isClass = Ember.CoreView.detect(emptyView);

      emptyView = this.createChildView(emptyView);
      addedViews.push(emptyView);
      set(this, 'emptyView', emptyView);

      if (isClass) { this._createdEmptyView = emptyView; }
    }
    this.replace(start, 0, addedViews);
  },

  createChildView: function(view, attrs) {
    view = this._super(view, attrs);

    var itemTagName = get(view, 'tagName');
    var tagName = (itemTagName === null || itemTagName === undefined) ? Ember.CollectionView.CONTAINER_MAP[get(this, 'tagName')] : itemTagName;

    set(view, 'tagName', tagName);

    return view;
  }
});

/**
  A map of parent tags to their default child tags. You can add
  additional parent tags if you want collection views that use
  a particular parent tag to default to a child tag.

  @property CONTAINER_MAP
  @type Hash
  @static
  @final
*/
Ember.CollectionView.CONTAINER_MAP = {
  ul: 'li',
  ol: 'li',
  table: 'tr',
  thead: 'tr',
  tbody: 'tr',
  tfoot: 'tr',
  tr: 'td',
  select: 'option'
};
<|endoftext|>


<commit_before>/* global  */
'use strict';

const lib = (function () {
  const urlData = 'https://api.codetabs.com/geoip/json';

  function fetchDataFromServer (urlData, callback) {
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) { // 4 = "DONE"
        if (xhr.status === 200) { // 200 ="OK"
          try {
            callback(JSON.parse(xhr.responseText));
          } catch (e) {
            console.log('Error parsing Json => ', e);
            callback({});
          }
        } else {
          console.log('Error: ' + xhr.status);
        }
      }
    };
    xhr.open('GET', urlData); // add false to synchronous request
    xhr.send();
  }

  function makeAjaxRequest (url, action, params, sendCookie , callback) {
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) { // 4 = "DONE"
        if (xhr.status === 200) { // 200 ="OK"
          if (action === 'GET' || action === 'POST') {
            try {
              callback(JSON.parse(xhr.responseText));
            } catch (e) {
              console.log('Error parsing Json => ', e);
              callback({});
            }
          } else {
            callback(xhr.status);
          }
        } else {
          console.log('Error: ' + xhr.status);
        }
      }
    };
    xhr.open(action, url);
    if (sendCookie) {
      xhr.withCredentials = true; // allow send cookies
    }
    if (action === 'GET') {
      xhr.send();
    } else if (action !== 'GET') {
      xhr.setRequestHeader('Content-Type',
        'application/x-www-form-urlencoded; charset=UTF-8');
      if (params) {
        xhr.send(params);
      } else {
        xhr.send();
      }
    // console.log('Request Sent')
    }
  }

  return {
    fetchDataFromServer: fetchDataFromServer,
    urlData: urlData,
    makeAjaxRequest: makeAjaxRequest
  };
})();
<commit_msg>geoip location change<commit_after>/* global  */
'use strict';

const lib = (function () {
  const urlData = 'https://geoip.tools/v1/json';

  function fetchDataFromServer (urlData, callback) {
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) { // 4 = "DONE"
        if (xhr.status === 200) { // 200 ="OK"
          try {
            callback(JSON.parse(xhr.responseText));
          } catch (e) {
            console.log('Error parsing Json => ', e);
            callback({});
          }
        } else {
          console.log('Error: ' + xhr.status);
        }
      }
    };
    xhr.open('GET', urlData); // add false to synchronous request
    xhr.send();
  }

  function makeAjaxRequest (url, action, params, sendCookie , callback) {
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) { // 4 = "DONE"
        if (xhr.status === 200) { // 200 ="OK"
          if (action === 'GET' || action === 'POST') {
            try {
              callback(JSON.parse(xhr.responseText));
            } catch (e) {
              console.log('Error parsing Json => ', e);
              callback({});
            }
          } else {
            callback(xhr.status);
          }
        } else {
          console.log('Error: ' + xhr.status);
        }
      }
    };
    xhr.open(action, url);
    if (sendCookie) {
      xhr.withCredentials = true; // allow send cookies
    }
    if (action === 'GET') {
      xhr.send();
    } else if (action !== 'GET') {
      xhr.setRequestHeader('Content-Type',
        'application/x-www-form-urlencoded; charset=UTF-8');
      if (params) {
        xhr.send(params);
      } else {
        xhr.send();
      }
    // console.log('Request Sent')
    }
  }

  return {
    fetchDataFromServer: fetchDataFromServer,
    urlData: urlData,
    makeAjaxRequest: makeAjaxRequest
  };
})();
<|endoftext|>


<commit_before>/*jshint expr: true*/
let expect = require('chai').expect;
let LocalQuery = require('../lib/providers/query/LocalQuery');

describe('LocalQuery', () => {
  it('handles null results', (done) => {
      let aQuery = new LocalQuery({
        store: {
          '$ParcelTrackerS1' : {
            'muppet': []
          }
        }
      }, '$ParcelTrackerS1', 310);
      aQuery.setOQL('snuffalupagos');
      let results = aQuery.execute();
      expect(results.hasResults).to.be.false;
      done();
  });
});
<commit_msg>fixing uCase<commit_after>/*jshint expr: true*/
let expect = require('chai').expect;
let LocalQuery = require('../lib/providers/query/localquery');

describe('LocalQuery', () => {
  it('handles null results', (done) => {
      let aQuery = new LocalQuery({
        store: {
          '$ParcelTrackerS1' : {
            'muppet': []
          }
        }
      }, '$ParcelTrackerS1', 310);
      aQuery.setOQL('snuffalupagos');
      let results = aQuery.execute();
      expect(results.hasResults).to.be.false;
      done();
  });
});
<|endoftext|>


<commit_before>/**
 * 抽象我们的数据中心
 *
 * 其实是非常的的简单，就像flux架构，只是一些规约，根本不是很厚很重的框架代码，
 * 我们要做的就是更好在我们的应用和数据之间更好的粘合
 */
var Immutable = require('immutable');
var Cursor = require('immutable/contrib/cursor');
var msg = require('./msg');

/**
 * 抽象数据对象
 */
var Store = module.exports = function (obj) {
  this.store = Immutable.fromJS(obj);
};

/**
 * 获取immutable数据
 */
Store.prototype.data = function () {
  return this.store;
};

/**
 * 获取immutable的数据部分数据，统一get，和getIn
 * 通过参数自动判断
 */
Store.prototype.get = function (path) {
  var isArray = Array.isArray(path);
  return this.store[isArray ? 'getIn' : 'get'](path);
};

/**
 * 获取整个应用数据的cursor，所有的数据更新只能通过cursor去更新
 */
Store.prototype.cursor = function () {
  var onStoreChange = function (nextStore, preStore, cursorPath) {
    if (preStore != this.store) {
      throw new Error('attemped to alter expired data.');
    }
    this.store = nextStore;
    //整个应用的画龙点睛之处
    msg.emit('onStoreChange', this.store, cursorPath);
  }.bind(this);

  return Cursor.from(this.store, onStoreChange);
};
<commit_msg>add log<commit_after>/**
 * 抽象我们的数据中心
 *
 * 其实是非常的的简单，就像flux架构，只是一些规约，根本不是很厚很重的框架代码，
 * 我们要做的就是更好在我们的应用和数据之间更好的粘合
 */
var Immutable = require('immutable');
var Cursor = require('immutable/contrib/cursor');
var msg = require('./msg');

/**
 * 抽象数据对象
 */
var Store = module.exports = function (obj) {
  this.store = Immutable.fromJS(obj);
};

/**
 * 获取immutable数据
 */
Store.prototype.data = function () {
  return this.store;
};

/**
 * 获取immutable的数据部分数据，统一get，和getIn
 * 通过参数自动判断
 */
Store.prototype.get = function (path) {
  var isArray = Array.isArray(path);
  return this.store[isArray ? 'getIn' : 'get'](path);
};

/**
 * 获取整个应用数据的cursor，所有的数据更新只能通过cursor去更新
 */
Store.prototype.cursor = function () {
  console.log('cursorPath->', cursorPath);
  console.log('nextStore->', nextStore.toString());

  var onStoreChange = function (nextStore, preStore, cursorPath) {
    if (preStore != this.store) {
      throw new Error('attemped to alter expired data.');
    }
    this.store = nextStore;
    //整个应用的画龙点睛之处
    msg.emit('onStoreChange', this.store, cursorPath);
  }.bind(this);

  return Cursor.from(this.store, onStoreChange);
};
<|endoftext|>


<commit_before>module.exports = function (config) {
  const configuration = {
    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    frameworks: ['jasmine', 'karma-typescript'],

    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-spec-reporter'),
      require('karma-typescript'),
    ],

    files: [
      './index.ts',
      './public_api.ts',
      './base.spec.ts',
      './src/**/*.ts',
      './validation/**/*.ts',
    ],

    exclude: [
    ],

    preprocessors: {
      './index.ts': ['karma-typescript'],
      './public_api.ts': ['karma-typescript'],
      './base.spec.ts': ['karma-typescript'],
      './src/**/*.ts': ['karma-typescript'],
      './validation/src/**/*.ts': ['karma-typescript'],
    },

    karmaTypescriptConfig: {
      bundlerOptions: {
        entrypoints: /\.spec\.(ts|tsx)$/,
        resolve: {
          extensions: ['.js', '.json', '.ts'],
          directories: ['node_modules', '.']
        },
        transforms: [require('karma-typescript-es6-transform')()],
        validateSyntax: true,
      },
      tsconfig: './tsconfig.spec.json',
      reports:
      {
        lcovonly: {
          directory: 'coverage',
          filename: 'lcov.info',
          subdirectory: 'lcov'
        },
        html: 'coverage',
        'text-summary': ''
      }
    },

    reporters: ['progress', 'karma-typescript'],

    specReporter: {
      maxLogLines: 10,
      suppressErrorSummary: true,
      suppressFailed: false,
      suppressPassed: true,
      suppressSkipped: true,
      showSpecTiming: false,
      failFast: false,
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['Chrome'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,
  };

  config.set(configuration);
};

<commit_msg>chore: use chrome headless for running tests<commit_after>module.exports = function (config) {
  const configuration = {
    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    frameworks: ['jasmine', 'karma-typescript'],

    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-spec-reporter'),
      require('karma-typescript'),
    ],

    files: [
      './index.ts',
      './public_api.ts',
      './base.spec.ts',
      './src/**/*.ts',
      './validation/**/*.ts',
    ],

    exclude: [
    ],

    preprocessors: {
      './index.ts': ['karma-typescript'],
      './public_api.ts': ['karma-typescript'],
      './base.spec.ts': ['karma-typescript'],
      './src/**/*.ts': ['karma-typescript'],
      './validation/src/**/*.ts': ['karma-typescript'],
    },

    karmaTypescriptConfig: {
      bundlerOptions: {
        entrypoints: /\.spec\.(ts|tsx)$/,
        resolve: {
          extensions: ['.js', '.json', '.ts'],
          directories: ['node_modules', '.']
        },
        transforms: [require('karma-typescript-es6-transform')()],
        validateSyntax: true,
      },
      tsconfig: './tsconfig.spec.json',
      reports:
      {
        lcovonly: {
          directory: 'coverage',
          filename: 'lcov.info',
          subdirectory: 'lcov'
        },
        html: 'coverage',
        'text-summary': ''
      }
    },

    reporters: ['progress', 'karma-typescript'],

    specReporter: {
      maxLogLines: 10,
      suppressErrorSummary: true,
      suppressFailed: false,
      suppressPassed: true,
      suppressSkipped: true,
      showSpecTiming: false,
      failFast: false,
    },

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['ChromeHeadless'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,
  };

  config.set(configuration);
};

<|endoftext|>