<commit_before>import { expect } from 'chai'
import fs from 'fs-extra'
import path from 'path'
import jsdom from 'jsdom'
import sagui, { InvalidSaguiConfig } from '../../src'
import actions from '../../src/actions'
import temp from 'temp'

// make sure the temp folders are cleaned up
temp.track()

/**
 * Simulate a complete install of Sagui in a target folder.
 *
 * It symlinks all the dependencies in place
 * and copies the require Sagui files.
 */
const npmInstall = (projectPath) => {
  const nodeModules = path.join(__dirname, '../../node_modules')
  const packages = fs.readdirSync(nodeModules)

  packages.forEach((name) => fs.ensureSymlinkSync(path.join(nodeModules, name), path.join(projectPath, 'node_modules', name)))

  const saguiInNodeModules = path.join(projectPath, 'node_modules/sagui/karma-static-files')
  fs.ensureDirSync(saguiInNodeModules)
  fs.copySync(path.join(__dirname, '../../karma-static-files'), saguiInNodeModules)
}

describe('[integration] sagui', function () {
  const projectFixture = path.join(__dirname, '../fixtures/simple-project')
  const projectContent = path.join(__dirname, '../fixtures/project-content')
  const projectContentWithLintErrors = path.join(__dirname, '../fixtures/project-content-with-lint-errors')
  let projectPath, projectSrcPath

  beforeEach(function () {
    projectPath = temp.mkdirSync('sagui-test-project')
    projectSrcPath = path.join(projectPath, 'src')

    npmInstall(projectPath)
    fs.copySync(projectFixture, projectPath)
  })

  describe('after update', () => {
    beforeEach(() => {
      return sagui({ projectPath, action: actions.UPDATE })
    })

    it('should be possible to build', () => {
      return sagui({ projectPath, action: actions.BUILD })
    })

    it('should be possible to test', () => {
      return sagui({ projectPath, action: actions.TEST_UNIT })
    })

    it('should be possible to test (with coverage)', () => {
      return sagui({ projectPath, action: actions.TEST_UNIT, coverage: true })
    })

    it('should have an .gitignore, .flowconfig and .editorconfig file', () => {
      fs.readFileSync(path.join(projectPath, '.gitignore'))
      fs.readFileSync(path.join(projectPath, '.flowconfig'))
      fs.readFileSync(path.join(projectPath, '.editorconfig'))
    })

    describe('once we add content', () => {
      beforeEach(function () {
        fs.copySync(projectContent, projectSrcPath, { overwrite: true })
      })

      it('should be possible to build', () => {
        return sagui({ projectPath, action: actions.BUILD })
      })

      it('should be possible to test more files', () => {
        return sagui({ projectPath, action: actions.TEST_UNIT })
      })

      it('should be possible to keep updating Sagui', () => {
        return sagui({ projectPath, action: actions.UPDATE })
      })
    })

    describe('project with transpile dependencies', () => {
      const projectWithTranspileDependencies = path.join(__dirname, '../fixtures/project-with-transpile-dependencies')
      beforeEach(function () {
        fs.copySync(projectWithTranspileDependencies, projectPath, { overwrite: true })
      })

      it('should be possible to build', () => {
        return sagui({ projectPath, action: actions.BUILD })
      })

      it('should be possible to test', () => {
        return sagui({ projectPath, action: actions.TEST_UNIT })
      })
    })

    describe('project with invalid configuration', () => {
      const projectWithInvalidConfig = path.join(__dirname, '../fixtures/project-with-invalid-config')
      beforeEach(function () {
        fs.copySync(projectWithInvalidConfig, projectPath, { overwrite: true })
      })

      it('should not be possible to build', () => {
        return sagui({ projectPath, action: actions.BUILD })
          .then(
            () => new Error('It should have failed'),
            (error) => expect(error).instanceof(InvalidSaguiConfig)
          )
      })
    })

    describe('style loader', () => {
      const projectWithCSSModules = path.join(__dirname, '../fixtures/project-with-css-modules')
      const htmlFile = path.join(__dirname, '../fixtures/index.html')

      beforeEach((done) => {
        fs.copySync(projectWithCSSModules, projectPath, { overwrite: true })

        jsdom.env(htmlFile, (err, window) => {
          global.window = window
          global.document = window.document
          done()
        });
      })

      afterEach(() => {
        global.window.close()
        delete global.window
        delete global.document
      })

      it('should build with the unique CSS Modules keys', () => {
        return sagui({ projectPath, action: actions.BUILD }).then(() => {
          const dist = require(path.join(projectPath, '/dist/index')).default

          expect(dist.componentA).to.match(/content-.{5}/)
          expect(dist.componentB).to.match(/content-.{5}/)
          expect(dist.componentA).not.to.eql(dist.componentB)
        })
      })

      it('should build (optimized) with the unique CSS Modules keys', () => {
        return sagui({ projectPath, action: actions.BUILD, optimize: true }).then(() => {
          const dist = require(path.join(projectPath, '/dist/index')).default

          expect(dist.componentA).to.match(/_.{5}/)
          expect(dist.componentB).to.match(/_.{5}/)
          expect(dist.componentA).not.to.eql(dist.componentB)
        })
      })

      it('should autoprefix CSS rules', () => {
        return sagui({ projectPath, action: actions.BUILD }).then(() => {
          const dist = fs.readFileSync(path.join(projectPath, '/dist/index.js'))

          expect(dist).to.match(/-ms-flex/)
        })
      })
    })

    describe('once we add content with lint errors', () => {
      beforeEach(function () {
        fs.copySync(projectContentWithLintErrors, projectSrcPath, { overwrite: true })
      })

      it('should break the build build', () => {
        return sagui({ projectPath, action: actions.BUILD })
          .then(
            () => new Error('It should have failed'),
            (error) => expect(error.message).to.eql('Build failed')
          )
      })
    })
  })
})
<commit_msg>Weirdly, sometimes we get an `_` and sometimes not in the small class hashes 😕<commit_after>import { expect } from 'chai'
import fs from 'fs-extra'
import path from 'path'
import jsdom from 'jsdom'
import sagui, { InvalidSaguiConfig } from '../../src'
import actions from '../../src/actions'
import temp from 'temp'

// make sure the temp folders are cleaned up
temp.track()

/**
 * Simulate a complete install of Sagui in a target folder.
 *
 * It symlinks all the dependencies in place
 * and copies the require Sagui files.
 */
const npmInstall = (projectPath) => {
  const nodeModules = path.join(__dirname, '../../node_modules')
  const packages = fs.readdirSync(nodeModules)

  packages.forEach((name) => fs.ensureSymlinkSync(path.join(nodeModules, name), path.join(projectPath, 'node_modules', name)))

  const saguiInNodeModules = path.join(projectPath, 'node_modules/sagui/karma-static-files')
  fs.ensureDirSync(saguiInNodeModules)
  fs.copySync(path.join(__dirname, '../../karma-static-files'), saguiInNodeModules)
}

describe('[integration] sagui', function () {
  const projectFixture = path.join(__dirname, '../fixtures/simple-project')
  const projectContent = path.join(__dirname, '../fixtures/project-content')
  const projectContentWithLintErrors = path.join(__dirname, '../fixtures/project-content-with-lint-errors')
  let projectPath, projectSrcPath

  beforeEach(function () {
    projectPath = temp.mkdirSync('sagui-test-project')
    projectSrcPath = path.join(projectPath, 'src')

    npmInstall(projectPath)
    fs.copySync(projectFixture, projectPath)
  })

  describe('after update', () => {
    beforeEach(() => {
      return sagui({ projectPath, action: actions.UPDATE })
    })

    it('should be possible to build', () => {
      return sagui({ projectPath, action: actions.BUILD })
    })

    it('should be possible to test', () => {
      return sagui({ projectPath, action: actions.TEST_UNIT })
    })

    it('should be possible to test (with coverage)', () => {
      return sagui({ projectPath, action: actions.TEST_UNIT, coverage: true })
    })

    it('should have an .gitignore, .flowconfig and .editorconfig file', () => {
      fs.readFileSync(path.join(projectPath, '.gitignore'))
      fs.readFileSync(path.join(projectPath, '.flowconfig'))
      fs.readFileSync(path.join(projectPath, '.editorconfig'))
    })

    describe('once we add content', () => {
      beforeEach(function () {
        fs.copySync(projectContent, projectSrcPath, { overwrite: true })
      })

      it('should be possible to build', () => {
        return sagui({ projectPath, action: actions.BUILD })
      })

      it('should be possible to test more files', () => {
        return sagui({ projectPath, action: actions.TEST_UNIT })
      })

      it('should be possible to keep updating Sagui', () => {
        return sagui({ projectPath, action: actions.UPDATE })
      })
    })

    describe('project with transpile dependencies', () => {
      const projectWithTranspileDependencies = path.join(__dirname, '../fixtures/project-with-transpile-dependencies')
      beforeEach(function () {
        fs.copySync(projectWithTranspileDependencies, projectPath, { overwrite: true })
      })

      it('should be possible to build', () => {
        return sagui({ projectPath, action: actions.BUILD })
      })

      it('should be possible to test', () => {
        return sagui({ projectPath, action: actions.TEST_UNIT })
      })
    })

    describe('project with invalid configuration', () => {
      const projectWithInvalidConfig = path.join(__dirname, '../fixtures/project-with-invalid-config')
      beforeEach(function () {
        fs.copySync(projectWithInvalidConfig, projectPath, { overwrite: true })
      })

      it('should not be possible to build', () => {
        return sagui({ projectPath, action: actions.BUILD })
          .then(
            () => new Error('It should have failed'),
            (error) => expect(error).instanceof(InvalidSaguiConfig)
          )
      })
    })

    describe('style loader', () => {
      const projectWithCSSModules = path.join(__dirname, '../fixtures/project-with-css-modules')
      const htmlFile = path.join(__dirname, '../fixtures/index.html')

      beforeEach((done) => {
        fs.copySync(projectWithCSSModules, projectPath, { overwrite: true })

        jsdom.env(htmlFile, (err, window) => {
          global.window = window
          global.document = window.document
          done()
        });
      })

      afterEach(() => {
        global.window.close()
        delete global.window
        delete global.document
      })

      it('should build with the unique CSS Modules keys', () => {
        return sagui({ projectPath, action: actions.BUILD }).then(() => {
          const dist = require(path.join(projectPath, '/dist/index')).default

          expect(dist.componentA).to.match(/content-.{5}/)
          expect(dist.componentB).to.match(/content-.{5}/)
          expect(dist.componentA).not.to.eql(dist.componentB)
        })
      })

      it('should build (optimized) with the unique CSS Modules keys', () => {
        return sagui({ projectPath, action: actions.BUILD, optimize: true }).then(() => {
          const dist = require(path.join(projectPath, '/dist/index')).default

          expect(dist.componentA).to.match(/^.{5,6}$/)
          expect(dist.componentB).to.match(/^.{5,6}$/)
          expect(dist.componentA).not.to.eql(dist.componentB)
        })
      })

      it('should autoprefix CSS rules', () => {
        return sagui({ projectPath, action: actions.BUILD }).then(() => {
          const dist = fs.readFileSync(path.join(projectPath, '/dist/index.js'))

          expect(dist).to.match(/-ms-flex/)
        })
      })
    })

    describe('once we add content with lint errors', () => {
      beforeEach(function () {
        fs.copySync(projectContentWithLintErrors, projectSrcPath, { overwrite: true })
      })

      it('should break the build build', () => {
        return sagui({ projectPath, action: actions.BUILD })
          .then(
            () => new Error('It should have failed'),
            (error) => expect(error.message).to.eql('Build failed')
          )
      })
    })
  })
})
<|endoftext|>


