<commit_before>const shell = require('shelljs');
const pify = require('pify');
const fs = require('fs');
const path = require('path');
const istanbul = require('sc-istanbul');
const assert = require('assert');
const detect = require('detect-port');
const _ = require('lodash/lang');

const ConfigValidator = require('./validator');
const Instrumenter = require('./instrumenter');
const Coverage = require('./coverage');
const DataCollector = require('./collector');
const AppUI = require('./ui').AppUI;

/**
 * Coverage Runner
 */
class API {
  constructor(config={}) {
    this.coverage = new Coverage();
    this.instrumenter = new Instrumenter();
    this.validator = new ConfigValidator()
    this.config = config || {};

    // Validate
    this.validator.validate(this.config);

    // Options
    this.testsErrored = false;

    this.cwd = config.cwd || process.cwd();

    this.defaultHook = () => {};
    this.onServerReady = config.onServerReady           || this.defaultHook;
    this.onTestsComplete = config.onTestsComplete       || this.defaultHook;
    this.onCompileComplete = config.onCompileComplete   || this.defaultHook;
    this.onIstanbulComplete = config.onIstanbulComplete || this.defaultHook;

    this.server = null;
    this.defaultPort = 8555;
    this.client = config.client;
    this.defaultNetworkName = 'soliditycoverage';
    this.port = config.port || this.defaultPort;
    this.host = config.host || "127.0.0.1";
    this.providerOptions = config.providerOptions || {};
    this.autoLaunchServer = config.autoLaunchServer === false ? false : true;

    this.skipFiles = config.skipFiles || [];

    this.log = config.log || console.log;

    this.gasLimit = 0xffffffffff;            // default "gas sent" with transactions
    this.gasLimitString = "0xfffffffffff";   // block gas limit for ganache (higher than "gas sent")
    this.gasPrice = 0x01;

    this.istanbulFolder = config.istanbulFolder || false;
    this.istanbulReporter = config.istanbulReporter || ['html', 'lcov', 'text', 'json'];

    this.setLoggingLevel(config.silent);
    this.ui = new AppUI(this.log);
  }

  /**
   * Instruments a set of sources to prepare them for running under coverage
   * @param  {Object[]}  targets (see below)
   * @return {Object[]}          (see below)
   * @example of input/output array:
   * [{
   *   source:         (required) <solidity-source>,
   *   canonicalPath:  (required) <absolute path to source file>
   *   relativePath:   (optional) <rel path to source file for logging>
   * }]
   */
  instrument(targets=[]) {
    let currentFile;      // Keep track of filename in case we crash...
    let started = false;
    let outputs = [];

    try {
      for (let target of targets) {
        currentFile = target.relativePath || target.canonicalPath;

        if(!started){
          started = true;
          this.ui.report('instr-start');
        }

        this.ui.report('instr-item', [currentFile]);

        const instrumented = this.instrumenter.instrument(
          target.source,
          target.canonicalPath
        );

        this.coverage.addContract(instrumented, target.canonicalPath);

        outputs.push({
          canonicalPath: target.canonicalPath,
          relativePath: target.relativePath,
          source: instrumented.contract
        })
      }

    } catch (err) {
      err.message = this.ui.generate('instr-fail', [currentFile]) + err.message;
      throw err;
    }

    return outputs;
  }

  /**
   * Returns a copy of the hit map created during instrumentation.
   * Useful if you'd like to delegate coverage collection to multiple processes.
   * @return {Object} instrumentationData
   */
  getInstrumentationData(){
    return _.cloneDeep(this.instrumenter.instrumentationData)
  }

  /**
   * Sets the hit map object generated during instrumentation. Useful if you'd like
   * to collect data for a pre-existing instrumentation.
   * @param {Object} data
   */
  setInstrumentationData(data={}){
    this.instrumenter.instrumentationData = _.cloneDeep(data);
  }

  /**
   * Enables coverage collection on in-process ethereum client server, hooking the DataCollector
   * to its VM. By default, method will return a url after server has begun listening on the port
   * specified in the config. When `autoLaunchServer` is false, method returns`ganache.server` so
   * the consumer can control the 'server.listen' invocation themselves.
   * @param  {Object} client             ganache client
   * @param  {Boolean} autoLaunchServer  boolean
   * @return {<Promise> (String | Server) }  address of server to connect to, or initialized, unlaunched server.
   */
  async ganache(client, autoLaunchServer){
    // Check for port-in-use
    if (await detect(this.port) !== this.port){
      throw new Error(this.ui.generate('server-fail', [this.port]))
    }

    this.collector = new DataCollector(this.instrumenter.instrumentationData);

    this.providerOptions.gasLimit = this.gasLimitString;
    this.providerOptions.allowUnlimitedContractSize = true;

    // Attach to vm step of supplied client
    try {
      if (this.config.forceBackupServer) throw new Error()
      await this.attachToVM(client)
    }

    // Fallback to ganache-cli)
    catch(err) {
      const _ganache = require('ganache-cli');
      this.ui.report('vm-fail', [_ganache.version]);
      await this.attachToVM(_ganache);
    }

    if (autoLaunchServer === false || this.autoLaunchServer === false){
      return this.server;
    }

    await pify(this.server.listen)(this.port);
    const address = `http://${this.host}:${this.port}`;
    this.ui.report('server', [address]);
    return address;
  }

  /**
   * Generate coverage / write coverage report / run istanbul
   */
  async report(_folder) {
    const folder = _folder || this.istanbulFolder;

    const collector = new istanbul.Collector();
    const reporter = new istanbul.Reporter(false, folder);

    return new Promise((resolve, reject) => {
      try {
        this.coverage.generate(this.instrumenter.instrumentationData);

        const mapping = this.makeKeysRelative(this.coverage.data, this.cwd);
        this.saveCoverage(mapping);

        collector.add(mapping);

        this.istanbulReporter.forEach(report => reporter.add(report));

        // Pify doesn't like this one...
        reporter.write(collector, true, (err) => {
          if (err) return reject(err);

          this.ui.report('istanbul');
          resolve();
        });

      } catch (error) {
        error.message = this.ui.generate('istanbul-fail') + error.message;
        throw error;
      }
    })
  }

  /**
   * Removes coverage build artifacts, kills testrpc.
   */
  async finish() {
    if (this.server && this.server.close){
      this.ui.report('finish');
      await pify(this.server.close)();
    }
  }
  // ------------------------------------------ Utils ----------------------------------------------

  // ========
  // Provider
  // ========
  async attachToVM(client){
    const self = this;

    // Fallback to client from options
    if(!client) client = this.client;
    this.server = client.server(this.providerOptions);

    this.assertHasBlockchain(this.server.provider);
    await this.vmIsResolved(this.server.provider);

    const blockchain = this.server.provider.engine.manager.state.blockchain;
    const createVM = blockchain.createVMFromStateTrie;

    // Attach to VM which ganache has already created for transactions
    blockchain.vm.on('step', self.collector.step.bind(self.collector));

    // Hijack createVM method which ganache runs for each `eth_call`
    blockchain.createVMFromStateTrie = function(state, activatePrecompiles) {
      const vm = createVM.apply(blockchain, arguments);
      vm.on('step', self.collector.step.bind(self.collector));
      return vm;
    }
  }

  assertHasBlockchain(provider){
    assert(provider.engine.manager.state.blockchain !== undefined);
    assert(provider.engine.manager.state.blockchain.createVMFromStateTrie !== undefined);
  }

  async vmIsResolved(provider){
    return new Promise(resolve => {
      const interval = setInterval(() => {
        if (provider.engine.manager.state.blockchain.vm !== undefined){
          clearInterval(interval);
          resolve();
        }
      });
    })
  }

  // ========
  // File I/O
  // ========

  saveCoverage(data){
    const covPath = path.join(this.cwd, "coverage.json");
    fs.writeFileSync(covPath, JSON.stringify(data));
  }

  // =====
  // Paths
  // =====
  //
  /**
   * Relativizes path keys so that istanbul report can be read on Windows
   * @param  {Object} map  coverage map generated by coverageMap
   * @param  {String} wd   working directory
   * @return {Object}      map with relativized keys
   */
  makeKeysRelative(map, wd) {
    const newCoverage = {};

    Object
     .keys(map)
     .forEach(pathKey => newCoverage[path.relative(wd, pathKey)] = map[pathKey]);

    return newCoverage;
  }

  // =======
  // Logging
  // =======

  /**
   * Turn logging off (for CI)
   * @param {Boolean} isSilent
   */
  setLoggingLevel(isSilent) {
    if (isSilent) this.log = () => {};
  }

}