<commit_before>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule fetchWithRetries
 * @typechecks
 * @flow
 */

'use strict';

var ExecutionEnvironment = require('ExecutionEnvironment');
var Promise = require('Promise');

var sprintf = require('sprintf');
var fetch = require('fetch');
var warning = require('warning');

type InitWithRetries = {
  body?: mixed;
  cache?: ?string;
  credentials?: ?string;
  fetchTimeout?: ?number;
  headers?: mixed;
  method?: ?string;
  mode?: ?string;
  retryDelays?: ?Array<number>;
};

var DEFAULT_FETCH_TIMEOUT = 15000;
var DEFAULT_RETRY_DELAYS = [1000, 3000];

/**
 * Posts a request to the server with the given data as the payload.
 * Automatic retries are done based on the values in `retryDelays`.
 */
function fetchWithRetries(
  uri: string,
  initWithRetries: InitWithRetries
): Promise {
  var {fetchTimeout, retryDelays, ...init} = initWithRetries;
  var nonNullFetchTimeout = fetchTimeout || DEFAULT_FETCH_TIMEOUT;
  var nonNullRetryDelays = retryDelays || DEFAULT_RETRY_DELAYS;

  var requestsAttempted = 0;
  var requestStartTime = 0;
  return new Promise((resolve, reject) => {
    /**
     * Sends a request to the server that will timeout after `fetchTimeout`.
     * If the request fails or times out a new request might be scheduled.
     */
    function sendTimedRequest(): void {
      requestsAttempted++;
      requestStartTime = Date.now();
      var isRequestAlive = true;
      var request = fetch(uri, init);
      var requestTimeout = setTimeout(() => {
        isRequestAlive = false;
        if (shouldRetry(requestsAttempted)) {
          warning(false, 'fetchWithRetries: HTTP timeout, retrying.');
          retryRequest();
        } else {
          reject(new Error(sprintf(
            'fetchWithRetries(): Failed to get response from server, ' +
            'tried %s times.',
            requestsAttempted
          )));
        }
      }, nonNullFetchTimeout);

      request.then(response => {
        clearTimeout(requestTimeout);
        if (isRequestAlive) {
          // We got a response, we can clear the timeout.
          if (response.status >= 200 && response.status < 300) {
            // Got a response code that indicates success, resolve the promise.
            resolve(response);
          } else if (shouldRetry(requestsAttempted)) {
            // Fetch was not successful, retrying.
            // TODO(#7595849): Only retry on transient HTTP errors.
            warning(false, 'fetchWithRetries: HTTP error, retrying.'),
            retryRequest();
          } else {
            // Request was not successful, giving up.
            reject(response);
          }
        }
      }).catch(error => {
        clearTimeout(requestTimeout);
        if (shouldRetry(requestsAttempted)) {
          retryRequest();
        } else {
          reject(error);
        }
      });
    }

    /**
     * Schedules another run of sendTimedRequest based on how much time has
     * passed between the time the last request was sent and now.
     */
    function retryRequest(): void {
      var retryDelay = nonNullRetryDelays[requestsAttempted - 1];
      var retryStartTime = requestStartTime + retryDelay;
      // Schedule retry for a configured duration after last request started.
      setTimeout(sendTimedRequest, retryStartTime - Date.now());
    }

    /**
     * Checks if another attempt should be done to send a request to the server.
     */
    function shouldRetry(attempt: number): boolean {
      return (
        ExecutionEnvironment.canUseDOM &&
        attempt <= nonNullRetryDelays.length
      );
    }

    sendTimedRequest();
  });
}

module.exports = fetchWithRetries;
<commit_msg>Make `init` optional in `fetchWithRetries`<commit_after>/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule fetchWithRetries
 * @typechecks
 * @flow
 */

'use strict';

var ExecutionEnvironment = require('ExecutionEnvironment');
var Promise = require('Promise');

var sprintf = require('sprintf');
var fetch = require('fetch');
var warning = require('warning');

type InitWithRetries = {
  body?: mixed;
  cache?: ?string;
  credentials?: ?string;
  fetchTimeout?: ?number;
  headers?: mixed;
  method?: ?string;
  mode?: ?string;
  retryDelays?: ?Array<number>;
};

var DEFAULT_FETCH_TIMEOUT = 15000;
var DEFAULT_RETRY_DELAYS = [1000, 3000];

/**
 * Makes a POST request to the server with the given data as the payload.
 * Automatic retries are done based on the values in `retryDelays`.
 */
function fetchWithRetries(
  uri: string,
  initWithRetries?: ?InitWithRetries
): Promise {
  var {fetchTimeout, retryDelays, ...init} = initWithRetries || {};
  var nonNullFetchTimeout = fetchTimeout || DEFAULT_FETCH_TIMEOUT;
  var nonNullRetryDelays = retryDelays || DEFAULT_RETRY_DELAYS;

  var requestsAttempted = 0;
  var requestStartTime = 0;
  return new Promise((resolve, reject) => {
    /**
     * Sends a request to the server that will timeout after `fetchTimeout`.
     * If the request fails or times out a new request might be scheduled.
     */
    function sendTimedRequest(): void {
      requestsAttempted++;
      requestStartTime = Date.now();
      var isRequestAlive = true;
      var request = fetch(uri, init);
      var requestTimeout = setTimeout(() => {
        isRequestAlive = false;
        if (shouldRetry(requestsAttempted)) {
          warning(false, 'fetchWithRetries: HTTP timeout, retrying.');
          retryRequest();
        } else {
          reject(new Error(sprintf(
            'fetchWithRetries(): Failed to get response from server, ' +
            'tried %s times.',
            requestsAttempted
          )));
        }
      }, nonNullFetchTimeout);

      request.then(response => {
        clearTimeout(requestTimeout);
        if (isRequestAlive) {
          // We got a response, we can clear the timeout.
          if (response.status >= 200 && response.status < 300) {
            // Got a response code that indicates success, resolve the promise.
            resolve(response);
          } else if (shouldRetry(requestsAttempted)) {
            // Fetch was not successful, retrying.
            // TODO(#7595849): Only retry on transient HTTP errors.
            warning(false, 'fetchWithRetries: HTTP error, retrying.'),
            retryRequest();
          } else {
            // Request was not successful, giving up.
            reject(response);
          }
        }
      }).catch(error => {
        clearTimeout(requestTimeout);
        if (shouldRetry(requestsAttempted)) {
          retryRequest();
        } else {
          reject(error);
        }
      });
    }

    /**
     * Schedules another run of sendTimedRequest based on how much time has
     * passed between the time the last request was sent and now.
     */
    function retryRequest(): void {
      var retryDelay = nonNullRetryDelays[requestsAttempted - 1];
      var retryStartTime = requestStartTime + retryDelay;
      // Schedule retry for a configured duration after last request started.
      setTimeout(sendTimedRequest, retryStartTime - Date.now());
    }

    /**
     * Checks if another attempt should be done to send a request to the server.
     */
    function shouldRetry(attempt: number): boolean {
      return (
        ExecutionEnvironment.canUseDOM &&
        attempt <= nonNullRetryDelays.length
      );
    }

    sendTimedRequest();
  });
}

module.exports = fetchWithRetries;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  name: 'RPCReturnBox',
  package: 'foam.swift.box',
  implements: ['foam.box.Box'],
  requires: [
    'foam.box.RPCReturnMessage'
  ],
  properties: [
    {
      swiftType: 'Future<Any?>',
      name: 'future',
      swiftFactory: 'return Future()',
    },
  ],
  methods: [
    {
      name: 'send',
      swiftCode: function() {/*
if let o = msg.object as? RPCReturnMessage {
  future.set(o.data)
  return
}
future.error(FoamError(msg.object))
      */},
    },
  ],
});
<commit_msg>Cleanup.<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  name: 'RPCReturnBox',
  package: 'foam.swift.box',
  implements: [ 'foam.box.Box' ],

  requires: [
    'foam.box.RPCReturnMessage'
  ],

  properties: [
    {
      swiftType: 'Future<Any?>',
      name: 'future',
      swiftFactory: 'return Future()'
    }
  ],

  methods: [
    {
      name: 'send',
      swiftCode: `
if let o = msg.object as? RPCReturnMessage {
  future.set(o.data)
  return
}
future.error(FoamError(msg.object))
      `
    }
  ]
});
<|endoftext|>


<commit_before>'use strict';

const hjson = require('hjson');

// Parses a HJSON file
const parse = function ({ content }) {
  return hjson.parse(content);
};

// Serializes a HJSON file
const serialize = function ({ content }) {
  return hjson.stringify(content, { bracesSameLine: true });
};

module.exports = {
  name: 'hjson',
  title: 'Hjson',
  types: ['conf', 'payload', 'db'],
  extNames: ['hjson'],
  mimes: ['application/hjson', 'text/hjson'],
  mimeExtensions: ['+hjson'],
  charsets: ['utf-8'],
  jsonCompat: ['superset'],
  parse,
  serialize,
};
<commit_msg>Hjson is a type-wise superset of JSON<commit_after>'use strict';

const hjson = require('hjson');

// Parses a HJSON file
const parse = function ({ content }) {
  return hjson.parse(content);
};

// Serializes a HJSON file
const serialize = function ({ content }) {
  return hjson.stringify(content, { bracesSameLine: true });
};

module.exports = {
  name: 'hjson',
  title: 'Hjson',
  types: ['conf', 'payload', 'db'],
  extNames: ['hjson'],
  mimes: ['application/hjson', 'text/hjson'],
  mimeExtensions: ['+hjson'],
  charsets: ['utf-8'],
  jsonCompat: [],
  parse,
  serialize,
};
<|endoftext|>


<commit_before>var methods = ['GET', 'POST', 'HEAD', 'PUT', 'DEL', 'PATCH', 'OPTS'];

var Base = function(app) {
	this.route = null;
	this.setup(app);
	this.routeSetup(app);
};

Base.prototype = {
	setup : function(app) {
		throw new Error('Please implement setup');
	},
	routeSetup: function(app) {
		var self = this, supportedMethods = [];
		if (self.route) {
			methods.forEach(function(method) {
				var lMethod = method.toLowerCase();
				if (typeof self[method] === 'function') {
					app[lMethod](self.route, self[method].bind(self));
					supportedMethods.push(method);
				} else if (typeof self[lMethod] === 'function') {
					app[lMethod](self.route, self[lMethod].bind(self));
					supportedMethods.push(method);
				}
			});

			if (supportedMethods.length < 1) {
				console.log(self.route, 'specified as route but no match for any method: ', methods.join(', '));
			} else {
				app['opts'](self.route, function(req, res, next) {
					res.header('Allow', supportedMethods.join(', '));
					return res.send(200, {});
				});
			}
		}
	}
};

module.exports = Base;
<commit_msg>Create default options response only if there is not one.<commit_after>var methods = ['GET', 'POST', 'HEAD', 'PUT', 'DEL', 'PATCH', 'OPTS'];

var Base = function(app) {
	this.route = null;
	this.setup(app);
	this.routeSetup(app);
};

Base.prototype = {
	setup : function(app) {
		throw new Error('Please implement setup');
	},
	routeSetup: function(app) {
		var self = this, supportedMethods = [];
		if (self.route) {
			methods.forEach(function(method) {
				var lMethod = method.toLowerCase();
				if (typeof self[method] === 'function') {
					app[lMethod](self.route, self[method].bind(self));
					supportedMethods.push(method);
				} else if (typeof self[lMethod] === 'function') {
					app[lMethod](self.route, self[lMethod].bind(self));
					supportedMethods.push(method);
				}
			});

			if (supportedMethods.length < 1) {
				console.log(self.route, 'specified as route but no match for any method: ', methods.join(', '));
			} else {
				if (supportedMethods.indexOf('OPTS') != -1) {
					app['opts'](self.route, function(req, res, next) {
						res.header('Allow', supportedMethods.join(', '));
						return res.send(200, {});
					});
				}
			}
		}
	}
};

module.exports = Base;
<|endoftext|>


<commit_before>// import _ from 'lodash'
import React, { Component } from 'react';
import {
  // Button,
  Form,
  // Grid,
  Header,
  // Segment, Step, Card, Icon, Checkbox, Divider, Radio,
  Statistic,
  Divider,
  // Reveal,
  Input
} from 'semantic-ui-react';
// import { Redirect, Prompt } from 'react-router-dom';
// import { percentPovertyLevel,
//         percentStateMedianIncome } from '../helpers/helperFunctions';
import {
  FormPartsContainer, MassiveToggle, FormHeading,
  IntervalColumnHeadings, CashFlowRow
} from './formHelpers';
import { merge } from '../helpers/object-manipulation';
import { roundMoney, limit } from '../helpers/math';

// ========================================
// COMPONENTS
// ========================================

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const Housing = function ( props ) {

  var client      = props.props.pageState,
      time        = props.time,
      storeBool   = props.props.storeBoolean,
      sharedProps = {
        client: client, type: props.type, time: time,
        storeComplex: props.props.storeComplex
      };

  // `hasHousing` is actually whether they're in the housing voucher program
  var ownedAHome  = client.previousHomeowner,
      wasHomeless = client.previousHomeless && !client.hasHousing && !ownedAHome;

  var utils = client.previousPaidUtilities, climate = client.previousGotClimateControl,
      electricity = client.previousNonHeatElectricity, phone = client.previousTelephone;

  /** @todo Owning a home vs. renting vs. homeless should probably be radio buttons */
  return (
    <wrapper>
      <FormHeading>Housing</FormHeading>

      <MassiveToggle id={ time + 'Homeless' } value={ wasHomeless } storeBoolean={ storeBool }
          label={'Was the household homeless at the last benefit assessment?'}/>
      { wasHomeless
        ? null
        : <MassiveToggle id={ time + 'Homeowner' } value={ ownedAHome }
            storeBoolean={ storeBool } label={ 'Did the household own a home?' } />
      }
      { ownedAHome
        ? <wrapper>
            <IntervalColumnHeadings type={ props.type }/>
            <CashFlowRow {...merge( sharedProps, {generic: 'RentOrMortgage'} )}> Mortgage </CashFlowRow>
            <CashFlowRow {...merge( sharedProps, {generic: 'HousingInsurance'} )}> Insurance Costs </CashFlowRow>
            <CashFlowRow {...merge( sharedProps, {generic: 'PropertyTax'} )}> Property Tax </CashFlowRow>
          </wrapper>
        : <wrapper> { wasHomeless
          ? null
          : <wrapper>
            <IntervalColumnHeadings type={ props.type }/>
            <CashFlowRow {...merge( sharedProps, {generic: 'RentOrMortgage'} )}> Rent </CashFlowRow>
            <MassiveToggle id={ time + 'PaidUtilities' } value={ utils } storeBoolean={ storeBool }
              label={'Did the household pay utilities seperately from the rent?'}/>
            { !client.previousPaidUtilities
              ? null
              : <wrapper>
                  <MassiveToggle id={ time + 'ClimateControl' } value={ climate } storeBoolean={ storeBool }
                    label={'Did the household pay for heating or cooling (e.g. A/C during summer), OR did they receive Fuel Assistance in the 12 months prior to the previous benefit assessment?'}/>
                  <MassiveToggle id={ time + 'NonHeatElectricity' } value={ electricity } storeBoolean={ storeBool }
                    label={'Did the household pay for electricity for non-heating purposes?'}/>
                  <MassiveToggle id={ time + 'Telephone' } value={ phone } storeBoolean={ storeBool }
                    label={'Did the household pay for its own telephone service?'}/>
                </wrapper>
            } </wrapper>
        } </wrapper>
    } </wrapper>
  );

};  // End Housing()

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const ExpensesFormContent = function ( props ) {

  var client    = props.client,
      storeBool = props.props.storeBoolean;

  var needsMedical = client.previousDisabledOrElderlyMember;

  var time = 'previous', type = 'expense';
  var sharedProps = { client: client, type: type, time: time,
                    storeComplex: props.props.storeComplex };

  return (
    <wrapper className='field-aligner two-column'>

      <FormHeading subheading = {'(a dependant is a child or disabled adult)'}>
        Dependent Monthly Care</FormHeading>
      <IntervalColumnHeadings type={type}/>
      <CashFlowRow {...merge( sharedProps, {generic: 'DirectCareCosts'} )}> Direct Care Costs </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'BeforeAndAfterSchoolPrograms'} )}> Before- and After-School Programs </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'TransportationCosts'} )}> Transportation Costs </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'OtherDependentCareCosts'} )}> Other </CashFlowRow>

      <Housing props={props.props} time={time} type={type} />

      <FormHeading>Other</FormHeading>
      <CashFlowRow {...merge( sharedProps, {generic: 'Medical'} )}>Medical</CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'ChildSupportPaidOut'} )}>LEGALLY OBLIGATED Child support paid out</CashFlowRow>

    </wrapper>
  );

};  // End ExpensesFormContent()

// If medical is only for disabled or elderly
// <MassiveToggle id={ time + 'DisabledOrElderlyMember' } value={ client.previousDisabledOrElderlyMember }
//   storeBoolean={ storeBool }
//   label={'Was any member of the household elderly (age 60+) or receiving a disability-based benefit (e.g. SSI, EAEDC, MassHealth Disability, etc.)'}/>
// <IntervalColumnHeadings type={type}/>
// { !needsMedical
//   ? null
//   : <CashFlowRow {...merge( sharedProps, {generic: 'Medical'} )}>Medical</CashFlowRow>
// }