module.exports = API;
<commit_msg>Allowing providerOptions gasLimit and allowUnlimitedContractSize to override defaults (#494)<commit_after>const shell = require('shelljs');
const pify = require('pify');
const fs = require('fs');
const path = require('path');
const istanbul = require('sc-istanbul');
const assert = require('assert');
const detect = require('detect-port');
const _ = require('lodash/lang');

const ConfigValidator = require('./validator');
const Instrumenter = require('./instrumenter');
const Coverage = require('./coverage');
const DataCollector = require('./collector');
const AppUI = require('./ui').AppUI;

/**
 * Coverage Runner
 */
class API {
  constructor(config={}) {
    this.coverage = new Coverage();
    this.instrumenter = new Instrumenter();
    this.validator = new ConfigValidator()
    this.config = config || {};

    // Validate
    this.validator.validate(this.config);

    // Options
    this.testsErrored = false;

    this.cwd = config.cwd || process.cwd();

    this.defaultHook = () => {};
    this.onServerReady = config.onServerReady           || this.defaultHook;
    this.onTestsComplete = config.onTestsComplete       || this.defaultHook;
    this.onCompileComplete = config.onCompileComplete   || this.defaultHook;
    this.onIstanbulComplete = config.onIstanbulComplete || this.defaultHook;

    this.server = null;
    this.defaultPort = 8555;
    this.client = config.client;
    this.defaultNetworkName = 'soliditycoverage';
    this.port = config.port || this.defaultPort;
    this.host = config.host || "127.0.0.1";
    this.providerOptions = config.providerOptions || {};
    this.autoLaunchServer = config.autoLaunchServer === false ? false : true;

    this.skipFiles = config.skipFiles || [];

    this.log = config.log || console.log;

    this.gasLimit = 0xffffffffff;            // default "gas sent" with transactions
    this.gasLimitString = "0xfffffffffff";   // block gas limit for ganache (higher than "gas sent")
    this.gasPrice = 0x01;

    this.istanbulFolder = config.istanbulFolder || false;
    this.istanbulReporter = config.istanbulReporter || ['html', 'lcov', 'text', 'json'];

    this.setLoggingLevel(config.silent);
    this.ui = new AppUI(this.log);
  }

  /**
   * Instruments a set of sources to prepare them for running under coverage
   * @param  {Object[]}  targets (see below)
   * @return {Object[]}          (see below)
   * @example of input/output array:
   * [{
   *   source:         (required) <solidity-source>,
   *   canonicalPath:  (required) <absolute path to source file>
   *   relativePath:   (optional) <rel path to source file for logging>
   * }]
   */
  instrument(targets=[]) {
    let currentFile;      // Keep track of filename in case we crash...
    let started = false;
    let outputs = [];

    try {
      for (let target of targets) {
        currentFile = target.relativePath || target.canonicalPath;

        if(!started){
          started = true;
          this.ui.report('instr-start');
        }

        this.ui.report('instr-item', [currentFile]);

        const instrumented = this.instrumenter.instrument(
          target.source,
          target.canonicalPath
        );

        this.coverage.addContract(instrumented, target.canonicalPath);

        outputs.push({
          canonicalPath: target.canonicalPath,
          relativePath: target.relativePath,
          source: instrumented.contract
        })
      }

    } catch (err) {
      err.message = this.ui.generate('instr-fail', [currentFile]) + err.message;
      throw err;
    }

    return outputs;
  }

  /**
   * Returns a copy of the hit map created during instrumentation.
   * Useful if you'd like to delegate coverage collection to multiple processes.
   * @return {Object} instrumentationData
   */
  getInstrumentationData(){
    return _.cloneDeep(this.instrumenter.instrumentationData)
  }

  /**
   * Sets the hit map object generated during instrumentation. Useful if you'd like
   * to collect data for a pre-existing instrumentation.
   * @param {Object} data
   */
  setInstrumentationData(data={}){
    this.instrumenter.instrumentationData = _.cloneDeep(data);
  }

  /**
   * Enables coverage collection on in-process ethereum client server, hooking the DataCollector
   * to its VM. By default, method will return a url after server has begun listening on the port
   * specified in the config. When `autoLaunchServer` is false, method returns`ganache.server` so
   * the consumer can control the 'server.listen' invocation themselves.
   * @param  {Object} client             ganache client
   * @param  {Boolean} autoLaunchServer  boolean
   * @return {<Promise> (String | Server) }  address of server to connect to, or initialized, unlaunched server.
   */
  async ganache(client, autoLaunchServer){
    // Check for port-in-use
    if (await detect(this.port) !== this.port){
      throw new Error(this.ui.generate('server-fail', [this.port]))
    }

    this.collector = new DataCollector(this.instrumenter.instrumentationData);

    this.providerOptions.gasLimit =
      'gasLimit' in this.providerOptions
        ? this.providerOptions.gasLimit
        : this.gasLimitString;

    this.providerOptions.allowUnlimitedContractSize =
      'allowUnlimitedContractSize' in this.providerOptions
        ? this.providerOptions.allowUnlimitedContractSize
        : true;

    // Attach to vm step of supplied client
    try {
      if (this.config.forceBackupServer) throw new Error()
      await this.attachToVM(client)
    }

    // Fallback to ganache-cli)
    catch(err) {
      const _ganache = require('ganache-cli');
      this.ui.report('vm-fail', [_ganache.version]);
      await this.attachToVM(_ganache);
    }

    if (autoLaunchServer === false || this.autoLaunchServer === false){
      return this.server;
    }

    await pify(this.server.listen)(this.port);
    const address = `http://${this.host}:${this.port}`;
    this.ui.report('server', [address]);
    return address;
  }

  /**
   * Generate coverage / write coverage report / run istanbul
   */
  async report(_folder) {
    const folder = _folder || this.istanbulFolder;

    const collector = new istanbul.Collector();
    const reporter = new istanbul.Reporter(false, folder);

    return new Promise((resolve, reject) => {
      try {
        this.coverage.generate(this.instrumenter.instrumentationData);

        const mapping = this.makeKeysRelative(this.coverage.data, this.cwd);
        this.saveCoverage(mapping);

        collector.add(mapping);

        this.istanbulReporter.forEach(report => reporter.add(report));

        // Pify doesn't like this one...
        reporter.write(collector, true, (err) => {
          if (err) return reject(err);

          this.ui.report('istanbul');
          resolve();
        });

      } catch (error) {
        error.message = this.ui.generate('istanbul-fail') + error.message;
        throw error;
      }
    })
  }

  /**
   * Removes coverage build artifacts, kills testrpc.
   */
  async finish() {
    if (this.server && this.server.close){
      this.ui.report('finish');
      await pify(this.server.close)();
    }
  }
  // ------------------------------------------ Utils ----------------------------------------------

  // ========
  // Provider
  // ========
  async attachToVM(client){
    const self = this;

    // Fallback to client from options
    if(!client) client = this.client;
    this.server = client.server(this.providerOptions);

    this.assertHasBlockchain(this.server.provider);
    await this.vmIsResolved(this.server.provider);

    const blockchain = this.server.provider.engine.manager.state.blockchain;
    const createVM = blockchain.createVMFromStateTrie;

    // Attach to VM which ganache has already created for transactions
    blockchain.vm.on('step', self.collector.step.bind(self.collector));

    // Hijack createVM method which ganache runs for each `eth_call`
    blockchain.createVMFromStateTrie = function(state, activatePrecompiles) {
      const vm = createVM.apply(blockchain, arguments);
      vm.on('step', self.collector.step.bind(self.collector));
      return vm;
    }
  }

  assertHasBlockchain(provider){
    assert(provider.engine.manager.state.blockchain !== undefined);
    assert(provider.engine.manager.state.blockchain.createVMFromStateTrie !== undefined);
  }

  async vmIsResolved(provider){
    return new Promise(resolve => {
      const interval = setInterval(() => {
        if (provider.engine.manager.state.blockchain.vm !== undefined){
          clearInterval(interval);
          resolve();
        }
      });
    })
  }

  // ========
  // File I/O
  // ========

  saveCoverage(data){
    const covPath = path.join(this.cwd, "coverage.json");
    fs.writeFileSync(covPath, JSON.stringify(data));
  }

  // =====
  // Paths
  // =====
  //
  /**
   * Relativizes path keys so that istanbul report can be read on Windows
   * @param  {Object} map  coverage map generated by coverageMap
   * @param  {String} wd   working directory
   * @return {Object}      map with relativized keys
   */
  makeKeysRelative(map, wd) {
    const newCoverage = {};

    Object
     .keys(map)
     .forEach(pathKey => newCoverage[path.relative(wd, pathKey)] = map[pathKey]);

    return newCoverage;
  }

  // =======
  // Logging
  // =======

  /**
   * Turn logging off (for CI)
   * @param {Boolean} isSilent
   */
  setLoggingLevel(isSilent) {
    if (isSilent) this.log = () => {};
  }

}

module.exports = API;
<|endoftext|>


<commit_before>import React from 'react';
import { text } from '@storybook/addon-knobs';

import { addStoryInGroup, MID_LEVEL_BLOCKS } from '../../../.storybook/utils';
import { WysiwygEditor } from '../../index';

export default {
  component: WysiwygEditor,
  title: addStoryInGroup(MID_LEVEL_BLOCKS, 'WysiwygEditor'),
};

export const wysiwygEditor = () => (
  <WysiwygEditor
    placeholder="Placeholder text"
    error={text('Error', '')}
    success={text('Success', '')}
    warning={text('Warning', '')}
    helpText={text('Help text', '')}
    width={text('Width', undefined)}
  />
);
<commit_msg>WysiwygEditor: update story<commit_after>import React from 'react';
import { addStoryInGroup, MID_LEVEL_BLOCKS } from '../../../.storybook/utils';
import WysiwygEditor from './WysiwygEditor';

export default {
  component: WysiwygEditor,
  title: addStoryInGroup(MID_LEVEL_BLOCKS, 'WysiwygEditor'),
};

export const Basic = (args) => <WysiwygEditor {...args} />;

Basic.args = {
  placeholder: 'Placeholder text',
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, 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.
 *
 * @flow
 */

'use strict';

const React = require('react');
const immutable = require('immutable');

import type {
  ControlState,
} from './BananaSlugTypes';

type Props = {
  onChange: (v: ControlState) => void,
};

type State = {};

type DefaultProps = {};

const StateRecord = immutable.Record({
  enabled: false,
});

class BananaSlugFrontendControl extends
  React.Component<DefaultProps, Props, State> {
  _defaultState: ControlState;
  _toogle: (b: boolean) => void;

  constructor(props: Props) {
    super(props);
    this._toogle = this._toogle.bind(this);
    this._defaultState = new StateRecord();
  }

  componentDidMount(): void {
    if (!this.props.state !== this._defaultState) {
      this.props.onChange(this._defaultState);
    }
  }

  render(): ReactElement {
    var state = this.props.state || this._defaultState;
    return (

        <input
          style={styles.checkbox}
          type="checkbox"
          checked={state.enabled}
          readOnly={true}
        />
        trace react updates

    );
  }

  _toogle() {
    var state = this.props.state || this._defaultState;
    var nextState = state.merge({
      enabled: !state.enabled,
    });

    this.props.onChange(nextState);
  }
}

var styles = {
  checkbox: {
    pointerEvents: 'none',
  },
  container: {
    WebkitUserSelect: 'none',
    cursor: 'pointer',
    display: 'inline-block',
    fontFamily: 'arial',
    fontSize: '12px',
    outline: 'none',
    userSelect: 'none',
  },
};

module.exports = BananaSlugFrontendControl;
<commit_msg>fix typo<commit_after>/**
 * Copyright (c) 2015-present, 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.
 *
 * @flow
 */

'use strict';

const React = require('react');
const immutable = require('immutable');

import type {
  ControlState,
} from './BananaSlugTypes';

type Props = {
  onChange: (v: ControlState) => void,
};

type State = {};

type DefaultProps = {};

const StateRecord = immutable.Record({
  enabled: false,
});

class BananaSlugFrontendControl extends
  React.Component<DefaultProps, Props, State> {
  _defaultState: ControlState;
  _toggle: (b: boolean) => void;

  constructor(props: Props) {
    super(props);
    this._toggle = this._toggle.bind(this);
    this._defaultState = new StateRecord();
  }

  componentDidMount(): void {
    if (!this.props.state !== this._defaultState) {
      this.props.onChange(this._defaultState);
    }
  }

  render(): ReactElement {
    var state = this.props.state || this._defaultState;
    return (

        <input
          style={styles.checkbox}
          type="checkbox"
          checked={state.enabled}
          readOnly={true}
        />
        trace react updates

    );
  }

  _toggle() {
    var state = this.props.state || this._defaultState;
    var nextState = state.merge({
      enabled: !state.enabled,
    });

    this.props.onChange(nextState);
  }
}

var styles = {
  checkbox: {
    pointerEvents: 'none',
  },
  container: {
    WebkitUserSelect: 'none',
    cursor: 'pointer',
    display: 'inline-block',
    fontFamily: 'arial',
    fontSize: '12px',
    outline: 'none',
    userSelect: 'none',
  },
};

module.exports = BananaSlugFrontendControl;
<|endoftext|>


<commit_before>'use strict';

var util = require('./util.js');
var scanFiles = require('./scan.js');
var analyzeFiles = require('./analyze.js');

var cani = function (files, browsers) {
  util.getFileList(files)
    .then(scanFiles)
    .then(analyzeFiles)
    .then(function(badTokens) {
      console.log(badTokens);
    });
};

module.exports = cani;
<commit_msg>Log more complete information<commit_after>'use strict';

var util = require('./util.js');
var scanFiles = require('./scan.js');
var analyzeFiles = require('./analyze.js');

var cani = function (files, browsers) {
  util.getFileList(files)
    .then(scanFiles)
    .then(analyzeFiles)
    .then(function(badTokens) {
      console.log(JSON.stringify(badTokens));
    });
};

module.exports = cani;
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import { List } from 'immutable'

const TransactionList = ({transactions}) => {
	if (transactions.size === 0) {
		return (

 No recent transactions

		)
	}
	const transactionComponents = transactions.map((txn, key) => {
		let valueData = ''
		if (txn.transactionsums.totalSiacoin.abs().gt(0)) {
			valueData += txn.transactionsums.totalSiacoin.round(4).toString() + ' SC '
		}
		if (txn.transactionsums.totalSiafund.abs().gt(0)) {
			valueData += txn.transactionsums.totalSiafund.round(4).toString() + ' SF '
		}
		if (txn.transactionsums.totalMiner.abs().gt(0)) {
			valueData += txn.transactionsums.totalMiner.round(4).toString() + ' SC (miner) '
		}
		if (valueData === '') {
			valueData = '0 SC'
		}
		return (

				{valueData}
				{txn.transactionid}
				{txn.confirmed ?  Confirmed  :  Unconfirmed }

		)
	})
	return (

 Recent Transactions

						Net Value
						Transaction ID
						Confirmation Status

					{transactionComponents}

	)
}

TransactionList.propTypes = {
	transactions: PropTypes.instanceOf(List).isRequired,
}

export default TransactionList
<commit_msg>remove unused txval css class<commit_after>import React, { PropTypes } from 'react'
import { List } from 'immutable'

const TransactionList = ({transactions}) => {
	if (transactions.size === 0) {
		return (

 No recent transactions

		)
	}
	const transactionComponents = transactions.map((txn, key) => {
		let valueData = ''
		if (txn.transactionsums.totalSiacoin.abs().gt(0)) {
			valueData += txn.transactionsums.totalSiacoin.round(4).toString() + ' SC '
		}
		if (txn.transactionsums.totalSiafund.abs().gt(0)) {
			valueData += txn.transactionsums.totalSiafund.round(4).toString() + ' SF '
		}
		if (txn.transactionsums.totalMiner.abs().gt(0)) {
			valueData += txn.transactionsums.totalMiner.round(4).toString() + ' SC (miner) '
		}
		if (valueData === '') {
			valueData = '0 SC'
		}
		return (

				{valueData}
				{txn.transactionid}
				{txn.confirmed ?  Confirmed  :  Unconfirmed }

		)
	})
	return (

 Recent Transactions

						Net Value
						Transaction ID
						Confirmation Status

					{transactionComponents}

	)
}

TransactionList.propTypes = {
	transactions: PropTypes.instanceOf(List).isRequired,
}

export default TransactionList
<|endoftext|>


<commit_before>"use strict";

/*

   - next
        x param(eter)s("name", "age").
        x callback("message", "age_plus_ten");
        - serve it.
        - build a client
            - api.hash(); -> method.hash() -> { echo: { expects: [], callback: [], role: "public", local: true } }

*/

/*

maybe api_manager.load. create a blank from api_manager.api(“user”).

use api.lock() and api_manager.lock() to prevent mutation, and spelling mistakes? I think it might be overkill.

method.params(“string”, “times”).documentation(“blah, blah, blah”)

maybe not on the documentation? although we should automate that in some way.

*/

var _ = require('dry-underscore');

var method_class = require('./method.js');
var type_expector_class = require('./expectors/type_expector.js');

function api(name, access_manager, log){

    if(!access_manager){ _.fatal("api must be provided an access_manager"); }

    this._parent = null;
    this._name = name || "default";
    this._methods = {};
    this._access_manager = access_manager;
    this._log = log || _.log;
    this._expectors = _.fchain();

    var type_expector = new type_expector_class();

    this.expector(_.bind(type_expector.match, type_expector));

    this.context_timeout = 1000;
    this.prepare_arguments_timeout = 1000;

    this._init_errors();
    this._init_role_functions();
}

_.hook(api.prototype);

api.prototype._set_parent = function(p){ this._parent = p; };
api.prototype.parent = _.r("_parent");

api.prototype.context = _.hook.event_function("context");
api.prototype.prepare_arguments = _.hook.event_function("prepare_arguments");
api.prototype.expector = function(f){
    this._expectors.add(f);
};

api.prototype.log = _.r("_log");
api.prototype.name = _.r("_name");
api.prototype.errors = _.r("_errors");
api.prototype.access_manager = _.r("_access_manager");
api.prototype.roles = function(){ return(this.access_manager().roles()); };

api.prototype._init_errors = function(){
    var errors = _.errors();

    errors.add("failure", "failure");
    errors.add("error", "error");
    errors.add("unknown_api", "unknown api");
    errors.add("unknown_method", "unknown method");
    errors.add("malformed_call", "malformed call");
    errors.add("method_error", "method error");
    errors.add("down_for_maintenance", "down for maintenance");
    errors.add("permission_error", "permission error");

    this._errors = errors;
};

api.prototype.hash = function(include_local){
    var self = this;

    var hash = {};

    var roles = self.access_manager().roles().hash();

    _.each(self._methods, function(methods, role_name){
        _.each(methods, function(method, method_name){
            if(roles[role_name].serve === false && !include_local){ return; }

            if(!hash[role_name]){ hash[role_name] = {}; }
            hash[role_name][method.name()] = method.hash();
        });
    });

    return(hash);
};

api.prototype._init_role_functions = function(){
    var self = this;

    _.each(self.roles().array(), function(role){
        var role_name = role.role;

        if(self[role_name]){ _.fatal("The names of properties of the api class must not be used as role names. You attempted to use the role name: " + role.role); }
        if(!self._methods[role_name]){ self._methods[role_name] = {}; }

        self[role_name] = function(name, method, expects){
            self._methods[role_name][name] = new method_class(role_name, name, method, expects);
            return(self._methods[role_name][name]);
        };
    });
};

api.prototype.method = function(role, method_name){
    return(this._methods[role][method_name] || null);
};

api.prototype.call_expectors = function(arg, expectations, callback){
   this._expectors.call(arg, expectations, callback);
};

// TODO: HACK: right now we only "look" like we support async expectors, we don't.
// if we want to support async expectors, we need to change _.beach to each.async
// we also need to change _.fchain to something that supports async calling
// we built it like this so we could move that way in the future
// but not spend time somewhere we didn't need to

api.prototype.validate_argument = function(index, arg, expectations, callback){

    if(!_.isArray(expectations)){ expectations = [expectations]; }

    var error = null;
    var is_valid = false;

    if(this.parent()){
        this.parent().call_expectors(arg, expectations, function(err, valid){
            if(err){ error = err; return(false); }
            if(valid){ is_valid = true; return(false); }
        });
    }

    if(!error && !is_valid){
        this.call_expectors(arg, expectations, function(err, valid){
            if(err){ error = err; return(false); }
            if(valid){ is_valid = true; return(false); }
        });
    }

    if(error){ return callback(error); }
    else if(!is_valid){ return callback(_.error("bad_parameter", "parameter: " + index + " did not meet expectations: " + expectations)); }
    else{ callback(null); }
};

api.prototype.validate_expectations = function(method, args, callback){
    var self = this;

    if(!method.expects()){ return callback(null); }

    _.each.async(method.expects(), function(expectations, i, next, done){
        self.validate_argument(i, args[i], expectations, function(err){
            if(err){ return callback(err); }
            next();
        });

    }, function(){ callback(null); });
};

api.prototype.process_context = function(context){

    if(!context){ context = {}; }

    if(!context.roles){ context.roles = []; }

    if(context.local === undefined){
        context.local = false;
    }

    return(context);
};

api.prototype.get_context = function(context, callback){
    var self = this;

    function get_context_self(context){
        self.bite("context", [context], callback, self.context_timeout);
    }

    if(self.parent()){
        self.parent().get_context(context, function(err, context){
            if(err){ return callback(err); }
            else{ get_context_self(context); }
        });
    }else{
        get_context_self(context);
    }
};

api.prototype.find_method = function(method_name, context, callback){

    var self = this;

    if(!method_name){ _.fatal("api.find_method: must pass a method_name."); }
    if(!callback){ _.fatal("api.find_method: must pass a callback."); }

    var method = null;
    var has_access = false;
    var method_exists = false;

    _.beach(self.roles().array(), function(role){

        var role_name = role.role;

        method = null;
        has_access = false;

        if(self.method(role_name, method_name) && (role.serve === true || context.local === true)){
            method_exists = true;
            method = self.method(role_name, method_name);
        }

        if(method && (_.contains(context.roles, role_name) || role.anon)){
            has_access = true;
        }

        if(method && has_access){ return(false); }
    });

    if(!method_exists){
        return callback(self.errors().unknown_method());
    }

    if(!has_access){
        return callback(self.errors().permission_error());
    }

    // method exists, and we have access

    callback(null, method);
};

api.prototype.get_prepared_arguments = function(args, callback){

    var self = this;

    function get_prepared_arguments_self(args){
        self.bite("prepare_arguments", [args], callback, self.prepare_arguments_timeout);
    }

    if(self.parent()){
        self.parent().get_prepared_arguments(args, function(err, args){
            if(err){ return callback(err); }
            else{ get_prepared_arguments_self(args); }
        });
    }else{
        get_prepared_arguments_self(args);
    }
};

api.prototype.call = function(method_name, context, args, callback){

    var self = this;

    if(!method_name){ _.fatal("api.call: must pass a method_name."); }
    if(!args){ _.fatal("api.call: must pass args for method call."); }
    if(!callback){ _.fatal("api.call: must pass a callback."); }

    // this shallow copies the context
    context = self.process_context(context);

    self.access_manager().get(context.access_token, _.plumb(function(security_context){

        context = _.extend(context, security_context);

        self.get_context(context, _.plumb(function(context){

            self.find_method(method_name, context, _.plumb(function(method){

                self.get_prepared_arguments(args, _.plumb(function(args){

                    self.validate_expectations(method, args, _.plumb(function(){

                        // assertions throw errors
                        if(self.testing){ return method.apply(context, args, callback);  }

                        try{ return method.apply(context, args, callback); }
                        catch(e){ return callback(self.errors().method_error(e)); }

                    }, callback));

                }, callback));

            }, callback));

        }, callback));

     }, callback));
};

module.exports = api;

<commit_msg>add todo<commit_after>"use strict";

/*
    TODO:
        - ability to convert the whole request into an object, instead of params
            - api.public("make_call", funcition(callback, call){ call.some_method(); }).deserialize(dry.call);
            - this is a one off however, to support twilio like api calls (which seem to be popular).
            - we can allow any object that takes a hash as the first (and only) parameter
        - the rest of the time, we'll just deserialize all the parameters, which makes for uglier api calls,
            - but better in language apis.
            - { last_call: { type: 'call', to: '555-555-5555' },
                history: [
                    { type: "call", from: '...' },
                    { type: "call", from: '...' },
                ],
                params_map: ['last_call', 'history']
              }
        - this doesn't need to be done right now.

*/

/*

maybe api_manager.load. create a blank from api_manager.api(“user”).

use api.lock() and api_manager.lock() to prevent mutation, and spelling mistakes? I think it might be overkill.

method.params(“string”, “times”).documentation(“blah, blah, blah”)

maybe not on the documentation? although we should automate that in some way.

*/

var _ = require('dry-underscore');

var method_class = require('./method.js');
var type_expector_class = require('./expectors/type_expector.js');

function api(name, access_manager, log){

    if(!access_manager){ _.fatal("api must be provided an access_manager"); }

    this._parent = null;
    this._name = name || "default";
    this._methods = {};
    this._access_manager = access_manager;
    this._log = log || _.log;
    this._expectors = _.fchain();

    var type_expector = new type_expector_class();

    this.expector(_.bind(type_expector.match, type_expector));

    this.context_timeout = 1000;
    this.prepare_arguments_timeout = 1000;

    this._init_errors();
    this._init_role_functions();
}

_.hook(api.prototype);

api.prototype._set_parent = function(p){ this._parent = p; };
api.prototype.parent = _.r("_parent");

api.prototype.context = _.hook.event_function("context");
api.prototype.prepare_arguments = _.hook.event_function("prepare_arguments");
api.prototype.expector = function(f){
    this._expectors.add(f);
};

api.prototype.log = _.r("_log");
api.prototype.name = _.r("_name");
api.prototype.errors = _.r("_errors");
api.prototype.access_manager = _.r("_access_manager");
api.prototype.roles = function(){ return(this.access_manager().roles()); };

api.prototype._init_errors = function(){
    var errors = _.errors();

    errors.add("failure", "failure");
    errors.add("error", "error");
    errors.add("unknown_api", "unknown api");
    errors.add("unknown_method", "unknown method");
    errors.add("malformed_call", "malformed call");
    errors.add("method_error", "method error");
    errors.add("down_for_maintenance", "down for maintenance");
    errors.add("permission_error", "permission error");

    this._errors = errors;
};

api.prototype.hash = function(include_local){
    var self = this;

    var hash = {};

    var roles = self.access_manager().roles().hash();

    _.each(self._methods, function(methods, role_name){
        _.each(methods, function(method, method_name){
            if(roles[role_name].serve === false && !include_local){ return; }

            if(!hash[role_name]){ hash[role_name] = {}; }
            hash[role_name][method.name()] = method.hash();
        });
    });

    return(hash);
};

api.prototype._init_role_functions = function(){
    var self = this;

    _.each(self.roles().array(), function(role){
        var role_name = role.role;

        if(self[role_name]){ _.fatal("The names of properties of the api class must not be used as role names. You attempted to use the role name: " + role.role); }
        if(!self._methods[role_name]){ self._methods[role_name] = {}; }

        self[role_name] = function(name, method, expects){
            self._methods[role_name][name] = new method_class(role_name, name, method, expects);
            return(self._methods[role_name][name]);
        };
    });
};

api.prototype.method = function(role, method_name){
    return(this._methods[role][method_name] || null);
};

api.prototype.call_expectors = function(arg, expectations, callback){
   this._expectors.call(arg, expectations, callback);
};

// TODO: HACK: right now we only "look" like we support async expectors, we don't.
// if we want to support async expectors, we need to change _.beach to each.async
// we also need to change _.fchain to something that supports async calling
// we built it like this so we could move that way in the future
// but not spend time somewhere we didn't need to

api.prototype.validate_argument = function(index, arg, expectations, callback){

    if(!_.isArray(expectations)){ expectations = [expectations]; }

    var error = null;
    var is_valid = false;

    if(this.parent()){
        this.parent().call_expectors(arg, expectations, function(err, valid){
            if(err){ error = err; return(false); }
            if(valid){ is_valid = true; return(false); }
        });
    }

    if(!error && !is_valid){
        this.call_expectors(arg, expectations, function(err, valid){
            if(err){ error = err; return(false); }
            if(valid){ is_valid = true; return(false); }
        });
    }

    if(error){ return callback(error); }
    else if(!is_valid){ return callback(_.error("bad_parameter", "parameter: " + index + " did not meet expectations: " + expectations)); }
    else{ callback(null); }
};

api.prototype.validate_expectations = function(method, args, callback){
    var self = this;

    if(!method.expects()){ return callback(null); }

    _.each.async(method.expects(), function(expectations, i, next, done){
        self.validate_argument(i, args[i], expectations, function(err){
            if(err){ return callback(err); }
            next();
        });

    }, function(){ callback(null); });
};

api.prototype.process_context = function(context){

    if(!context){ context = {}; }

    if(!context.roles){ context.roles = []; }

    if(context.local === undefined){
        context.local = false;
    }

    return(context);
};

api.prototype.get_context = function(context, callback){
    var self = this;

    function get_context_self(context){
        self.bite("context", [context], callback, self.context_timeout);
    }

    if(self.parent()){
        self.parent().get_context(context, function(err, context){
            if(err){ return callback(err); }
            else{ get_context_self(context); }
        });
    }else{
        get_context_self(context);
    }
};

api.prototype.find_method = function(method_name, context, callback){

    var self = this;

    if(!method_name){ _.fatal("api.find_method: must pass a method_name."); }
    if(!callback){ _.fatal("api.find_method: must pass a callback."); }

    var method = null;
    var has_access = false;
    var method_exists = false;

    _.beach(self.roles().array(), function(role){

        var role_name = role.role;

        method = null;
        has_access = false;

        if(self.method(role_name, method_name) && (role.serve === true || context.local === true)){
            method_exists = true;
            method = self.method(role_name, method_name);
        }

        if(method && (_.contains(context.roles, role_name) || role.anon)){
            has_access = true;
        }

        if(method && has_access){ return(false); }
    });

    if(!method_exists){
        return callback(self.errors().unknown_method());
    }

    if(!has_access){
        return callback(self.errors().permission_error());
    }

    // method exists, and we have access

    callback(null, method);
};

api.prototype.get_prepared_arguments = function(args, callback){

    var self = this;

    function get_prepared_arguments_self(args){
        self.bite("prepare_arguments", [args], callback, self.prepare_arguments_timeout);
    }

    if(self.parent()){
        self.parent().get_prepared_arguments(args, function(err, args){
            if(err){ return callback(err); }
            else{ get_prepared_arguments_self(args); }
        });
    }else{
        get_prepared_arguments_self(args);
    }
};

api.prototype.call = function(method_name, context, args, callback){

    var self = this;

    if(!method_name){ _.fatal("api.call: must pass a method_name."); }
    if(!args){ _.fatal("api.call: must pass args for method call."); }
    if(!callback){ _.fatal("api.call: must pass a callback."); }

    // this shallow copies the context
    context = self.process_context(context);

    self.access_manager().get(context.access_token, _.plumb(function(security_context){

        context = _.extend(context, security_context);

        self.get_context(context, _.plumb(function(context){

            self.find_method(method_name, context, _.plumb(function(method){

                self.get_prepared_arguments(args, _.plumb(function(args){

                    self.validate_expectations(method, args, _.plumb(function(){

                        // assertions throw errors
                        if(self.testing){ return method.apply(context, args, callback);  }

                        try{ return method.apply(context, args, callback); }
                        catch(e){ return callback(self.errors().method_error(e)); }

                    }, callback));

                }, callback));

            }, callback));

        }, callback));

     }, callback));
};

module.exports = api;

<|endoftext|>


<commit_before>import express from "express";
import bodyParser from "body-parser";
import low from "lowdb";
import storage from "lowdb/file-sync";
import fs from "fs";
import {API} from "./api";
import {Keystore} from "./keystore";
import {DeviceManager} from "./device-manager";

export class App {
  constructor(manifestPath, publicPath) {
    this.manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
    this.routes = express().use(express.static(publicPath)).use(bodyParser.json());
    this.api = new API(this);
    this.devices = null;
    this.deviceManager = null;
    this.db = null;
    this.keystore = null;
  }

  run() {
    return new Promise(resolve => {
      let server = this.routes.listen(0, () => {
        // Inform the Hub API of the server's port number.
        this.api.appInstallations.updateAppInstallation({ port: server.address().port })
        .then(appInstallation => {
          this.devices = appInstallation.installation_devices.reduce((map, installationDevice) => {
            return map.set(installationDevice.reference_device_name, installationDevice.device_id);
          }, new Map());

          this.deviceManager = new DeviceManager(this);

          this.db = low(appInstallation.database_path, { storage });

          this.keystore = new Keystore(this.db);

          resolve();
        }).catch(err => {
          console.error(err);
          process.exit(1);
        });
      });
    });
  }
}
<commit_msg>add a log message on start<commit_after>import express from "express";
import bodyParser from "body-parser";
import low from "lowdb";
import storage from "lowdb/file-sync";
import fs from "fs";
import {API} from "./api";
import {Keystore} from "./keystore";
import {DeviceManager} from "./device-manager";

export class App {
  constructor(manifestPath, publicPath) {
    this.manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
    this.routes = express().use(express.static(publicPath)).use(bodyParser.json());
    this.api = new API(this);
    this.devices = null;
    this.deviceManager = null;
    this.db = null;
    this.keystore = null;
  }

  run() {
    return new Promise(resolve => {
      let server = this.routes.listen(0, () => {
        // Inform the Hub API of the server's port number.
        this.api.appInstallations.updateAppInstallation({ port: server.address().port })
        .then(appInstallation => {
          this.devices = appInstallation.installation_devices.reduce((map, installationDevice) => {
            return map.set(installationDevice.reference_device_name, installationDevice.device_id);
          }, new Map());

          this.deviceManager = new DeviceManager(this);

          this.db = low(appInstallation.database_path, { storage });

          this.keystore = new Keystore(this.db);

          resolve();

		  console.log("Application Started");
        }).catch(err => {
          console.error(err);
          process.exit(1);
        });
      });
    });
  }
}
<|endoftext|>


<commit_before>/**
 * conjoon
 * (c) 2002-2012 siteartwork.de/conjoon.org
 * licensing@conjoon.org
 *
 * $Author$
 * $Id$
 * $Date$
 * $Revision$
 * $LastChangedDate$
 * $LastChangedBy$
 * $URL$
 */

Ext.namespace('com.conjoon.groupware.email');

/**
 * Controller for previewing Feed contents.
 * This is a singleton-object and used bycom.conjoon.groupware.feeds.FeedGrid
 * to enable previewing a feed in a panel sliding out left of the grid panel,
 * aligned to the current selected cell. The panel is closable and draggable.
 * Once a panel was created, it can not be closed such that the object gets
 * destroyed.
 *
 * The preview panel depends on record properties passed from the grid to the
 * showPreview-method. The needed properties are
 *
 *

 *
id - the id of the feed to preview

 *
title - the title of the feed

 *
link - the link of the feed  of the feed to preview

 *
pubDate - the publication date of the feed

 *

 *
 * @author Thorsten Suckow-Homberg <tsuckow@conjoon.org>
 */
com.conjoon.groupware.email.EmailPreview = function() {

// {{{ private members

    /**
     * @type {Ext.Element} gridEl The element of the grid the preview is attached to
     */
    var gridEl = null;

    /**
     * Initial width of the preview panel.
     * @param {Number}
     */
    var width = 330;

    /**
     * Initial height of the preview panel.
     * @param {Number}
     */
    var height = 250;

    /**
     * The y position of the last clicked cell.
     * @param {Number} clkCellY
     */
    var clkCellY = 0;

    /**
     * Stores the id of the last previewed feed. If a preview panel gets closed,
     * the property will be reset to <tt>null</tt>.
     */
    var activeEmailId = null;

    /**
     * The html container that is responsible for enabling animation effects
     * of the preview panel.
     */
    var container = null;

    /**
     * The panel that is used for previewing a feed content. The property will
     * hold an instance of <tt>Ext.Panel</tt> which is being reused for previewing
     * until the panel was detached from the grid.
     */
    var previewPanel = null;

    /**
     * Stores the active cell to which the preview panel is aligned.
     */
    var clkCell = null;

    /**
     * Stores the row index of the cell to which the preview panel is aligned.
     */
    var clkRowIndex = -1;

    /**
     * Stores the record information of the cell's row associated with previewing.
     * The record needs to have a id-property that holds a unique id of the
     * grid's record that was selected.
     */
    var clkRecord = null;

    var loadMask = null;

    var emailView = null;

    var lastRecord = null;

// }}}

// {{{ private methods

    /**
     * Returns the first left outermost columnIndex of the first column
     * that is not hidden in the grid.
     * This method is guaranteed to return a value in the range of [0, columnIndex].
     *
     * @param {Ext.grid.GridPanel} grid
     * @param {Numbe} columnIndex
     *
     * @return {Number}
     */
    var _getColumnIndex = function(grid, columnIndex)
    {
        var colModel = grid.getColumnModel();
        i = 0;
        while (i < columnIndex) {
            if (!colModel.isHidden(i)) {
                return i;
            }
            i++;
        }

        return i;
    };

    /**
     * Callback.
     * Called when the preview panel's show-animation is finished.
     */
    var onShow = function()
    {
        emailView.show();
        var viewHeight  = Ext.fly(document.body).getHeight();
        var panelHeight = previewPanel.el.getHeight();

        if (clkCellY + panelHeight > viewHeight) {
            container.shift({
                y : container.getY() - (((clkCellY + panelHeight) - viewHeight) + 4)
            });
        }
    };

    var onBeforeLoad = function()
    {
        loadMask.show();
        emailView.hide();
    };

    var onLoadFailure = function(response, options)
    {
        com.conjoon.groupware.ResponseInspector.handleFailure(response, {
            onLogin: {
                fn : function(){
                    decoratePreviewPanel();
                }
            }
        });
        previewPanel.close();
        loadMask.hide();
    };

    var onLoadSuccess = function()
    {
        lastRecord = emailView.emailRecord;

        loadMask.hide();
        previewPanel.setTitle(lastRecord.get('subject'));
    };

    /**
     * Inits any component that is needed for displaying/animating
     * the preview panel.
     * This method will only be called once.
     */
    var initComponents = function()
    {
        container = Ext.DomHelper.append(document.body, {
            id    : 'DOM:com.conjoon.groupware.email.EmailPreview.container',
            style : "position:absolute;overflow:hidden;height:"+(height+5)+"px;width:"+width+"px"
        }, true);
    };

    /**
     * Callback.
     * Called when the preview panel's hide-animation is finished.
     */
    var onHide = function(skipAlign)
    {
        emailView.abortRequest();

        previewPanel.setTitle(com.conjoon.Gettext.gettext("Loading..."));

        if (skipAlign === true) {
            return;
        }

        refreshAnimSettings();
    };

    /**
     * Loads the feed's data into the preview panel.
     */
    var decoratePreviewPanel = function()
    {
        if (clkRecord == null) {
            return;
        }

        var subject = clkRecord.get('subject');
        var rec = com.conjoon.groupware.email.EmailViewBaton.getRecord(clkRecord.id);
        if (rec) {
            lastRecord = rec;
            emailView.emailRecord = rec;
            emailView.renderView();
        } else {
            emailView.setEmailItem(clkRecord)
        }

        previewPanel.setTitle(subject);
    }

    /**
     * Callback.
     * Called after the panel was detached from the grid and dropped anywhere
     * on the document body.
     * Sets <tt>previewPanel</tt> to <tt>null</tt> to notify the <tt>show</tt> method
     * to create a new preview panel.
     *
     */
    var onMove = function()
    {
        if (lastRecord == null) {
            previewPanel.close();
            return;
        }
        var emailItem = lastRecord.copy();
        previewPanel.close();
        var view = com.conjoon.groupware.email.EmailViewBaton.showEmail(emailItem, {
            autoLoad : false
        }, true);

    };

    /**
     * Creates a window for displaying email contents.
     *
     * @return {Ext.Window} The window used for previewing.
     */
    var createPreviewWindow = function()
    {
        var templateConfig = {
            header : new Ext.Template(
                '
',
                   '
',
                    '{date:date("d.m.Y H:i")}',
                    '{subject}',
                    '
',
                    '{from}',
                    '{replyTo}',
                    '{to}',
                    '{cc}',
                    '{bcc}',
                    '
',
                   '
',
                '
'
        )};

        emailView = new com.conjoon.groupware.email.EmailViewPanel({
            autoLoad     : false,
            refreshFrame : true,
            border       :  false,
            hideMode     : 'visibility',
            viewConfig   : {
                templates        : templateConfig,
                fromValue        : com.conjoon.Gettext.gettext("From"),
                toValue          : com.conjoon.Gettext.gettext("To"),
                ccValue          : com.conjoon.Gettext.gettext("CC"),
                bccValue         : com.conjoon.Gettext.gettext("BCC")
            }
        });

        var win =  new Ext.Window({
            bodyStyle  : 'background:white;',
            autoScroll : false,
            layout     : 'fit',
            title      : ("Loading..."),
            iconCls    : 'com-conjoon-groupware-email-EmailPreview-Icon',
            resizable  : false,
            shadow     : false,
            hideMode   : 'visibility',
            items      : [emailView],
            height     : height,
            width      : width
        });

        win.mon(emailView, 'emailload',        onLoadSuccess, com.conjoon.groupware.email.EmailPreview);
        win.mon(emailView, 'beforeemailload',  onBeforeLoad, com.conjoon.groupware.email.EmailPreview);
        win.mon(emailView, 'emailloadfailure', onLoadFailure, com.conjoon.groupware.email.EmailPreview);

        win.on('render', function() {
            this.mon(this.header, 'dblclick', function(){
               onMove();
            }, this);
        }, win, {single : true});

        win.initDraggable = function() {
            Ext.Window.prototype.initDraggable.call(this);

            this.dd.b4Drag = function(e) {
                container.dom.style.overflow = "visible";
            };

            this.dd.endDrag = function(e){
                this.win.unghost(true, false);
                this.win.setPosition(0, 0);
                this.win.saveState();
                container.dom.style.overflow = "hidden";
            };
        }

        return win;
    };

    var animConfig = 'r';

    var refreshAnimSettings = function()
    {
        var x = gridEl.getX();

        // this should work in most cases - determine if the panel is rendered
        // in the left side of the workbench
        if (x <= 50) {
            x += gridEl.getSize().width;
            animConfig = 'l';
        } else {
            x -= container.getSize().width;
            animConfig = 'r';
        }

        container.setY(clkCellY);
        container.setX(x);
    };

// }}}

    return {

        getLastRecord : function()
        {
            return lastRecord;
        },

        getActiveRecord : function()
        {
            return clkRecord;
        },

        /**
         * Shows the preview panel using a slide-in animation effect.
         * The preview will not been shown if ctrl or shift was pressed while
         * calling this method.
         *
         * @param {Ext.grid.GridPanel} The grid panel that calls this method.
         * @param {Number} The row index of the cell the panel is aligned to.
         * @param {Number} The column index of the cell the panel is aligned to.
         * @param {Ext.EventObject} The raw event object that triggered this method.
         */
        show : function(grid, record)
        {
            if (!record) {
                return;
            }
            clkRecord = record.copy();

            var store    = grid.getStore(),
                /**
                 * @ticket CN-821
                 */
                rowIndex = store.indexOf(record) + store.bufferRange[0];

            var pId = clkRecord.id;
            if (activeEmailId == pId) {
                // previewing is already active for this record.
                return;
            }

            // lazy create needed components
            if (container == null) {
                initComponents.call(this);
            }

            clkRowIndex  = rowIndex;
            clkCell      = grid.view.getRow(rowIndex);
            clkCellY     = Ext.fly(clkCell).getY();
            gridEl       = grid.el;

            if (previewPanel !== null) {
                // preview panel can be reused for previewing another feed.
                // abort all pending operations
                previewPanel.el.stopFx();

                if (activeEmailId != null) {
                    // if the activeEmailId does not equal to zero, the
                    // previewPanel was hidden using the animation effect.
                    previewPanel.el.slideOut(animConfig, {
                                        duration : .4,
                                        useDisplay: false,
                                        callback : function(){
                                            onHide();
                                            decoratePreviewPanel();
                                            emailView.hide();
                                        },
                                        scope:this
                                   })
                                   .slideIn(animConfig, {callback : onShow, duration : .4, useDisplay: false});

                } else {
                    // the preview panel was hidden using the hide method
                    // reshow and slide in.
                    container.setDisplayed(true);
                    refreshAnimSettings();
                    decoratePreviewPanel();
                    previewPanel.el.slideIn(animConfig, {callback : onShow, duration : .4, useDisplay: false});
                }
            } else {
                refreshAnimSettings();
                previewPanel = createPreviewWindow();
                previewPanel.render(container);
                loadMask = new Ext.LoadMask(previewPanel.el.dom);
                previewPanel.show();
                decoratePreviewPanel();
                previewPanel.el.slideIn(animConfig, {callback : onShow, duration : .4, useDisplay: false});
                previewPanel.on('beforeclose', this.hide, this, [true, true]);
                previewPanel.on('move', onMove);
            }

            activeEmailId = pId;
        },

        isPreviewShownForRecord : function(record)
        {
            return record
                ? record.id === activeEmailId
                : false;
        },

        getCurrentlyShownRecordId : function()
        {
            return activeEmailId;
        },

        /**
         * Hides the preview panel.
         * Returns <tt>false</tt> to prevents bubbling the <tt>close</tt> event
         * to the Ext.Window based on the passed argument <tt>preventBubbling</tt>.
         *
         * @param {boolean} <tt>true</tt> to skip animation, <tt>false</tt>
         *                  to show.
         *
         * @todo update every call since second paramter is now deprecated!
         */
        hide : function(skipAnimation)
        {
            if (previewPanel == null || activeEmailId == null) {
                return;
            }
            if (!skipAnimation) {
                previewPanel.el.slideOut(animConfig, {
                    useDisplay : false,
                    duration   : .4,
                    callback   : function(){
                        emailView.hide();
                        onHide();
                        container.setDisplayed(false);
                    }
                });
            } else {
                container.setDisplayed(false);
                previewPanel.el.slideOut(animConfig, {callback : function(){emailView.hide();}, useDisplay : false, duration : .1});
                onHide(true);
            }

            lastRecord   = null;
            activeEmailId = null;

            return false;
        }

    };

}();
<commit_msg>[Email module - client] - fixed: fixed an issue where the email preview would not show the email message when it was reloaded with external resources (closes CN-822)<commit_after>/**
 * conjoon
 * (c) 2002-2012 siteartwork.de/conjoon.org
 * licensing@conjoon.org
 *
 * $Author$
 * $Id$
 * $Date$
 * $Revision$
 * $LastChangedDate$
 * $LastChangedBy$
 * $URL$
 */

Ext.namespace('com.conjoon.groupware.email');

/**
 * Controller for previewing Feed contents.
 * This is a singleton-object and used bycom.conjoon.groupware.feeds.FeedGrid
 * to enable previewing a feed in a panel sliding out left of the grid panel,
 * aligned to the current selected cell. The panel is closable and draggable.
 * Once a panel was created, it can not be closed such that the object gets
 * destroyed.
 *
 * The preview panel depends on record properties passed from the grid to the
 * showPreview-method. The needed properties are
 *
 *

 *
id - the id of the feed to preview

 *
title - the title of the feed

 *
link - the link of the feed  of the feed to preview

 *
pubDate - the publication date of the feed

 *

 *
 * @author Thorsten Suckow-Homberg <tsuckow@conjoon.org>
 */
com.conjoon.groupware.email.EmailPreview = function() {

// {{{ private members

    /**
     * @type {Ext.Element} gridEl The element of the grid the preview is attached to
     */
    var gridEl = null;

    /**
     * Initial width of the preview panel.
     * @param {Number}
     */
    var width = 330;

    /**
     * Initial height of the preview panel.
     * @param {Number}
     */
    var height = 250;

    /**
     * The y position of the last clicked cell.
     * @param {Number} clkCellY
     */
    var clkCellY = 0;

    /**
     * Stores the id of the last previewed feed. If a preview panel gets closed,
     * the property will be reset to <tt>null</tt>.
     */
    var activeEmailId = null;

    /**
     * The html container that is responsible for enabling animation effects
     * of the preview panel.
     */
    var container = null;

    /**
     * The panel that is used for previewing a feed content. The property will
     * hold an instance of <tt>Ext.Panel</tt> which is being reused for previewing
     * until the panel was detached from the grid.
     */
    var previewPanel = null;

    /**
     * Stores the active cell to which the preview panel is aligned.
     */
    var clkCell = null;

    /**
     * Stores the row index of the cell to which the preview panel is aligned.
     */
    var clkRowIndex = -1;

    /**
     * Stores the record information of the cell's row associated with previewing.
     * The record needs to have a id-property that holds a unique id of the
     * grid's record that was selected.
     */
    var clkRecord = null;

    var loadMask = null;

    var emailView = null;

    var lastRecord = null;

// }}}

// {{{ private methods

    /**
     * Returns the first left outermost columnIndex of the first column
     * that is not hidden in the grid.
     * This method is guaranteed to return a value in the range of [0, columnIndex].
     *
     * @param {Ext.grid.GridPanel} grid
     * @param {Numbe} columnIndex
     *
     * @return {Number}
     */
    var _getColumnIndex = function(grid, columnIndex)
    {
        var colModel = grid.getColumnModel();
        i = 0;
        while (i < columnIndex) {
            if (!colModel.isHidden(i)) {
                return i;
            }
            i++;
        }

        return i;
    };

    /**
     * Callback.
     * Called when the preview panel's show-animation is finished.
     */
    var onShow = function()
    {
        emailView.show();
        var viewHeight  = Ext.fly(document.body).getHeight();
        var panelHeight = previewPanel.el.getHeight();

        if (clkCellY + panelHeight > viewHeight) {
            container.shift({
                y : container.getY() - (((clkCellY + panelHeight) - viewHeight) + 4)
            });
        }
    };

    var onBeforeLoad = function()
    {
        loadMask.show();
        emailView.hide();
    };

    var onLoadFailure = function(response, options)
    {
        com.conjoon.groupware.ResponseInspector.handleFailure(response, {
            onLogin: {
                fn : function(){
                    decoratePreviewPanel();
                }
            }
        });
        previewPanel.close();
        loadMask.hide();
    };

    var onLoadSuccess = function()
    {
        lastRecord = emailView.emailRecord;

        loadMask.hide();

        /**
         * @ticket CN-822
         */
        if (!emailView.isVisible()) {
            emailView.show();
        }

        previewPanel.setTitle(lastRecord.get('subject'));
    };

    /**
     * Inits any component that is needed for displaying/animating
     * the preview panel.
     * This method will only be called once.
     */
    var initComponents = function()
    {
        container = Ext.DomHelper.append(document.body, {
            id    : 'DOM:com.conjoon.groupware.email.EmailPreview.container',
            style : "position:absolute;overflow:hidden;height:"+(height+5)+"px;width:"+width+"px"
        }, true);
    };

    /**
     * Callback.
     * Called when the preview panel's hide-animation is finished.
     */
    var onHide = function(skipAlign)
    {
        emailView.abortRequest();

        previewPanel.setTitle(com.conjoon.Gettext.gettext("Loading..."));

        if (skipAlign === true) {
            return;
        }

        refreshAnimSettings();
    };

    /**
     * Loads the feed's data into the preview panel.
     */
    var decoratePreviewPanel = function()
    {
        if (clkRecord == null) {
            return;
        }

        var subject = clkRecord.get('subject');
        var rec = com.conjoon.groupware.email.EmailViewBaton.getRecord(clkRecord.id);
        if (rec) {
            lastRecord = rec;
            emailView.emailRecord = rec;
            emailView.renderView();
        } else {
            emailView.setEmailItem(clkRecord)
        }

        previewPanel.setTitle(subject);
    }

    /**
     * Callback.
     * Called after the panel was detached from the grid and dropped anywhere
     * on the document body.
     * Sets <tt>previewPanel</tt> to <tt>null</tt> to notify the <tt>show</tt> method
     * to create a new preview panel.
     *
     */
    var onMove = function()
    {
        if (lastRecord == null) {
            previewPanel.close();
            return;
        }
        var emailItem = lastRecord.copy();
        previewPanel.close();
        var view = com.conjoon.groupware.email.EmailViewBaton.showEmail(emailItem, {
            autoLoad : false
        }, true);

    };

    /**
     * Creates a window for displaying email contents.
     *
     * @return {Ext.Window} The window used for previewing.
     */
    var createPreviewWindow = function()
    {
        var templateConfig = {
            header : new Ext.Template(
                '
',
                   '
',
                    '{date:date("d.m.Y H:i")}',
                    '{subject}',
                    '
',
                    '{from}',
                    '{replyTo}',
                    '{to}',
                    '{cc}',
                    '{bcc}',
                    '
',
                   '
',
                '
'
        )};

        emailView = new com.conjoon.groupware.email.EmailViewPanel({
            autoLoad     : false,
            refreshFrame : true,
            border       :  false,
            hideMode     : 'visibility',
            viewConfig   : {
                templates        : templateConfig,
                fromValue        : com.conjoon.Gettext.gettext("From"),
                toValue          : com.conjoon.Gettext.gettext("To"),
                ccValue          : com.conjoon.Gettext.gettext("CC"),
                bccValue         : com.conjoon.Gettext.gettext("BCC")
            }
        });

        var win =  new Ext.Window({
            bodyStyle  : 'background:white;',
            autoScroll : false,
            layout     : 'fit',
            title      : ("Loading..."),
            iconCls    : 'com-conjoon-groupware-email-EmailPreview-Icon',
            resizable  : false,
            shadow     : false,
            hideMode   : 'visibility',
            items      : [emailView],
            height     : height,
            width      : width
        });

        win.mon(emailView, 'emailload',        onLoadSuccess, com.conjoon.groupware.email.EmailPreview);
        win.mon(emailView, 'beforeemailload',  onBeforeLoad, com.conjoon.groupware.email.EmailPreview);
        win.mon(emailView, 'emailloadfailure', onLoadFailure, com.conjoon.groupware.email.EmailPreview);

        win.on('render', function() {
            this.mon(this.header, 'dblclick', function(){
               onMove();
            }, this);
        }, win, {single : true});

        win.initDraggable = function() {
            Ext.Window.prototype.initDraggable.call(this);

            this.dd.b4Drag = function(e) {
                container.dom.style.overflow = "visible";
            };

            this.dd.endDrag = function(e){
                this.win.unghost(true, false);
                this.win.setPosition(0, 0);
                this.win.saveState();
                container.dom.style.overflow = "hidden";
            };
        }

        return win;
    };

    var animConfig = 'r';

    var refreshAnimSettings = function()
    {
        var x = gridEl.getX();

        // this should work in most cases - determine if the panel is rendered
        // in the left side of the workbench
        if (x <= 50) {
            x += gridEl.getSize().width;
            animConfig = 'l';
        } else {
            x -= container.getSize().width;
            animConfig = 'r';
        }

        container.setY(clkCellY);
        container.setX(x);
    };

// }}}

    return {

        getLastRecord : function()
        {
            return lastRecord;
        },

        getActiveRecord : function()
        {
            return clkRecord;
        },

        /**
         * Shows the preview panel using a slide-in animation effect.
         * The preview will not been shown if ctrl or shift was pressed while
         * calling this method.
         *
         * @param {Ext.grid.GridPanel} The grid panel that calls this method.
         * @param {Number} The row index of the cell the panel is aligned to.
         * @param {Number} The column index of the cell the panel is aligned to.
         * @param {Ext.EventObject} The raw event object that triggered this method.
         */
        show : function(grid, record)
        {
            if (!record) {
                return;
            }
            clkRecord = record.copy();

            var store    = grid.getStore(),
                /**
                 * @ticket CN-821
                 */
                rowIndex = store.indexOf(record) + store.bufferRange[0];

            var pId = clkRecord.id;
            if (activeEmailId == pId) {
                // previewing is already active for this record.
                return;
            }

            // lazy create needed components
            if (container == null) {
                initComponents.call(this);
            }

            clkRowIndex  = rowIndex;
            clkCell      = grid.view.getRow(rowIndex);
            clkCellY     = Ext.fly(clkCell).getY();
            gridEl       = grid.el;

            if (previewPanel !== null) {
                // preview panel can be reused for previewing another feed.
                // abort all pending operations
                previewPanel.el.stopFx();

                if (activeEmailId != null) {
                    // if the activeEmailId does not equal to zero, the
                    // previewPanel was hidden using the animation effect.
                    previewPanel.el.slideOut(animConfig, {
                                        duration : .4,
                                        useDisplay: false,
                                        callback : function(){
                                            onHide();
                                            decoratePreviewPanel();
                                            emailView.hide();
                                        },
                                        scope:this
                                   })
                                   .slideIn(animConfig, {callback : onShow, duration : .4, useDisplay: false});

                } else {
                    // the preview panel was hidden using the hide method
                    // reshow and slide in.
                    container.setDisplayed(true);
                    refreshAnimSettings();
                    decoratePreviewPanel();
                    previewPanel.el.slideIn(animConfig, {callback : onShow, duration : .4, useDisplay: false});
                }
            } else {
                refreshAnimSettings();
                previewPanel = createPreviewWindow();
                previewPanel.render(container);
                loadMask = new Ext.LoadMask(previewPanel.el.dom);
                previewPanel.show();
                decoratePreviewPanel();
                previewPanel.el.slideIn(animConfig, {callback : onShow, duration : .4, useDisplay: false});
                previewPanel.on('beforeclose', this.hide, this, [true, true]);
                previewPanel.on('move', onMove);
            }

            activeEmailId = pId;
        },

        isPreviewShownForRecord : function(record)
        {
            return record
                ? record.id === activeEmailId
                : false;
        },

        getCurrentlyShownRecordId : function()
        {
            return activeEmailId;
        },

        /**
         * Hides the preview panel.
         * Returns <tt>false</tt> to prevents bubbling the <tt>close</tt> event
         * to the Ext.Window based on the passed argument <tt>preventBubbling</tt>.
         *
         * @param {boolean} <tt>true</tt> to skip animation, <tt>false</tt>
         *                  to show.
         *
         * @todo update every call since second paramter is now deprecated!
         */
        hide : function(skipAnimation)
        {
            if (previewPanel == null || activeEmailId == null) {
                return;
            }
            if (!skipAnimation) {
                previewPanel.el.slideOut(animConfig, {
                    useDisplay : false,
                    duration   : .4,
                    callback   : function(){
                        emailView.hide();
                        onHide();
                        container.setDisplayed(false);
                    }
                });
            } else {
                container.setDisplayed(false);
                previewPanel.el.slideOut(animConfig, {callback : function(){emailView.hide();}, useDisplay : false, duration : .1});
                onHide(true);
            }

            lastRecord   = null;
            activeEmailId = null;

            return false;
        }

    };

}();
<|endoftext|>


<commit_before>var Metric = require('./metric')
	, MetricCache = require('./metric_cache')
	, Writer = require('./writer')
	, Reader = require('./reader')
	, Q = require('q');

function App(){
	var me = this;
	var metric_cache_ = new MetricCache();
	var writer_ = new Writer();

	//////////////////////////////////////////////////////////
	// metric commands
	this.createMetric = Metric.create;
	this.getMetric = Metric.get;
	this.setMetric = Metric.set;
	this.dropMetric = Metric.drop;
	this.findMetric = Metric.find;

	///////////////////////////////////////////////////////////
	// write commands
	/*
		append data to one topic
	*/
	this.append = function (topic_name, metric_name, data, cb){
		metric_cache_.get(metric_name, function (err, metric){
			if (err)
				cb && cb(err);
			else{
				writer_.append(topic_name, data, metric);
				cb && cb(null);
			}
		})
	}

	/*
		append batch
		@batch - array
		[
			{
				"topic" : "{topic_name}",
				"metric" : "{metric_name}",
				"data" : {object}
			},
			...
		]
	*/
	this.appendBatch = function (batch, cb){
		if (!Array.isArray(batch)){
			return cb && cb("ER_BAD_BATCH_BODY");
		}

		var append_ = function (topic_name, metric_name, data){
			return Q.Promise(function (resolve, reject){
				me.append(topic_name, metric_name, data, function (err){
					if (err)
						reject(err);
					else
						resolve();
				})
			})
		}

		var callbacks = [];
		batch.forEach(function (it){
			callbacks.push(append_(it.topic, it.metric, it.data))
		});

		Q.allSettled(callbacks).then(function (results){
			var ret = new Array(results.length);
			var last_error = null;

			results.forEach(function (it, i){
				if (it.state == "fulfilled"){
					ret[i] = null;
				}
				else{
					ret[i] = last_error = it.reason;
				}
			});

			if (last_error)
				cb && cb("ER_PARTIAL_FAIL", ret);
			else
				cb && cb(null, null);
		});
	}

	/////////////////////////////////////////////////////////////////////
	// read commands

	/*
		@topic_name - string
		@query - object
		{
			fields : array of string,
			start : timestamp,
			end : timestamp,
			limit : number
		}
	*/
	this.readRaw = function (topic_name, query, cb){
		var reader = new Reader(topic_name, query.fields);
		var options = query.limit ? {"limit":parseInt(query.limit)} : null;

		if (query.end == undefined)
			reader.readRaw(parseInt(query.start), options, cb);
		else
			reader.readRaw(parseInt(query.start), parseInt(query.end), options, cb);
	}
}

module.exports = App;<commit_msg>	modified:   lib/app.js<commit_after>var Metric = require('./metric')
	, MetricCache = require('./metric_cache')
	, Writer = require('./writer')
	, Reader = require('./reader')
	, Q = require('q');

function App(){
	var me = this;
	var metric_cache_ = new MetricCache();
	var writer_ = new Writer();

	//////////////////////////////////////////////////////////
	// metric commands
	this.createMetric = Metric.create;
	this.getMetric = Metric.get;
	this.setMetric = Metric.set;
	this.dropMetric = Metric.drop;
	this.findMetric = Metric.find;

	///////////////////////////////////////////////////////////
	// write commands
	/*
		append data to one topic
	*/
	this.append = function (topic_name, metric_name, data, cb){
		metric_cache_.get(metric_name, function (err, metric){
			if (err)
				cb && cb(err);
			else{
				writer_.append(topic_name, data, metric);
				cb && cb(null);
			}
		})
	}

	/*
		append batch
		@batch - array
		[
			{
				"topic" : "{topic_name}",
				"metric" : "{metric_name}",
				"data" : {object}
			},
			...
		]
	*/
	this.appendBatch = function (batch, cb){
		if (!Array.isArray(batch)){
			return cb && cb("ER_BAD_BATCH_BODY");
		}

		var append_ = function (topic_name, metric_name, data){
			return Q.Promise(function (resolve, reject){
				me.append(topic_name, metric_name, data, function (err){
					if (err)
						reject(err);
					else
						resolve();
				})
			})
		}

		var callbacks = [];
		batch.forEach(function (it){
			callbacks.push(append_(it.topic, it.metric, it.data))
		});

		Q.allSettled(callbacks).then(function (results){
			var ret = new Array(results.length);
			var last_error = null;

			results.forEach(function (it, i){
				if (it.state == "fulfilled"){
					ret[i] = null;
				}
				else{
					ret[i] = last_error = it.reason;
				}
			});

			if (last_error)
				cb && cb("ER_PARTIAL_FAIL", ret);
			else
				cb && cb(null, null);
		});
	}

	/////////////////////////////////////////////////////////////////////
	// read commands

	/*
		@topic_name - string
		@query - object
		{
			fields : array of string,
			start : timestamp,
			end : timestamp,
			limit : number
		}
	*/
	this.readRaw = function (topic_name, query, cb){
		var reader = new Reader(topic_name, query.fields);
		var options = query.limit ? {"limit":parseInt(query.limit)} : null;
		var start_ = parseInt(query.start);
		if (isNaN(start_)){
			return cb && cb("ER_INVALID_START_TIME");
		}

		if (query.end == undefined){
			reader.readRaw(start_, options, cb);
		}
		else {
			var end_ = parseInt(query.end);
			if (isNaN(end_))
				return cb && cb("ER_INVALID_END_TIME");

			reader.readRaw(start_, end_, options, cb);
		}
	}
}

module.exports = App;<|endoftext|>


<commit_before>var express  = require('express'),
    hogan    = require('hogan.js'),
    path     = require('path'),
    fs       = require('fs'),
    app      = express(),
    options  = require('./config'),
    store    = require('./store')(options.store),
    handlers = require('./handlers')(app),
    gobo     = require('../vendor/gobo');

app.store = store;
app.templates = {};

// Apply the keys from the config file.
Object.getOwnPropertyNames(options).forEach(function (key) {
  app.set(key, options[key]);
});

app.set('root', path.resolve(path.join(__dirname, '..')));
app.set('version', require('../package').version);

// Register all the middleware.
app.use(express.logger());
app.use(express.static(path.join(app.set('root'), 'public')));
app.use(express.errorHandler({dumpExceptions: true}));
app.use(express.errorHandler({showStack: true, dumpExceptions: true}));

// Create a Hogan/Mustache handler for templates.
app.engine('html', function (path, options, fn) {
  fs.readFile(path, 'utf8', function (err, template) {
    if (err) {
      return fn(err);
    }

    try {
      var compiled = app.templates[path];
      if (!compiled) {
        compiled = app.templates[path] = hogan.compile(template);
      }

      fn(null, compiled.render(options));
    } catch (error) {
      fn(error);
    }
  });
});

// Configure the template engine.
app.set('view engine', 'html');
app.set('views', path.join(app.set('root'), 'views'));

// Define some generic template variables.
app.locals({
  root: (options.url.ssl ? 'https://' : 'http://') + options.url.host + options.url.prefix,
  version: app.set('version'),
  home: null
});

// Load the bin from the store when encountered in the url. Also handles the
// "latest" url action.
app.param('bin', handlers.loadBin);

// Set up the routes.
app.get('/', handlers.getDefault);

// Latest
app.get('/:bin/latest.:format?', handlers.redirectToLatest);
app.get('/:bin/latest/edit', handlers.redirectToLatest);

// Edit
app.get('/:bin/edit', handlers.getBin);
app.get('/:bin/:rev/edit', handlers.getBin);

// Source
app.get('/:bin.:format(js|css|html)', handlers.getBinSource);
app.get('/:bin/:rev.:format(js|css|html)', handlers.getBinSource);
app.get('/:bin/:format(js)', handlers.getBinSource);
app.get('/:bin/:rev/:format(js)', handlers.getBinSource);

// Preview
app.get('/:bin/:rev?', handlers.getBinPreview);

// Serve the concatenated JavaScript.
app.get('/js/debug/jsbin.js', function (req, res) {
  var js = path.join(app.set('root'), 'public', 'js');
  gobo(path.join(js, 'jsbin.js'), 'vendor', function (content) {
    res.contentType('js');
    res.send(content);
  });
});

// Error handler.
app.use(function (err, req, res, next) {
  if (err instanceof handlers.NotFound) {
    return handlers.notFound(req, res);
  }
  next(err);
});

// Export the application to allow it to be included.
module.exports = app;

// Run a local development server if this file is called directly.
if (require.main === module) {
  app.store.connect(function (err) {
    if (err) {
      throw err;
    }
    app.listen(3000);
  });
}
<commit_msg>Tidy up the route files<commit_after>var express  = require('express'),
    hogan    = require('hogan.js'),
    path     = require('path'),
    fs       = require('fs'),
    app      = express(),
    options  = require('./config'),
    store    = require('./store')(options.store),
    handlers = require('./handlers')(app),
    gobo     = require('../vendor/gobo');

app.store = store;
app.templates = {};

// Apply the keys from the config file.
Object.getOwnPropertyNames(options).forEach(function (key) {
  app.set(key, options[key]);
});

app.set('root', path.resolve(path.join(__dirname, '..')));
app.set('version', require('../package').version);

// Register all the middleware.
app.use(express.logger());
app.use(express.static(path.join(app.set('root'), 'public')));
app.use(express.errorHandler({dumpExceptions: true}));
app.use(express.errorHandler({showStack: true, dumpExceptions: true}));

// Create a Hogan/Mustache handler for templates.
app.engine('html', function (path, options, fn) {
  fs.readFile(path, 'utf8', function (err, template) {
    if (err) {
      return fn(err);
    }

    try {
      var compiled = app.templates[path];
      if (!compiled) {
        compiled = app.templates[path] = hogan.compile(template);
      }

      fn(null, compiled.render(options));
    } catch (error) {
      fn(error);
    }
  });
});

// Configure the template engine.
app.set('view engine', 'html');
app.set('views', path.join(app.set('root'), 'views'));

// Define some generic template variables.
app.locals({
  root: (options.url.ssl ? 'https://' : 'http://') + options.url.host + options.url.prefix,
  version: app.set('version'),
  home: null
});

// Load the bin from the store when encountered in the url. Also handles the
// "latest" url action.
app.param('bin', handlers.loadBin);

// Set up the routes.
app.get('/', handlers.getDefault);

// Latest
app.get('/:bin/latest(.|/):format?', handlers.redirectToLatest);
app.get('/:bin/latest/edit', handlers.redirectToLatest);

// Edit
app.get('/:bin/:rev?/edit', handlers.getBin);

// Source
app.get('/:bin/:rev?.:format(js|css|html)', handlers.getBinSource);
app.get('/:bin/:rev?/:format(js)', function (req, res) {
  // Redirect legacy /js suffix to the new .js extension.
  res.redirect(301, req.url.replace(/\/js$/, '.js'));
});

// Preview
app.get('/:bin/:rev?', handlers.getBinPreview);

// Serve the concatenated JavaScript.
app.get('/js/debug/jsbin.js', function (req, res) {
  var js = path.join(app.set('root'), 'public', 'js');
  gobo(path.join(js, 'jsbin.js'), 'vendor', function (content) {
    res.contentType('js');
    res.send(content);
  });
});

// Error handler.
app.use(function (err, req, res, next) {
  if (err instanceof handlers.NotFound) {
    return handlers.notFound(req, res);
  }
  next(err);
});

// Export the application to allow it to be included.
module.exports = app;

// Run a local development server if this file is called directly.
if (require.main === module) {
  app.store.connect(function (err) {
    if (err) {
      throw err;
    }
    app.listen(3000);
  });
}
<|endoftext|>


<commit_before>requirejs.config({
	urlArgs: 'v=111',
	paths: {
		'theme': 'livedesk-embed/themes/cnm'
	}
});
require(['cnm.min'], function() {
	require(['../scripts/js/config'], function(){
		var name;
		for(name in livedesk.theme) {
			define('tmpl!theme/'+name, ['dust/compiler'], function(dust){
				dust.loadSource(dust.compile(livedesk.theme[name],'theme/'+name));
			});
		}
		function loadCss(url) {
			var link = document.createElement("link");
			link.type = "text/css";
			link.rel = "stylesheet";
			link.href = url;
			document.getElementsByTagName("head")[0].appendChild(link);
		}
		loadCss(require.toUrl('theme/livedesk.css'));//'css!theme/livedesk',
		require(['livedesk-embed/main']);
	});
	(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

	ga('create', 'UA-45928067-1', 'auto');
	ga('send', 'pageview');
});
<commit_msg>Update cnm.js<commit_after>requirejs.config({
	urlArgs: 'v=112',
	paths: {
		'theme': 'livedesk-embed/themes/cnm'
	}
});
require(['cnm.min'], function() {
	require(['../scripts/js/config'], function(){
		var name;
		for(name in livedesk.theme) {
			define('tmpl!theme/'+name, ['dust/compiler'], function(dust){
				dust.loadSource(dust.compile(livedesk.theme[name],'theme/'+name));
			});
		}
		function loadCss(url) {
			var link = document.createElement("link");
			link.type = "text/css";
			link.rel = "stylesheet";
			link.href = url;
			document.getElementsByTagName("head")[0].appendChild(link);
		}
		loadCss(require.toUrl('theme/livedesk.css'));//'css!theme/livedesk',
		require(['livedesk-embed/main']);
	});
	(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
	(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
	m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
	})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

	ga('create', 'UA-45931917-1', 'auto');
	ga('send', 'pageview');
});
<|endoftext|>