/**
* @todo Does a medical assistant's payments count as a medical expense?
* @todo Medical expense only matters if household has elder/disabled, but
* are they any medical expenses or only those of the disabled person? "Medical
* Expenses for Disabled or Elderly". Also, do they sometimes need to
* enter medical expenses even if they don't have an elderly or disabled
* household member?
*/

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/// `props` is a cloned version of the original props. References broken.
const PreviousExpensesStep = function ( props ) {

  return (
    <Form className = 'expense-form'>
      <FormPartsContainer
        title     = {'Previous Household Monthly Expenses'}
        clarifier = {'What were the household\'s expenses at the last time benefits were calculated?'}
        next      = {props.nextStep}
        prev      = {props.previousStep} >
        <ExpensesFormContent client={props.pageState} props={props}/>
      </FormPartsContainer>
    </Form>
  );

};  // End PreviousExpensesStep()

export { PreviousExpensesStep };
<commit_msg>Adds an additional "other" field to expenses<commit_after>// import _ from 'lodash'
import React, { Component } from 'react';
import {
  // Button,
  Form,
  // Grid,
  Header,
  // Segment, Step, Card, Icon, Checkbox, Divider, Radio,
  Statistic,
  Divider,
  // Reveal,
  Input
} from 'semantic-ui-react';
// import { Redirect, Prompt } from 'react-router-dom';
// import { percentPovertyLevel,
//         percentStateMedianIncome } from '../helpers/helperFunctions';
import {
  FormPartsContainer, MassiveToggle, FormHeading,
  IntervalColumnHeadings, CashFlowRow
} from './formHelpers';
import { merge } from '../helpers/object-manipulation';
import { roundMoney, limit } from '../helpers/math';

// ========================================
// COMPONENTS
// ========================================

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const Housing = function ( props ) {

  var client      = props.props.pageState,
      time        = props.time,
      storeBool   = props.props.storeBoolean,
      sharedProps = {
        client: client, type: props.type, time: time,
        storeComplex: props.props.storeComplex
      };

  // `hasHousing` is actually whether they're in the housing voucher program
  var ownedAHome  = client.previousHomeowner,
      wasHomeless = client.previousHomeless && !client.hasHousing && !ownedAHome;

  var utils = client.previousPaidUtilities, climate = client.previousGotClimateControl,
      electricity = client.previousNonHeatElectricity, phone = client.previousTelephone;

  /** @todo Owning a home vs. renting vs. homeless should probably be radio buttons */
  return (
    <wrapper>
      <FormHeading>Housing</FormHeading>

      <MassiveToggle id={ time + 'Homeless' } value={ wasHomeless } storeBoolean={ storeBool }
          label={'Was the household homeless at the last benefit assessment?'}/>
      { wasHomeless
        ? null
        : <MassiveToggle id={ time + 'Homeowner' } value={ ownedAHome }
            storeBoolean={ storeBool } label={ 'Did the household own a home?' } />
      }
      { ownedAHome
        ? <wrapper>
            <IntervalColumnHeadings type={ props.type }/>
            <CashFlowRow {...merge( sharedProps, {generic: 'RentOrMortgage'} )}> Mortgage </CashFlowRow>
            <CashFlowRow {...merge( sharedProps, {generic: 'HousingInsurance'} )}> Insurance Costs </CashFlowRow>
            <CashFlowRow {...merge( sharedProps, {generic: 'PropertyTax'} )}> Property Tax </CashFlowRow>
          </wrapper>
        : <wrapper> { wasHomeless
          ? null
          : <wrapper>
            <IntervalColumnHeadings type={ props.type }/>
            <CashFlowRow {...merge( sharedProps, {generic: 'RentOrMortgage'} )}> Rent </CashFlowRow>
            <MassiveToggle id={ time + 'PaidUtilities' } value={ utils } storeBoolean={ storeBool }
              label={'Did the household pay utilities seperately from the rent?'}/>
            { !client.previousPaidUtilities
              ? null
              : <wrapper>
                  <MassiveToggle id={ time + 'ClimateControl' } value={ climate } storeBoolean={ storeBool }
                    label={'Did the household pay for heating or cooling (e.g. A/C during summer), OR did they receive Fuel Assistance in the 12 months prior to the previous benefit assessment?'}/>
                  <MassiveToggle id={ time + 'NonHeatElectricity' } value={ electricity } storeBoolean={ storeBool }
                    label={'Did the household pay for electricity for non-heating purposes?'}/>
                  <MassiveToggle id={ time + 'Telephone' } value={ phone } storeBoolean={ storeBool }
                    label={'Did the household pay for its own telephone service?'}/>
                </wrapper>
            } </wrapper>
        } </wrapper>
    } </wrapper>
  );

};  // End Housing()

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/
const ExpensesFormContent = function ( props ) {

  var client    = props.client,
      storeBool = props.props.storeBoolean;

  var needsMedical = client.previousDisabledOrElderlyMember;

  var time = 'previous', type = 'expense';
  var sharedProps = { client: client, type: type, time: time,
                    storeComplex: props.props.storeComplex };

  return (
    <wrapper className='field-aligner two-column'>

      <FormHeading subheading = {'(a dependant is a child or disabled adult)'}>
        Dependent Monthly Care</FormHeading>
      <IntervalColumnHeadings type={type}/>
      <CashFlowRow {...merge( sharedProps, {generic: 'DirectCareCosts'} )}> Direct Care Costs </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'BeforeAndAfterSchoolPrograms'} )}> Before- and After-School Programs </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'TransportationCosts'} )}> Transportation Costs </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'OtherDependentCareCosts'} )}> Other </CashFlowRow>

      <Housing props={props.props} time={time} type={type} />

      <FormHeading>Other</FormHeading>
      <CashFlowRow {...merge( sharedProps, {generic: 'Medical'} )}> Medical </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'ChildSupportPaidOut'} )}> LEGALLY OBLIGATED Child support paid out </CashFlowRow>
      <CashFlowRow {...merge( sharedProps, {generic: 'OtherExpenses'} )}> Other Expenses </CashFlowRow>

    </wrapper>
  );

};  // End ExpensesFormContent()

// If medical is only for disabled or elderly
// <MassiveToggle id={ time + 'DisabledOrElderlyMember' } value={ client.previousDisabledOrElderlyMember }
//   storeBoolean={ storeBool }
//   label={'Was any member of the household elderly (age 60+) or receiving a disability-based benefit (e.g. SSI, EAEDC, MassHealth Disability, etc.)'}/>
// <IntervalColumnHeadings type={type}/>
// { !needsMedical
//   ? null
//   : <CashFlowRow {...merge( sharedProps, {generic: 'Medical'} )}>Medical</CashFlowRow>
// }

/**
* @todo Does a medical assistant's payments count as a medical expense?
* @todo Medical expense only matters if household has elder/disabled, but
* are they any medical expenses or only those of the disabled person? "Medical
* Expenses for Disabled or Elderly". Also, do they sometimes need to
* enter medical expenses even if they don't have an elderly or disabled
* household member?
*/

/** @todo description
*
* @function
* @param {object} props
* @property {object} props.__ - explanation
*
* @returns Component
*/// `props` is a cloned version of the original props. References broken.
const PreviousExpensesStep = function ( props ) {

  return (
    <Form className = 'expense-form'>
      <FormPartsContainer
        title     = {'Previous Household Monthly Expenses'}
        clarifier = {'What were the household\'s expenses at the last time benefits were calculated?'}
        next      = {props.nextStep}
        prev      = {props.previousStep} >
        <ExpensesFormContent client={props.pageState} props={props}/>
      </FormPartsContainer>
    </Form>
  );

};  // End PreviousExpensesStep()

export { PreviousExpensesStep };
<|endoftext|>


<commit_before>import { EventEmitter } from 'events';
import logger from 'cytube-common/lib/logger';

export default class Channel extends EventEmitter {
    constructor(name, backendConnection) {
        super();
        this.name = name;
        this.backendConnection = backendConnection;
        this.sockets = [];
    }

    onSocketJoin(socket) {
        if (this.sockets.indexOf(socket) >= 0) {
            logger.error(`socket:${socket.id} attempted to join ` +
                    `channel:${this.name} twice`);
            return;
        }

        socket.on('disconnect', this.onSocketDisconnect.bind(this, socket));

        this.sockets.push(socket);
        this.backendConnection.write(
                this.backendConnection.protocol.newSocketConnectEvent(socket.id, socket.ip)
        );
        this.backendConnection.write(
                this.backendConnection.protocol.newSocketFrameEvent(socket.id, 'joinChannel', [{
                    name: this.name
                }])
        );
    }

    onSocketDisconnect(socket) {
        const index = this.sockets.indexOf(socket);
        if (index >= 0) {
            this.sockets.splice(index, 1);
        }

        this.backendConnection.write(
                this.backendConnection.protocol.newSocketDisconnectEvent(socket.id)
        );

        if (this.sockets.length === 0) {
            this.emit('empty');
        }
    }

    onSocketEvent(socket, event, args) {
        this.backendConnection.write(
                this.backendConnection.protocol.newSocketFrameEvent(socket.id, event, args)
        );
    }

    onBackendDisconnect() {
        this.sockets.forEach(socket => {
            // TODO: emit error frame
            socket.disconnect();
        });
    }
}
<commit_msg>Send socketUser with connection event<commit_after>import { EventEmitter } from 'events';
import logger from 'cytube-common/lib/logger';

export default class Channel extends EventEmitter {
    constructor(name, backendConnection) {
        super();
        this.name = name;
        this.backendConnection = backendConnection;
        this.sockets = [];
    }

    onSocketJoin(socket) {
        if (this.sockets.indexOf(socket) >= 0) {
            logger.error(`socket:${socket.id} attempted to join ` +
                    `channel:${this.name} twice`);
            return;
        }

        socket.on('disconnect', this.onSocketDisconnect.bind(this, socket));

        this.sockets.push(socket);
        this.backendConnection.write(
                this.backendConnection.protocol.newSocketConnectEvent(
                        socket.id,
                        socket.ip,
                        socket.user
                )
        );
        this.backendConnection.write(
                this.backendConnection.protocol.newSocketFrameEvent(socket.id, 'joinChannel', [{
                    name: this.name
                }])
        );
    }

    onSocketDisconnect(socket) {
        const index = this.sockets.indexOf(socket);
        if (index >= 0) {
            this.sockets.splice(index, 1);
        }

        this.backendConnection.write(
                this.backendConnection.protocol.newSocketDisconnectEvent(socket.id)
        );

        if (this.sockets.length === 0) {
            this.emit('empty');
        }
    }

    onSocketEvent(socket, event, args) {
        this.backendConnection.write(
                this.backendConnection.protocol.newSocketFrameEvent(socket.id, event, args)
        );
    }

    onBackendDisconnect() {
        this.sockets.forEach(socket => {
            // TODO: emit error frame
            socket.disconnect();
        });
    }
}
<|endoftext|>


<commit_before>import Phaser from 'phaser'

export default class extends Phaser.Sprite {
  constructor ({ game, x, y, asset }) {
    super(game, x, y, asset)
    this.anchor.setTo(0.5)
    this
    this.pointsx = [1400, 1500, 1600, 1500, 1400]
    this.pointsy = [560, 660, 560, 460, 560]
  }

  update () {
    this.angle += 1

    var x = this.game.time.now/3000 % 1
    var y = this.game.time.now/3000 % 1

    this.x = this.game.math.catmullRomInterpolation(this.pointsx, x)
    this.y = this.game.math.catmullRomInterpolation(this.pointsy, y)
  }
}
<commit_msg>Remove Mushroom<commit_after><|endoftext|>


<commit_before>'use strict';

var Map = require('../models/map');

module.exports = function (app) {
  app.route('/api/maps')
    .get(function(req, res){
      Map.find(function (error, doc) {
        res.send(doc);
      });
    })
    .post(function(req, res){
      let map = req.body;
      let locationMap = new Map(map);
      locationMap.save(function (error, data) {
          res.status(300).send();
      });
    });
  app.route('/api/maps/:id')
    .delete(function(req, res) {
      Map.findOne({
        _id: req.params.id
      }).remove(function (error, result){
        res.status(300).send();
      });
    })
    .patch(function(req, res) {
      Map.findById(req.params.id,
        function (error, doc) {
          for (let key in req.body) {
            if (key === '_id' || key.indexOf('pins') === 0) { continue; }
            doc[key] = req.body[key];
          }
          doc.pins = makePinsArray(req.body)
          doc.save();
          res.status(200).send();
        }
      );
    });
}

function makePinsArray(obj) {
  var pins = [];

  for (let key in obj ) {
    if (key === 'pinKey') { key = x; }
    if (key.indexOf('pins') !== 0) { continue; }
    let index = parseInt(/\d+/.exec(key)[0], 10);
    let pinKey = /\[([a-z]+)\]/i.exec(key)[1];
    let pinValue = parseInt(obj[key], 10);
    if (pins[index]) {
      pins[index][pinKey] = pinValue;
      continue;
    }
    let o = {};
    o[pinKey] = pinValue;
    pins.push(o);
  }

  return pins;
}
<commit_msg>Remove force code<commit_after>'use strict';

var Map = require('../models/map');

module.exports = function (app) {
  app.route('/api/maps')
    .get(function(req, res){
      Map.find(function (error, doc) {
        res.send(doc);
      });
    })
    .post(function(req, res){
      let map = req.body;
      let locationMap = new Map(map);
      locationMap.save(function (error, data) {
          res.status(300).send();
      });
    });
  app.route('/api/maps/:id')
    .delete(function(req, res) {
      Map.findOne({
        _id: req.params.id
      }).remove(function (error, result){
        res.status(300).send();
      });
    })
    .patch(function(req, res) {
      Map.findById(req.params.id,
        function (error, doc) {
          for (let key in req.body) {
            if (key === '_id' || key.indexOf('pins') === 0) { continue; }
            doc[key] = req.body[key];
          }
          doc.pins = makePinsArray(req.body)
          doc.save();
          res.status(200).send();
        }
      );
    });
}

function makePinsArray(obj) {
  var pins = [];

  for (let key in obj ) {
    if (key.indexOf('pins') !== 0) { continue; }
    let index = parseInt(/\d+/.exec(key)[0], 10);
    let pinKey = /\[([a-z]+)\]/i.exec(key)[1];
    let pinValue = parseInt(obj[key], 10);
    if (pins[index]) {
      pins[index][pinKey] = pinValue;
      continue;
    }
    let o = {};
    o[pinKey] = pinValue;
    pins.push(o);
  }

  return pins;
}
<|endoftext|>


<commit_before>'use strict';

let path = process.cwd();
let ctrlPath = path + '/server/ctrl';

const ImageController = require(ctrlPath + '/image-ctrl.server.js');
const UserController = require(ctrlPath + '/user-ctrl.server.js');
const debug = require('debug')('book:routes');

let _log = function(msg) {
    console.log('[LOG@SERVER]: ' + msg);
};

/* Function for debug logging requests.*/
let reqDebug = function(req) {
	_log('\t\tHeaders: ' + JSON.stringify(req.headers));
	_log('\t\tBody: ' + JSON.stringify(req.body));
	_log('\t\tParams: ' + JSON.stringify(req.params));
	_log('\t\tUrl:' + JSON.stringify(req.url));
	_log('\t\tText:' + JSON.stringify(req.text));
	_log('\t\tContent:' + JSON.stringify(req.content));
	_log('\t\tQuery:' + JSON.stringify(req.query));
};

const _u = function(username) {
    return '|' + username + '|';
};

// Msg objects sent back to the client
let notAuthorized = {msg: 'Operation not authorized. Log in first.'};
let errorInternal = {msg: 'Server internal error.'};
let errorForbidden = {msg: 'Requested action forbidden.'};

let errorNoUserInUrl = {msg: 'No username given in URL'};

/* Contains all routes for this application. */
module.exports = function(app, passport) {

    /* Renders a pug template.*/
    let renderPug = function(req, res, pugFile) {
        let isAuth = req.isAuthenticated();
        let username = '';
        if (isAuth) {
            username = req.user.username;
        }
        debug('renderPug auth: ' + isAuth + ' file: ' + pugFile);
        res.render(path + '/pug/' + pugFile,
            {isAuth: isAuth, username: username});
    };

    /* loggedIn func from clementine.js. */
	let isLoggedInOrRedirect = function(req, res, next) {
		if (req.isAuthenticated()) {
			return next();
		}
        else {
            debug('Redirecting non-auth user to /login');
			return res.redirect('/login');
		}
	};

    let isLoggedInAjax = function(req, res, next) {
		if (req.isAuthenticated()) {
			return next();
		}
        else {
            debug('Non-authorized ajax call received');
            return res.status(403).json(notAuthorized);
        }
    };

    /* Returns the username from the request. Logs an error if username is not
     * present. */
    let getUserName = function(req, route) {
        if (req.user) {
            if (req.user.username) {
                return req.user.username;
            }
            else {
                logError(route, 'getUserName: No req.user.username exists.',
                    req);
            }
        }
        else {
            logError(route, 'getUserName: No req.user exists.', req);
        }
        return null;
    };

    let logErrorReq = function(req) {
        console.error('Error REQ headers: ');
        reqDebug(req);
    };

    /* Logs an error with route and request information included.*/
    let logError = function(route, err, req) {
        let date = new Date();
        console.error(date + ' [ERROR@SERVER] route ' + route + ' | ' + err);
        if (req) {
            logErrorReq(req);
        }
    };

    let debugJSON = function(msg, obj) {
        debug(msg + ' ' + JSON.stringify(obj));
    };

    // CONTROLLERS
    let userController = new UserController(path);
    let imageController = new ImageController(path);

    //----------------------------------------------------------------------
    // ROUTES
    //----------------------------------------------------------------------

	app.route('/')
		.get((req, res) => {
            renderPug(req, res, 'index.pug');
		});

	app.route('/about')
		.get((req, res) => {
            renderPug(req, res, 'about.pug');
		});

	app.route('/grid')
		.get((req, res) => {
            renderPug(req, res, 'grid.pug');
		});

	app.route('/all-images')
		.get((req, res) => {
            renderPug(req, res, 'images.pug');
		});

	app.route('/walls')
		.get((req, res) => {
            renderPug(req, res, 'walls.pug');
		});

	app.route('/signup')
		.get((req, res) => {
            renderPug(req, res, 'signup.pug');
		});

	app.route('/login')
		.get((req, res) => {
            renderPug(req, res, 'login.pug');
		});

	app.route('/loginFailed')
		.get((req, res) => {
            res.render(path + '/pug/login.pug',
                {isAuth: false, loginFailed: true});
        });

    // If a user logs out, return to main page
	app.route('/logout')
		.get((req, res) => {
			req.logout();
			res.redirect('/');
		});

	app.route('/profile')
		.get(isLoggedInOrRedirect, (req, res) => {
            renderPug(req, res, 'profile.pug');
		});

    // Handle registration of user
    app.route('/forms/signup')
        .post((req, res) => {
            debug('Got a signup form GET request..');
            userController.addLocalUser(req, res);
        });

    //----------------------------------------------------
    // /users/ Routes for accessing/manipulating user data
    //----------------------------------------------------

    // Called by client to check their authentication status
	app.route('/users/amiauth')
		.get((req, res) => {
            let data = {isAuth: false};
            if (req.isAuthenticated()) {
                data.isAuth = true;
                data.username = req.user.username;
                userController.getUserID(data.username, (err, userID) => {
                    if (err) {
                        logError('/users/amiauth', err, req);
                        res.status(500).json({error: 'Failed to authenticate'});
                    }
                    else {
                        data.userID = userID;
                        res.status(200).json(data);
                    }
                });
            }
            else {
                res.status(200).json(data);
            }
		});

    // Returns names of all users
    app.route('/users/list')
        .get((req, res) => {
            userController.getUserList((err, resp) => {
                if (err) {
                    logError('/users/list', err, req);
                    res.status(500).json({error: 'No user list found.'});
                }
                else {
                    res.status(200).json(resp);
                }

            });
        });

    app.route('/users/wall/:username')
        .get((req, res) => {
            let username = req.params.username;
            if (username) {
                userController.getPublicUserWall(username, (err, resp) => {
                    if (err) {
                        logError('/users/wall', err, req);
                        res.status(500).json({error: 'No user wall found.'});
                    }
                    else {
                        res.status(200).json(resp);
                    }

                });
            }
            else {
                res.status(400).json(errorNoUserInUrl);
            }
        });

    app.route('/users/:name')
        .get(isLoggedInAjax, (req, res) => {
            let username = req.params.name;
            if (username === req.user.username) {
                userController.getUserByName(username, (err, data) => {
                    if (err) {
                        logError('/users/' + username, err, req);
                        res.status(500).json(errorInternal);
                    }
                    else {
                        res.json(data);
                    }
                });
            }
            else {
                // Forbidden
                logError('/users/' + username,
                    'Forbidden action attempted.', req);
                res.status(403).json(errorForbidden);
            }
        });

    app.route('/users/update')
        .post(isLoggedInAjax, (req, res) => {
            let username = getUserName(req, '/user/update');
            let userInfo = req.body;
            debugJSON('/users/update ' + _u(username) + ' info: ', userInfo);
            userController.updateUserInfo(username, userInfo, (err, data) => {
                if (err) {
                    logError('/users/update', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    res.json(data);
                }
            });
        });

    app.route('/users')
        .get(isLoggedInAjax, (req, res) => {
            let username = req.user.username;
            userController.getUserByName(username, (err, data) => {
                if (err) {
                    logError('/users/' + username, err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    res.json(data);
                }
            });
        });

    //--------------------------------------
    // Images
    //--------------------------------------

    app.route('/images')

        .get( (req, res) => {
            imageController.getAllImages( (err, data) => {
                if (err) {
                    logError('/images', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('GET /images result (200): ', data);
                    res.status(200).json(data);
                }
            });
        })

        /* Used for updating existing images. */
        .put(isLoggedInAjax, (req, res) => {
            debugJSON('PUT /images req.body: ', req.body);
            let username = req.user.username;
            imageController.updateImage(username, req.body, (err, result) => {
                if (err) {
                    logError('/images', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('PUT /images result (200): ', result);
                    res.status(200).json({msg: 'OK'});
                }

            });
        })

        .post(isLoggedInAjax, (req, res) => {
            debug('/images POST');
            debugJSON('/images POST req.body: ', req.body);
            let username = req.user.username;
            imageController.addImage(username, req.body, (err, result) => {
                if (err) {
                    logError('/images POST', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('/images POST result (200): ', result);
                    res.status(200).json({msg: 'OK'});
                }
            });

        })

        .delete(isLoggedInAjax, (req, res) => {
            debug('/images DELETE');
            debugJSON('/images DELETE req.body: ', req.body);
            let username = req.user.username;
            imageController.removeImage(username, req.body, (err, result) => {
                if (err) {
                    logError('/images DELETE', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('/images DELETE result (200): ', result);
                    res.status(200).json({msg: 'OK', result: result});
                }
            });

        });

    //--------------------------------------
    // User registration and authentication
    //--------------------------------------

	app.get('/auth/twitter',
		passport.authenticate('twitter'));

	app.get('/auth/twitter/callback',
		passport.authenticate('twitter', { failureRedirect: '/login' }),
		(req, res) => {
			// Successful authentication, redirect home.
			res.redirect('/profile');
		});

    // Logs user in via form (after successful authentication)
	app.route('/auth/userlogin')
        .post(passport.authenticate('local',
            { failureRedirect: '/loginFailed' }), (req, res) => {
			res.redirect('/');
		});

};
<commit_msg>Added route /search for searching images.<commit_after>'use strict';

let path = process.cwd();
let ctrlPath = path + '/server/ctrl';

const ImageController = require(ctrlPath + '/image-ctrl.server.js');
const UserController = require(ctrlPath + '/user-ctrl.server.js');
const BingSearch = require('../common/bing-search');
const debug = require('debug')('book:routes');

let _log = function(msg) {
    console.log('[LOG@SERVER]: ' + msg);
};

/* Function for debug logging requests.*/
let reqDebug = function(req) {
	_log('\t\tHeaders: ' + JSON.stringify(req.headers));
	_log('\t\tBody: ' + JSON.stringify(req.body));
	_log('\t\tParams: ' + JSON.stringify(req.params));
	_log('\t\tUrl:' + JSON.stringify(req.url));
	_log('\t\tText:' + JSON.stringify(req.text));
	_log('\t\tContent:' + JSON.stringify(req.content));
	_log('\t\tQuery:' + JSON.stringify(req.query));
};

const _u = function(username) {
    return '|' + username + '|';
};

// Msg objects sent back to the client
let notAuthorized = {msg: 'Operation not authorized. Log in first.'};
let errorInternal = {msg: 'Server internal error.'};
let errorForbidden = {msg: 'Requested action forbidden.'};

let errorNoUserInUrl = {msg: 'No username given in URL'};

/* Contains all routes for this application. */
module.exports = function(app, passport) {

    /* Renders a pug template.*/
    let renderPug = function(req, res, pugFile) {
        let isAuth = req.isAuthenticated();
        let username = '';
        if (isAuth) {
            username = req.user.username;
        }
        debug('renderPug auth: ' + isAuth + ' file: ' + pugFile);
        res.render(path + '/pug/' + pugFile,
            {isAuth: isAuth, username: username});
    };

    /* loggedIn func from clementine.js. */
	let isLoggedInOrRedirect = function(req, res, next) {
		if (req.isAuthenticated()) {
			return next();
		}
        else {
            debug('Redirecting non-auth user to /login');
			return res.redirect('/login');
		}
	};

    let isLoggedInAjax = function(req, res, next) {
		if (req.isAuthenticated()) {
			return next();
		}
        else {
            debug('Non-authorized ajax call received');
            return res.status(403).json(notAuthorized);
        }
    };

    /* Returns the username from the request. Logs an error if username is not
     * present. */
    let getUserName = function(req, route) {
        if (req.user) {
            if (req.user.username) {
                return req.user.username;
            }
            else {
                logError(route, 'getUserName: No req.user.username exists.',
                    req);
            }
        }
        else {
            logError(route, 'getUserName: No req.user exists.', req);
        }
        return null;
    };

    let logErrorReq = function(req) {
        console.error('Error REQ headers: ');
        reqDebug(req);
    };

    /* Logs an error with route and request information included.*/
    let logError = function(route, err, req) {
        let date = new Date();
        console.error(date + ' [ERROR@SERVER] route ' + route + ' | ' + err);
        if (req) {
            logErrorReq(req);
        }
    };

    let debugJSON = function(msg, obj) {
        debug(msg + ' ' + JSON.stringify(obj));
    };

    // CONTROLLERS
    let userController = new UserController(path);
    let imageController = new ImageController(path);

    let imageSearch = new BingSearch(process.env.BING_KEY);

    //----------------------------------------------------------------------
    // ROUTES
    //----------------------------------------------------------------------

	app.route('/')
		.get((req, res) => {
            renderPug(req, res, 'index.pug');
		});

	app.route('/about')
		.get((req, res) => {
            renderPug(req, res, 'about.pug');
		});

	app.route('/grid')
		.get((req, res) => {
            renderPug(req, res, 'grid.pug');
		});

	app.route('/all-images')
		.get((req, res) => {
            renderPug(req, res, 'images.pug');
		});

	app.route('/walls')
		.get((req, res) => {
            renderPug(req, res, 'walls.pug');
		});

	app.route('/signup')
		.get((req, res) => {
            renderPug(req, res, 'signup.pug');
		});

	app.route('/login')
		.get((req, res) => {
            renderPug(req, res, 'login.pug');
		});

	app.route('/loginFailed')
		.get((req, res) => {
            res.render(path + '/pug/login.pug',
                {isAuth: false, loginFailed: true});
        });

    // If a user logs out, return to main page
	app.route('/logout')
		.get((req, res) => {
			req.logout();
			res.redirect('/');
		});

	app.route('/profile')
		.get(isLoggedInOrRedirect, (req, res) => {
            renderPug(req, res, 'profile.pug');
		});

    // Handle registration of user
    app.route('/forms/signup')
        .post((req, res) => {
            debug('Got a signup form GET request..');
            userController.addLocalUser(req, res);
        });

    //----------------------------------------------------
    // /users/ Routes for accessing/manipulating user data
    //----------------------------------------------------

    // Called by client to check their authentication status
	app.route('/users/amiauth')
		.get((req, res) => {
            let data = {isAuth: false};
            if (req.isAuthenticated()) {
                data.isAuth = true;
                data.username = req.user.username;
                userController.getUserID(data.username, (err, userID) => {
                    if (err) {
                        logError('/users/amiauth', err, req);
                        res.status(500).json({error: 'Failed to authenticate'});
                    }
                    else {
                        data.userID = userID;
                        res.status(200).json(data);
                    }
                });
            }
            else {
                res.status(200).json(data);
            }
		});

    // Returns names of all users
    app.route('/users/list')
        .get((req, res) => {
            userController.getUserList((err, resp) => {
                if (err) {
                    logError('/users/list', err, req);
                    res.status(500).json({error: 'No user list found.'});
                }
                else {
                    res.status(200).json(resp);
                }

            });
        });

    app.route('/users/wall/:username')
        .get((req, res) => {
            let username = req.params.username;
            if (username) {
                userController.getPublicUserWall(username, (err, resp) => {
                    if (err) {
                        logError('/users/wall', err, req);
                        res.status(500).json({error: 'No user wall found.'});
                    }
                    else {
                        res.status(200).json(resp);
                    }

                });
            }
            else {
                res.status(400).json(errorNoUserInUrl);
            }
        });

    app.route('/users/:name')
        .get(isLoggedInAjax, (req, res) => {
            let username = req.params.name;
            if (username === req.user.username) {
                userController.getUserByName(username, (err, data) => {
                    if (err) {
                        logError('/users/' + username, err, req);
                        res.status(500).json(errorInternal);
                    }
                    else {
                        res.json(data);
                    }
                });
            }
            else {
                // Forbidden
                logError('/users/' + username,
                    'Forbidden action attempted.', req);
                res.status(403).json(errorForbidden);
            }
        });

    app.route('/users/update')
        .post(isLoggedInAjax, (req, res) => {
            let username = getUserName(req, '/user/update');
            let userInfo = req.body;
            debugJSON('/users/update ' + _u(username) + ' info: ', userInfo);
            userController.updateUserInfo(username, userInfo, (err, data) => {
                if (err) {
                    logError('/users/update', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    res.json(data);
                }
            });
        });

    app.route('/users')
        .get(isLoggedInAjax, (req, res) => {
            let username = req.user.username;
            userController.getUserByName(username, (err, data) => {
                if (err) {
                    logError('/users/' + username, err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    res.json(data);
                }
            });
        });

    //--------------------------------------
    // Images
    //--------------------------------------

    app.route('/images')

        .get( (req, res) => {
            imageController.getAllImages( (err, data) => {
                if (err) {
                    logError('/images', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('GET /images result (200): ', data);
                    res.status(200).json(data);
                }
            });
        })

        /* Used for updating existing images. */
        .put(isLoggedInAjax, (req, res) => {
            debugJSON('PUT /images req.body: ', req.body);
            let username = req.user.username;
            imageController.updateImage(username, req.body, (err, result) => {
                if (err) {
                    logError('/images', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('PUT /images result (200): ', result);
                    res.status(200).json({msg: 'OK'});
                }

            });
        })

        .post(isLoggedInAjax, (req, res) => {
            debug('/images POST');
            debugJSON('/images POST req.body: ', req.body);
            let username = req.user.username;
            imageController.addImage(username, req.body, (err, result) => {
                if (err) {
                    logError('/images POST', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('/images POST result (200): ', result);
                    res.status(200).json({msg: 'OK'});
                }
            });

        })

        .delete(isLoggedInAjax, (req, res) => {
            debug('/images DELETE');
            debugJSON('/images DELETE req.body: ', req.body);
            let username = req.user.username;
            imageController.removeImage(username, req.body, (err, result) => {
                if (err) {
                    logError('/images DELETE', err, req);
                    res.status(500).json(errorInternal);
                }
                else {
                    debugJSON('/images DELETE result (200): ', result);
                    res.status(200).json({msg: 'OK', result: result});
                }
            });

        });

        /* Route for image searches. For registered users only. */
        app.route('/search')
            .post(isLoggedInAjax, (req, res) => {
                let query = req.body.query;
                imageSearch.search(query, (err, result) => {
                    if (err) {
                        logError('/search POST', err, req);
                        res.status(500).json(errorInternal);
                    }
                    else {
                        // TODO add search into user data
                        res.status(200).json(result);
                    }

                });
            });

    //--------------------------------------
    // User registration and authentication
    //--------------------------------------

	app.get('/auth/twitter',
		passport.authenticate('twitter'));

	app.get('/auth/twitter/callback',
		passport.authenticate('twitter', { failureRedirect: '/login' }),
		(req, res) => {
			// Successful authentication, redirect home.
			res.redirect('/profile');
		});

    // Logs user in via form (after successful authentication)
	app.route('/auth/userlogin')
        .post(passport.authenticate('local',
            { failureRedirect: '/loginFailed' }), (req, res) => {
			res.redirect('/');
		});

};
<|endoftext|>


<commit_before>'use strict'

var fs = require('fs')
var child_process = require('child_process')
var through = require('through2')
var split = require('split')
var elasticsearch = require('elasticsearch')
var htmlProcess = require('./html_process')
var CONF = require('../config.js')

function batchify(size) {
  let queue = []

  return through.obj(function(data, enc, cb) {
    queue.push(data)

    if (queue.length < size) {
      // Return immediately
      cb()
    } else {
      // Yield a batch
      let batch = queue
      queue = []
      this.push(batch)
      cb()
    }
  }, function(cb) {
    // Flush on end
    let batch = queue
    queue = []
    this.push(batch)
    cb()
  })
}

function jsonsToElasticBatch() {
  return through.obj((jsons, enc, cb) => {
    let batch = []
    jsons.forEach(json => {
      let typeParts = json.type.split(/\//g)
      let type = typeParts[typeParts.length - 1]

      batch.push({ index: {
        _type: type,
        _id: json.id
      } })
      batch.push(json)
    })
    cb(null, batch)
  })
}

function elasticSink() {
  let es = new elasticsearch.Client({
    host: CONF.elasticsearchUrl,
    log: 'info'
  })

  return through.obj((data, enc, cb) => {
    console.log(`Indexing ${data.length / 2} documents`)
    es.bulk({
      index: CONF.elasticsearchOparlIndex,
      body: data
    }, (err, res) => cb(err))
  })
}

function pdftohtml(pdfPath, cb) {
  child_process.exec(`pdftohtml -i -s ${pdfPath}`, (err, stdout, stderr) => {
    if (err) return cb(err)

    stderr = stderr.toString()
    if (stderr) return cb(new Error(stderr))

    let basePath = pdfPath.replace(/\.pdf$/i, "")
    let htmlPath = `${basePath}.html`
    fs.unlink(`${basePath}s.html`, err => {
      // Ignore this err
      fs.rename(`${basePath}-html.html`, htmlPath, err => {
        cb(err, htmlPath)
      })
    })
  })
}

function htmlToText(htmlPath, cb) {
  let pages = []

  let proc = htmlProcess()
  proc.on('error', err => {
    cb(err)
    cb = () => {}
  })

  fs.createReadStream(htmlPath)
    .pipe(proc)
    .pipe(through.obj((page, enc, cb) => {
      pages.push(page.contents.map(
        block =>
          block.contents.map(getFragmentText).join("")
      ).join("\n"))
      cb()
    }, flushCb => {
      flushCb()
      cb(null, pages.join("\n\n\n"))
    }))
}

function getFragmentText(frag) {
  if (typeof frag === 'string') {
    return frag
  } else if (frag.contents) {
    return frag.contents.map(getFragmentText).join("")
  } else {
    return ""
  }
}

/*** Main pipeline ***/

child_process.spawn("/usr/bin/env", ["find", CONF.scrapeData, "-name", "*.json", "-type", "f"]).stdout
  .pipe(split())
  .pipe(through.obj((line, enc, cb) => {
    cb(null, line.toString('utf8'))
  }))
  .pipe(through.obj((path, enc, cb) => {
    if (!path) return cb()

    fs.readFile(path, (err, data) => {
      cb(err, {
        path: path,
        data: data
      })
    })
  }))
  .pipe(through.obj((data, enc, cb) => {
    let json = JSON.parse(data.data)
    cb(null, {
      path: data.path,
      json: json
    })
  }))
  .pipe(through.obj((data, enc, cb) => {
    // pdftohtml for Files
    if (/\/File$/.test(data.json.type)) {
      let pdfPath = data.path.replace(/\.json$/, ".pdf")
      fs.access(pdfPath, err => {
        if (err) {
          // Can't access .pdf, ignore
          return cb(null, data)
        }

        let t1 = Date.now()
        pdftohtml(pdfPath, (err, htmlPath) => {
          if (err) {
            console.log("pdftohtml error: " + err.message)
            return cb(null, data)
          }

          let t2 = Date.now()
          console.log(`pdftohtml [${t2 - t1}ms] ${pdfPath}`)

          data.htmlPath = htmlPath
          cb(null, data)
        })
      })
    } else {
      // Pass through non-Files
      cb(null, data)
    }
  }))
  .pipe(through.obj((data, enc, cb) => {
    // extract text from pdftohtml result
    if (data.htmlPath) {
      htmlToText(data.htmlPath, (err, text) => {
        if (err) {
          console.log("htmlToText error: " + err.message)
          return cb(null, data)
        }

        data.json.text = text
        cb(err, data)
      })
    } else {
      cb(null, data)
    }
  }))
  .pipe(through.obj((data, enc, cb) => {
    // Actually, we only send the JSON to ES, not the paths
    cb(null, data.json)
  }))
  .pipe(batchify(64))
  .pipe(jsonsToElasticBatch())
  .pipe(elasticSink())
<commit_msg>es_upload: don't pdftohtml if .html already exists<commit_after>'use strict'

var fs = require('fs')
var child_process = require('child_process')
var through = require('through2')
var split = require('split')
var elasticsearch = require('elasticsearch')
var htmlProcess = require('./html_process')
var CONF = require('../config.js')

function batchify(size) {
  let queue = []

  return through.obj(function(data, enc, cb) {
    queue.push(data)

    if (queue.length < size) {
      // Return immediately
      cb()
    } else {
      // Yield a batch
      let batch = queue
      queue = []
      this.push(batch)
      cb()
    }
  }, function(cb) {
    // Flush on end
    let batch = queue
    queue = []
    this.push(batch)
    cb()
  })
}

function jsonsToElasticBatch() {
  return through.obj((jsons, enc, cb) => {
    let batch = []
    jsons.forEach(json => {
      let typeParts = json.type.split(/\//g)
      let type = typeParts[typeParts.length - 1]

      batch.push({ index: {
        _type: type,
        _id: json.id
      } })
      batch.push(json)
    })
    cb(null, batch)
  })
}

function elasticSink() {
  let es = new elasticsearch.Client({
    host: CONF.elasticsearchUrl,
    log: 'info'
  })

  return through.obj((data, enc, cb) => {
    console.log(`Indexing ${data.length / 2} documents`)
    es.bulk({
      index: CONF.elasticsearchOparlIndex,
      body: data
    }, (err, res) => cb(err))
  })
}

function pdftohtml(pdfPath, htmlPath, cb) {
  child_process.exec(`pdftohtml -i -s ${pdfPath}`, (err, stdout, stderr) => {
    if (err) return cb(err)

    stderr = stderr.toString()
    if (stderr) return cb(new Error(stderr))

    let basePath = pdfPath.replace(/\.pdf$/i, "")
    fs.unlink(`${basePath}s.html`, err => {
      // Ignore this err
      fs.rename(`${basePath}-html.html`, htmlPath, err => {
        cb(err)
      })
    })
  })
}

function htmlToText(htmlPath, cb) {
  let pages = []

  let proc = htmlProcess()
  proc.on('error', err => {
    cb(err)
    cb = () => {}
  })

  fs.createReadStream(htmlPath)
    .pipe(proc)
    .pipe(through.obj((page, enc, cb) => {
      pages.push(page.contents.map(
        block =>
          block.contents.map(getFragmentText).join("")
      ).join("\n"))
      cb()
    }, flushCb => {
      flushCb()
      cb(null, pages.join("\n\n\n"))
    }))
}

function getFragmentText(frag) {
  if (typeof frag === 'string') {
    return frag
  } else if (frag.contents) {
    return frag.contents.map(getFragmentText).join("")
  } else {
    return ""
  }
}

/*** Main pipeline ***/

child_process.spawn("/usr/bin/env", ["find", CONF.scrapeData, "-name", "*.json", "-type", "f"]).stdout
  .pipe(split())
  .pipe(through.obj((line, enc, cb) => {
    cb(null, line.toString('utf8'))
  }))
  .pipe(through.obj((path, enc, cb) => {
    if (!path) return cb()

    fs.readFile(path, (err, data) => {
      cb(err, {
        path: path,
        data: data
      })
    })
  }))
  .pipe(through.obj((data, enc, cb) => {
    let json = JSON.parse(data.data)
    cb(null, {
      path: data.path,
      json: json
    })
  }))
  .pipe(through.obj((data, enc, cb) => {
    // pdftohtml for Files
    if (/\/File$/.test(data.json.type)) {
      data.htmlPath = pdfPath.replace(/\.pdf$/i, ".html")
      fs.access(data.htmlPath, err => {
        if (!err) {
          // .html already exists, skip
          return cb()
        }

        let pdfPath = data.path.replace(/\.json$/, ".pdf")
        fs.access(pdfPath, err => {
          if (err) {
            // Can't access .pdf, ignore
            return cb(null, data)
          }

          let t1 = Date.now()
          pdftohtml(pdfPath, err => {
            if (err) {
              console.log("pdftohtml error: " + err.message)
              return cb(null, data)
            }

            let t2 = Date.now()
            console.log(`pdftohtml [${t2 - t1}ms] ${pdfPath}`)

            cb(null, data)
          })
        })
      })
    } else {
      // Pass through non-Files
      cb(null, data)
    }
  }))
  .pipe(through.obj((data, enc, cb) => {
    // extract text from pdftohtml result
    if (data.htmlPath) {
      htmlToText(data.htmlPath, (err, text) => {
        if (err) {
          console.log("htmlToText error: " + err.message)
          return cb(null, data)
        }

        data.json.text = text
        cb(err, data)
      })
    } else {
      cb(null, data)
    }
  }))
  .pipe(through.obj((data, enc, cb) => {
    // Actually, we only send the JSON to ES, not the paths
    cb(null, data.json)
  }))
  .pipe(batchify(64))
  .pipe(jsonsToElasticBatch())
  .pipe(elasticSink())
<|endoftext|>


<commit_before>// Inspired by Underscore's groupBy:
// http://documentcloud.github.com/underscore/#groupBy

'use strict';

var callable = require('../../object/valid-callable')
  , value    = require('../../object/valid-value')

  , forEach = Array.prototype.forEach, apply = Function.prototype.apply;

module.exports = function (cb/*, thisArg*/) {
	var r;

	(value(this) && callable(cb));

	r = {};
	forEach.call(this, function (v) {
		var key = apply.call(cb, this, arguments);
		if (!r.hasOwnProperty(key)) {
			r[key] = [];
		}
		r[key].push(v);
	}, arguments[1]);
	return r;
};
<commit_msg>-- whitespace<commit_after>// Inspired by Underscore's groupBy:
// http://documentcloud.github.com/underscore/#groupBy

'use strict';

var callable = require('../../object/valid-callable')
  , value    = require('../../object/valid-value')

  , forEach = Array.prototype.forEach, apply = Function.prototype.apply;

module.exports = function (cb/*, thisArg*/) {
	var r;

	(value(this) && callable(cb));

	r = {};
	forEach.call(this, function (v) {
		var key = apply.call(cb, this, arguments);
		if (!r.hasOwnProperty(key)) r[key] = [];
		r[key].push(v);
	}, arguments[1]);
	return r;
};
<|endoftext|>


<commit_before>
$(function() {

    function syncValue(evt, args) {
        var el = $('#' + args.key);
        el.val(args.chart.get('metadata.visualize.'+args.key));
        function save() {
            args.chart.set('metadata.visualize.'+args.key, el.val());
        }
        el.change(save).keyup(save);
    }

    function syncCheckbox(evt, args) {
        var el = $('#'+args.key);
        if (args.chart.get('metadata.visualize.'+args.key))
            el.prop('checked', 'checked');
        else
            el.removeAttr('checked');
        el.change(function() {
            args.chart.set('metadata.visualize.'+args.key, el.is(':checked'));
        });
    }

    function syncRadio(evt, args) {
        var curVal = args.chart.get('metadata.visualize.'+args.key);
        if (_.isBoolean(curVal)) {
            curVal = curVal ? 'yes' : 'no';
        }
        $('input:radio[name='+args.key+'][value='+curVal+']').prop('checked', 'checked');
        $('input:radio[name='+args.key+']').change(function() {
            var val = $('input:radio[name='+args.key+']:checked').val();
            if (val === 'yes') val = true;
            else if (val === 'no') val = false;
            args.chart.set('metadata.visualize.'+args.key, val);
        });
    }

    function syncSelectAxisColumn(evt, args) {
        var select = $('select#'+args.key),
            chart = args.chart,
            dataset = chart.dataset(),
            axisKey = select.data('axis'),
            axisMeta = args.vis.meta.axes[axisKey];

        // populate select with columns that match accepted types for axis
        dataset.eachColumn(function(column) {
            if (_.indexOf(axisMeta.accepts, column.type()) > -1) {
                $('<option />')
                    .attr('value', column.name())
                    .html(column.title())
                    .attr('selected', column.name() == args.vis.axes().color)
                    .appendTo(select);
            }
        });

        select.change(function() {
            var axes = _.clone(chart.get('metadata.axes', {}));
            axes[axisKey] = select.val();
            chart.set('metadata.axes', axes);
        });

        console.log(axisMeta, select.data('axis'), select);
    }

    $('#vis-options').on('dw:vis-option:select', syncValue);
    $('#vis-options').on('dw:vis-option:text', syncValue);
    $('#vis-options').on('dw:vis-option:checkbox', syncCheckbox);
    $('#vis-options').on('dw:vis-option:radio', syncRadio);
    $('#vis-options').on('dw:vis-option:radio-left', syncRadio);

    // column select
    $('#vis-options').on('dw:vis-option:select-axis-column', syncSelectAxisColumn);

});

<commit_msg>removed .log<commit_after>
$(function() {

    function syncValue(evt, args) {
        var el = $('#' + args.key);
        el.val(args.chart.get('metadata.visualize.'+args.key));
        function save() {
            args.chart.set('metadata.visualize.'+args.key, el.val());
        }
        el.change(save).keyup(save);
    }

    function syncCheckbox(evt, args) {
        var el = $('#'+args.key);
        if (args.chart.get('metadata.visualize.'+args.key))
            el.prop('checked', 'checked');
        else
            el.removeAttr('checked');
        el.change(function() {
            args.chart.set('metadata.visualize.'+args.key, el.is(':checked'));
        });
    }

    function syncRadio(evt, args) {
        var curVal = args.chart.get('metadata.visualize.'+args.key);
        if (_.isBoolean(curVal)) {
            curVal = curVal ? 'yes' : 'no';
        }
        $('input:radio[name='+args.key+'][value='+curVal+']').prop('checked', 'checked');
        $('input:radio[name='+args.key+']').change(function() {
            var val = $('input:radio[name='+args.key+']:checked').val();
            if (val === 'yes') val = true;
            else if (val === 'no') val = false;
            args.chart.set('metadata.visualize.'+args.key, val);
        });
    }

    function syncSelectAxisColumn(evt, args) {
        var select = $('select#'+args.key),
            chart = args.chart,
            dataset = chart.dataset(),
            axisKey = select.data('axis'),
            axisMeta = args.vis.meta.axes[axisKey];

        // populate select with columns that match accepted types for axis
        dataset.eachColumn(function(column) {
            if (_.indexOf(axisMeta.accepts, column.type()) > -1) {
                $('<option />')
                    .attr('value', column.name())
                    .html(column.title())
                    .attr('selected', column.name() == args.vis.axes().color)
                    .appendTo(select);
            }
        });

        select.change(function() {
            var axes = _.clone(chart.get('metadata.axes', {}));
            axes[axisKey] = select.val();
            chart.set('metadata.axes', axes);
        });
    }

    $('#vis-options').on('dw:vis-option:select', syncValue);
    $('#vis-options').on('dw:vis-option:text', syncValue);
    $('#vis-options').on('dw:vis-option:checkbox', syncCheckbox);
    $('#vis-options').on('dw:vis-option:radio', syncRadio);
    $('#vis-options').on('dw:vis-option:radio-left', syncRadio);

    // column select
    $('#vis-options').on('dw:vis-option:select-axis-column', syncSelectAxisColumn);

});

<|endoftext|>