<commit_before>/**
 * Module dependencies.
 */

var RPC = require('../rpc')
var path = require('path')
var Asset = require('./asset')
var debug = require('debug')('micromono:service')
var Router = require('./router')
var assign = require('lodash.assign')
var extend = require('ampersand-class-extend')
var EventEmitter = require('eventemitter3')
var Announcement = require('./announcement')

/**
 * MicroMono Service class constructor.
 */
var Service = module.exports = function MicroMonoService() {
  if (!this.packagePath) {
    throw new Error('Please provide `packagePath` property when you extend Service class')
  }

  this.packageInfo = require(path.join(this.packagePath, 'package.json'))
  this.setDefaults(this.packageInfo)
  var ann = new Announcement(this)

  // setup asset
  if (this.packageInfo.jspm) {
    // found jspm info, initialize Asset
    this.asset = new Asset(this.packagePath)
    ann.asset = this.asset.parseJSPM()
    // make sure we have the same name
    ann.asset.name = this.name
    this.asset.pkgInfo.name = this.name
  }

  // setup web server
  if (this.route || this.asset || this.middleware) {
    this.framework = this.framework || 'express'
    this.router = new Router(this)
    this.app = this.router.framework.getApp()
  }

  // setup rpc
  if (this.api) {
    this.rpcType = this.rpcType || 'axon'
    this.rpc = new RPC({
      api: this.api,
      type: this.rpcType,
      context: this,
      isRemote: this.isRemote()
    })

    ann.rpc = this.rpc.getAPIs()
    ann.rpcType = this.rpc.type
  }

  if (!this.init) {
    this.init = function() {
      return Promise.resolve()
    }
  }

  this.announcement = ann
}

// Provide the ability to extend the Service class.
Service.extend = extend

// Service is an event emitter
assign(Service.prototype, EventEmitter.prototype)

/**
 * Set default options of the service
 *
 * @param {Object} info Object contains service information.
 */
Service.prototype.setDefaults = function(info) {
  this.name = this.name || info.name
  this.baseUrl = this.baseUrl || '/'
  this.version = info.version
}

/**
 * Get the type of the service instance, remote or not.
 *
 * @return {Boolean} True if this is a farcaster (a fake service rebuilt from
 * announcement of remote service), otherwise false.
 */
Service.prototype.isRemote = function() {
  return false
}

/**
 * Set the instance of native node http.Server instance
 *
 * @param {http.Server} server
 * @emit 'server' {http.Server}
 */
Service.prototype.setHttpServer = function(server) {
  this.server = server
  this.emit('server', server)
}

/**
 * Set or get upgrade url.
 *
 * @param  {String|undefined} upgradeUrl Set the upgrade url when this is string
 * or return the current value if this is undefined.
 * @return {String}           Value of current upgrade url.
 */
Service.prototype.allowUpgrade = function(upgradeUrl) {
  if ('undefined' === typeof upgradeUrl) {
    return this.announcement.upgradeUrl
  } else if (upgradeUrl) {
    upgradeUrl = path.join(this.baseUrl, upgradeUrl)
  }
  return (this.announcement.upgradeUrl = upgradeUrl)
}

/**
 * Start a web server which serves requests for route, asset and middleware
 * provided by this service.
 *
 * @param  {Number|String}  port Port to bind the server.
 * @param  {String}         host Host or ip address to bind the port to.
 * @return {Promise}        A promise instance rejects with error or resolve with
 * instance of http.Server when server started successfully.
 */
Service.prototype.startWebServer = function(port, host) {
  if (!this.router) {
    // no need to start http server if we don't have asset or route to serve.
    return Promise.resolve()
  }

  var self = this
  host = host || '0.0.0.0'
  this.announcement.webPort = port

  debug('start http server at %s:%s', host, port)

  return this.router.startServer(port, host).then(function(server) {
    if (server) {
      self.setHttpServer(server)
    }
  })
}

Service.prototype.startRPCServer = function(port, host) {
  host = host || '0.0.0.0'
  debug('start rpc server type %s at %s:%s', this.rpc.type, host, port)
  return this.rpc.startServer(port, host)
}

Service.prototype.run = function(options) {
  var self = this

  var promise = this.startWebServer(options.port, options.host)
    .then(function() {
      return self.init()
    })
    .then(function() {
      if (self.router) {
        // build and attach route handlers
        self.router.buildRoutes()
        self.announcement.route = self.router.getRoutes()
        self.announcement.middleware = self.router.getMiddlewares()
      }
    })
    .then(function() {
      if (self.rpc) {
        return self.startRPCServer(options.rpcPort, options.rpcHost)
      }
    })
    .then(function() {
      debug('Service "%s" started with following service info: ', self.announcement.name)
      debug(self.announcement)
    })

  return promise
}
<commit_msg>Reduce the size of the constructor.<commit_after>/**
 * Module dependencies.
 */

var RPC = require('../rpc')
var path = require('path')
var Asset = require('./asset')
var debug = require('debug')('micromono:service')
var Router = require('./router')
var assign = require('lodash.assign')
var extend = require('ampersand-class-extend')
var EventEmitter = require('eventemitter3')
var Announcement = require('./announcement')

/**
 * MicroMono Service class constructor.
 */
var Service = module.exports = function MicroMonoService() {
  if (!this.packagePath) {
    throw new Error('Please provide `packagePath` property when you extend Service class')
  }

  this.packageInfo = require(path.join(this.packagePath, 'package.json'))
  this.setDefaults(this.packageInfo)
  this.announcement = new Announcement(this)

  this.setupAsset()
  this.setupWeb()
  this.setupRPC()

  if (!this.init) {
    this.init = function() {
      return Promise.resolve()
    }
  }
}

// Provide the ability to extend the Service class.
Service.extend = extend

// Service is an event emitter
assign(Service.prototype, EventEmitter.prototype)

/**
 * Set default options of the service
 *
 * @param {Object} info Object contains service information.
 */
Service.prototype.setDefaults = function(info) {
  this.name = this.name || info.name
  this.baseUrl = this.baseUrl || '/'
  this.version = info.version
}

Service.prototype.setupAsset = function() {
  if (this.packageInfo.jspm) {
    // found jspm info, initialize Asset
    this.asset = new Asset(this.packagePath)
      // make sure we have a consistent service name
    this.asset.pkgInfo.name = this.name
  }
}

Service.prototype.setupWeb = function() {
  if (this.route || this.asset || this.middleware) {
    this.framework = this.framework || 'express'
    this.router = new Router(this)
    this.app = this.router.framework.getApp()
  }
}

Service.prototype.setupRPC = function() {
  if (this.api) {
    this.rpcType = this.rpcType || 'axon'
    var rpcOptions = {
      api: this.api,
      type: this.rpcType,
      context: this,
      isRemote: false
    }
    this.rpc = new RPC(rpcOptions)
  }
}

/**
 * Get the type of the service instance, remote or not.
 *
 * @return {Boolean} True if this is a farcaster (a fake service rebuilt from
 * announcement of remote service), otherwise false.
 */
Service.prototype.isRemote = function() {
  return false
}

/**
 * Set the instance of native node http.Server instance
 *
 * @param {http.Server} server
 * @emit 'server' {http.Server}
 */
Service.prototype.setHttpServer = function(server) {
  this.server = server
  this.emit('server', server)
}

/**
 * Set or get upgrade url.
 *
 * @param  {String|undefined} upgradeUrl Set the upgrade url when this is string
 * or return the current value if this is undefined.
 * @return {String}           Value of current upgrade url.
 */
Service.prototype.allowUpgrade = function(upgradeUrl) {
  if ('undefined' === typeof upgradeUrl) {
    return this.announcement.upgradeUrl
  } else if (upgradeUrl) {
    upgradeUrl = path.join(this.baseUrl, upgradeUrl)
  }
  return (this.announcement.upgradeUrl = upgradeUrl)
}

/**
 * Start a web server which serves requests for route, asset and middleware
 * provided by this service.
 *
 * @param  {Number|String}  port Port to bind the server.
 * @param  {String}         host Host or ip address to bind the port to.
 * @return {Promise}        A promise instance rejects with error or resolve with
 * instance of http.Server when server started successfully.
 */
Service.prototype.startWebServer = function(port, host) {
  if (!this.router) {
    // no need to start http server if we don't have asset or route to serve.
    return Promise.resolve()
  }

  var self = this
  host = host || '0.0.0.0'
  this.announcement.webPort = port

  debug('start http server at %s:%s', host, port)

  return this.router.startServer(port, host).then(function(server) {
    if (server) {
      self.setHttpServer(server)
    }
  })
}

Service.prototype.startRPCServer = function(port, host) {
  host = host || '0.0.0.0'
  debug('start rpc server type %s at %s:%s', this.rpc.type, host, port)
  return this.rpc.startServer(port, host)
}

Service.prototype.run = function(options) {
  var self = this
  var ann = this.announcement

  var promise = this.startWebServer(options.port, options.host)
    .then(function() {
      return self.init()
    })
    .then(function() {
      if (self.router) {
        if (self.asset) {
          ann.asset = self.asset.parseJSPM()
            // make sure we have a consistent package name
          ann.asset.name = self.name
        }

        // build and attach route handlers
        self.router.buildRoutes()
        ann.route = self.router.getRoutes()
        ann.middleware = self.router.getMiddlewares()
      }
    })
    .then(function() {
      if (self.rpc) {
        ann.rpc = this.rpc.getAPIs()
        ann.rpcType = this.rpcType
        ann.rpcPort = options.rpcPort
        return self.startRPCServer(options.rpcPort, options.rpcHost)
      }
    })
    .then(function() {
      debug('Service "%s" started with following service info: ', self.announcement.name)
      debug(self.announcement)
    })

  return promise
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import {
  StatusBar,
  View,
  StyleSheet,
  LayoutAnimation,
  Platform,
  TextInput,
  ActivityIndicator,
} from 'react-native';
import {
  NavigationStyles,
} from '@exponent/ex-navigation';
import colors from '../config/colors';
import KeyboardEventListener from 'KeyboardEventListener';
import Swiper from 'react-native-swiper';
import Icon from '../components/CrossPlatformIcon';
import GetEventName from '../components/GetEventName';
import GetEventType from '../components/GetEventType';
import GetEventDate from '../components/GetEventDate';
import GetEventTime from '../components/GetEventTime';
import GetEventUrl from '../components/GetEventUrl';
import GetEventDescription from '../components/GetEventDescription';
import GetEventLocation from '../components/GetEventLocation';
import CancelButton from '../components/NavBarCancelButton';
import moment from 'moment';
import filter from '../utils/filter';
import connectDropdownAlert from '../utils/connectDropdownAlert';
import { isExponentPushToken, sendPushNotificationAsync } from '../utils/ExponentPushClient';
import _ from 'lodash';
/**
 *  Allows user to create new events for school
 */
@connectDropdownAlert
export default class NewEventScreen extends Component {
  static route = {
    navigationBar: {
      visible: true,
      title: 'NEW EVENT',
      tintColor: colors.black,
      renderLeft: () => null,
      renderRight: () => <CancelButton />,
      borderBottomColor: 'transparent',
      titleStyle: {
        fontFamily: 'open-sans-bold',
      },
      backgroundColor: 'white',
    },
    styles: {
      ...NavigationStyles.SlideHorizontal,
    },
  }

  static propTypes = {
    navigator: PropTypes.object.isRequired,
    refresh: PropTypes.func,
    alertWithType: PropTypes.func.isRequired,
  }

  state = {
    name: null,
    date: moment.utc().toDate(),
    time: moment.utc().toDate().getTime(),
    url: '',
    submitting: false,
    type: null,
    description: null,
    location: null,
    keyboardHeight: 0,
  }

  componentWillMount() {
    this._unsubscribe = KeyboardEventListener.subscribe(this._onKeyboardVisibilityChange);
  }

  componentWillUnmount() {
    if (this._unsubscribe) {
      this._unsubscribe();
      this._unsubscribe = null;
    }
  }

  createEvent = () => {
    const name = this.state.name !== null && this.state.name.name;
    const type = this.state.type !== null && this.state.type.type;
    const date = this.state.date.date ?
      moment.utc(moment(this.state.date.date).startOf('day')).toJSON() :
      moment.utc(moment(this.state.date).startOf('day')).toJSON();
    const time = {
      hours: this.state.time.time ? moment(this.state.time.time).hours() : moment(this.state.time).hours(),
      minutes: this.state.time.time ? moment(this.state.time.time).minutes() : moment(this.state.time).minutes(),
    };
    const url = this.state.url.url || this.state.url;
    const location = {
      address: this.state.location.details.formatted_address,
      geometry: this.state.location.details.geometry,
    };
    const description = this.state.description !== null && this.state.description.description;
    return {
      name: filter.clean(name.trim()),
      type,
      createdBy: global.firebaseApp.auth().currentUser.uid,
      date,
      time,
      url: url.toLowerCase(),
      createdInDev: __DEV__, // eslint-disable-line jsx-control-statements/jsx-jcs-no-undef
      location,
      description: description && filter.clean(description.trim()),
    };
  }

  checkDataAndPush = () => {
    let propertiesAreValid = true;

    const name = this.state.name !== null && this.state.name.name;
    const date = this.state.date.date ?
      moment.utc(moment(this.state.date.date).startOf('day')) :
      moment.utc(moment(this.state.date).startOf('day'));
    const time = {
      hours: this.state.time.time ? moment(this.state.time.time).hours() : moment(this.state.time).hours(),
      minutes: this.state.time.time ? moment(this.state.time.time).minutes() : moment(this.state.time).minutes(),
    };

    if (name !== filter.clean(name)) {
      this.props.alertWithType('error', 'Error', 'Please mind your choice of words.');
      propertiesAreValid = false;
    }
    if (!date.add(time.hours, 'hours').add(time.minutes, 'minutes').isAfter(moment().add(3, 'hours'))) {
      this.props.alertWithType('error', 'Error', 'Event should be scheduled at least three hours in advance.');
      propertiesAreValid = false;
    }
    ['name', 'date', 'time', 'url', 'type', 'description'].forEach(elem => {
      if (!this[elem].isValid()) {
        this.props.alertWithType('error', 'Error', `Event ${elem} is invalid.`);
        propertiesAreValid = false;
      }
    });
    if (propertiesAreValid) {
      this.submitEvent(this.createEvent());
    }
  }

  _blurFocusedTextInput = () => {
    TextInput.State.blurTextInput(TextInput.State.currentlyFocusedField());
  };

  _isKeyboardOpen = () => {
    return this.state.keyboardHeight > 0;
  }

  _onKeyboardVisibilityChange = (
    { keyboardHeight, layoutAnimationConfig }:
    { keyboardHeight: number, layoutAnimationConfig: ?Object }) => {
    if (keyboardHeight === 0) {
      this._blurFocusedTextInput();
    }

    if (layoutAnimationConfig) {
      LayoutAnimation.configureNext(layoutAnimationConfig);
    }

    this.setState(() => {
      return { keyboardHeight };
    });
  }

  submitEvent = (event) => {
    if (this.state.submitting) {
      return;
    }
    this.setState(() => {
      return { submitting: true };
    });
    global.firebaseApp.database().ref('users')
    .child(global.firebaseApp.auth().currentUser.uid)
    .once('value')
    .then(snap => {
      const schoolUID = snap.val().school;
      global.firebaseApp.database().ref('schools')
      .child(schoolUID)
      .child('events')
      .push(event)
      .then(() => {
        // send pushes to peers
        global.firebaseApp.database().ref('users')
        .once('value')
        .then(usersSnap => {
          _.each(usersSnap.val(), user => {
            if (isExponentPushToken(user.pushToken) && user.school === schoolUID) {
              sendPushNotificationAsync({
                exponentPushToken: user.pushToken,
                message: `There's a new ${event.type.toLowerCase()} event at your school!`,
              }).then(() => {

              }).catch((err) => {
                this.props.alertWithType('error', 'Error', err.toString());
              });
            }
          });

          this.props.alertWithType('success', 'Success', 'Your event was submitted successfully!');
          this.props.refresh();
          this.props.navigator.pop();
        });
      });
    })
    .catch(err => {
      this.setState(() => {
        return { submitting: false };
      });
      this.props.alertWithType('error', 'Error', err.toString());
    });
  }

  render() {
    return (
      <View
        style={ [styles.container, this.state.keyboardHeight ?
          { flex: 1, marginBottom: this.state.keyboardHeight } :
          { flex: 1 },
        ] }
        onLayout={ (e) => {
          const { width, height } = e.nativeEvent.layout;
          this.setState(() => {
            return {
              swiperHeight: height,
              swiperWidth: width,
            };
          });
        } }
      >
        <StatusBar barStyle="dark-content" />
        <Choose>
          <When condition={ this.state.submitting }>
            <ActivityIndicator size="large" />
          </When>
          <Otherwise>
            <Swiper
              ref={ r => { this.swiper = r; } }
              showsPagination
              onScroll={ this._blurFocusedTextInput }
              scrollEventThrottle={ 32 }
              keyboardShouldPersistTaps="always"
              keyboardDismissMode={ Platform.OS === 'ios' ? 'none' : 'on-drag' }
              height={ this.state.swiperHeight }
              contentContainerStyle={ styles.swiperWrapper }
              showsButtons
              loop={ false }
              prevButton={
                <Icon
                  onPress={ () => { this.swiper.scrollBy(-1, false); } }
                  name="arrow-back"
                  color={ colors.black }
                  size={ 32 }
                />
              }
              nextButton={
                <Icon
                  onPress={ () => { this.swiper.scrollBy(1, false); } }
                  name="arrow-forward"
                  color={ colors.black }
                  size={ 32 }
                />
              }
            >
              <GetEventName // attach validate() to component and access via refs
                ref={ r => { this.name = r; } }
                value={ this.state.name }
                onChange={ (name) => {
                  this.setState(() => ({ name }));
                } }
              />
              <GetEventType
                ref={ r => { this.type = r; } }
                value={ this.state.type }
                onChange={ (type) => {
                  this.setState(() => ({ type }));
                } }
              />
              <GetEventDate
                ref={ r => { this.date = r; } }
                value={ this.state.date }
                onChange={ (date) => {
                  this.setState(() => ({ date }));
                } }
              />
              <GetEventTime
                ref={ r => { this.time = r; } }
                value={ this.state.time }
                onChange={ (time) => {
                  this.setState(() => ({ time }));
                } }
              />
              <GetEventUrl
                ref={ r => { this.url = r; } }
                value={ this.state.url }
                onChange={ (url) => {
                  this.setState(() => ({ url }));
                } }
              />
              <GetEventDescription
                ref={ r => { this.description = r; } }
                value={ this.state.description }
                onChange={ (description) => {
                  this.setState(() => ({ description }));
                } }
              />
              <GetEventLocation
                location={ this.state.location }
                onLocationSelect={ (data, details = null) => {
                  this.setState(() => ({ location: { data, details } }));
                } }
                submitting={ this.state.submitting }
                onSubmit={ this.checkDataAndPush }
                keyboardHeight={ this.state.keyboardHeight }
              />
            </Swiper>
          </Otherwise>
        </Choose>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    justifyContent: 'center',
    alignItems: 'center',
  },
  swiperWrapper: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  slide: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
<commit_msg>anotha one<commit_after>import React, { Component, PropTypes } from 'react';
import {
  StatusBar,
  View,
  StyleSheet,
  LayoutAnimation,
  Platform,
  TextInput,
  ActivityIndicator,
} from 'react-native';
import {
  NavigationStyles,
} from '@exponent/ex-navigation';
import colors from '../config/colors';
import KeyboardEventListener from 'KeyboardEventListener';
import Swiper from 'react-native-swiper';
import Icon from '../components/CrossPlatformIcon';
import GetEventName from '../components/GetEventName';
import GetEventType from '../components/GetEventType';
import GetEventDate from '../components/GetEventDate';
import GetEventTime from '../components/GetEventTime';
import GetEventUrl from '../components/GetEventUrl';
import GetEventDescription from '../components/GetEventDescription';
import GetEventLocation from '../components/GetEventLocation';
import CancelButton from '../components/NavBarCancelButton';
import moment from 'moment';
import filter from '../utils/filter';
import connectDropdownAlert from '../utils/connectDropdownAlert';
import { isExponentPushToken, sendPushNotificationAsync } from '../utils/ExponentPushClient';
import _ from 'lodash';
/**
 *  Allows user to create new events for school
 */
@connectDropdownAlert
export default class NewEventScreen extends Component {
  static route = {
    navigationBar: {
      visible: true,
      title: 'NEW EVENT',
      tintColor: colors.black,
      renderLeft: () => null,
      renderRight: () => <CancelButton />,
      borderBottomColor: 'transparent',
      titleStyle: {
        fontFamily: 'open-sans-bold',
      },
      backgroundColor: 'white',
    },
    styles: {
      ...NavigationStyles.SlideHorizontal,
    },
  }

  static propTypes = {
    navigator: PropTypes.object.isRequired,
    refresh: PropTypes.func,
    alertWithType: PropTypes.func.isRequired,
  }

  state = {
    name: null,
    date: moment.utc().toDate(),
    time: moment.utc().toDate().getTime(),
    url: '',
    submitting: false,
    type: null,
    description: null,
    location: null,
    keyboardHeight: 0,
  }

  componentWillMount() {
    this._unsubscribe = KeyboardEventListener.subscribe(this._onKeyboardVisibilityChange);
  }

  componentWillUnmount() {
    if (this._unsubscribe) {
      this._unsubscribe();
      this._unsubscribe = null;
    }
  }

  createEvent = () => {
    const name = this.state.name !== null && this.state.name.name;
    const type = this.state.type !== null && this.state.type.type;
    const date = this.state.date.date ?
      moment.utc(moment(this.state.date.date).startOf('day')).toJSON() :
      moment.utc(moment(this.state.date).startOf('day')).toJSON();
    const time = {
      hours: this.state.time.time ? moment(this.state.time.time).hours() : moment(this.state.time).hours(),
      minutes: this.state.time.time ? moment(this.state.time.time).minutes() : moment(this.state.time).minutes(),
    };
    const url = this.state.url.url || this.state.url;
    const location = {
      address: this.state.location.details.formatted_address,
      geometry: this.state.location.details.geometry,
    };
    const description = this.state.description !== null && this.state.description.description;
    return {
      name: filter.clean(name.trim()),
      type,
      createdBy: global.firebaseApp.auth().currentUser.uid,
      date,
      time,
      url: url.toLowerCase(),
      createdInDev: __DEV__, // eslint-disable-line jsx-control-statements/jsx-jcs-no-undef
      location,
      description: description && filter.clean(description.trim()),
    };
  }

  checkDataAndPush = () => {
    let propertiesAreValid = true;

    const name = this.state.name !== null && this.state.name.name;
    const date = this.state.date.date ?
      moment.utc(moment(this.state.date.date).startOf('day')) :
      moment.utc(moment(this.state.date).startOf('day'));
    const time = {
      hours: this.state.time.time ? moment(this.state.time.time).hours() : moment(this.state.time).hours(),
      minutes: this.state.time.time ? moment(this.state.time.time).minutes() : moment(this.state.time).minutes(),
    };

    if (name !== filter.clean(name)) {
      this.props.alertWithType('error', 'Error', 'Please mind your choice of words.');
      propertiesAreValid = false;
    }
    if (!date.add(time.hours, 'hours').add(time.minutes, 'minutes').isAfter(moment().add(3, 'hours'))) {
      this.props.alertWithType('error', 'Error', 'Event should be scheduled at least three hours in advance.');
      propertiesAreValid = false;
    }
    ['name', 'date', 'time', 'url', 'type', 'description'].forEach(elem => {
      if (!this[elem].isValid()) {
        this.props.alertWithType('error', 'Error', `Event ${elem} is invalid.`);
        propertiesAreValid = false;
      }
    });
    if (propertiesAreValid) {
      this.submitEvent(this.createEvent());
    }
  }

  _blurFocusedTextInput = () => {
    TextInput.State.blurTextInput(TextInput.State.currentlyFocusedField());
  };

  _isKeyboardOpen = () => {
    return this.state.keyboardHeight > 0;
  }

  _onKeyboardVisibilityChange = (
    { keyboardHeight, layoutAnimationConfig }:
    { keyboardHeight: number, layoutAnimationConfig: ?Object }) => {
    if (keyboardHeight === 0) {
      this._blurFocusedTextInput();
    }

    if (layoutAnimationConfig) {
      LayoutAnimation.configureNext(layoutAnimationConfig);
    }

    this.setState(() => {
      return { keyboardHeight };
    });
  }

  submitEvent = (event) => {
    if (this.state.submitting) {
      return;
    }
    this.setState(() => {
      return { submitting: true };
    });
    global.firebaseApp.database().ref('users')
    .child(global.firebaseApp.auth().currentUser.uid)
    .once('value')
    .then(snap => {
      const schoolUID = snap.val().school;
      global.firebaseApp.database().ref('schools')
      .child(schoolUID)
      .child('events')
      .push(event)
      .then(() => {
        // send pushes to peers
        global.firebaseApp.database().ref('users')
        .once('value')
        .then(usersSnap => {
          _.each(usersSnap.val(), user => {
            if (isExponentPushToken(user.pushToken) && user.school === schoolUID) {
              sendPushNotificationAsync({
                exponentPushToken: user.pushToken,
                message: `There's a new ${event.type.toLowerCase()} event at your school!`,
              }).catch((err) => {
                this.props.alertWithType('error', 'Error', err.toString());
              });
            }
          });

          this.props.alertWithType('success', 'Success', 'Your event was submitted successfully!');
          this.props.refresh();
          this.props.navigator.pop();
        });
      });
    })
    .catch(err => {
      this.setState(() => {
        return { submitting: false };
      });
      this.props.alertWithType('error', 'Error', err.toString());
    });
  }

  render() {
    return (
      <View
        style={ [styles.container, this.state.keyboardHeight ?
          { flex: 1, marginBottom: this.state.keyboardHeight } :
          { flex: 1 },
        ] }
        onLayout={ (e) => {
          const { width, height } = e.nativeEvent.layout;
          this.setState(() => {
            return {
              swiperHeight: height,
              swiperWidth: width,
            };
          });
        } }
      >
        <StatusBar barStyle="dark-content" />
        <Choose>
          <When condition={ this.state.submitting }>
            <ActivityIndicator size="large" />
          </When>
          <Otherwise>
            <Swiper
              ref={ r => { this.swiper = r; } }
              showsPagination
              onScroll={ this._blurFocusedTextInput }
              scrollEventThrottle={ 32 }
              keyboardShouldPersistTaps="always"
              keyboardDismissMode={ Platform.OS === 'ios' ? 'none' : 'on-drag' }
              height={ this.state.swiperHeight }
              contentContainerStyle={ styles.swiperWrapper }
              showsButtons
              loop={ false }
              prevButton={
                <Icon
                  onPress={ () => { this.swiper.scrollBy(-1, false); } }
                  name="arrow-back"
                  color={ colors.black }
                  size={ 32 }
                />
              }
              nextButton={
                <Icon
                  onPress={ () => { this.swiper.scrollBy(1, false); } }
                  name="arrow-forward"
                  color={ colors.black }
                  size={ 32 }
                />
              }
            >
              <GetEventName // attach validate() to component and access via refs
                ref={ r => { this.name = r; } }
                value={ this.state.name }
                onChange={ (name) => {
                  this.setState(() => ({ name }));
                } }
              />
              <GetEventType
                ref={ r => { this.type = r; } }
                value={ this.state.type }
                onChange={ (type) => {
                  this.setState(() => ({ type }));
                } }
              />
              <GetEventDate
                ref={ r => { this.date = r; } }
                value={ this.state.date }
                onChange={ (date) => {
                  this.setState(() => ({ date }));
                } }
              />
              <GetEventTime
                ref={ r => { this.time = r; } }
                value={ this.state.time }
                onChange={ (time) => {
                  this.setState(() => ({ time }));
                } }
              />
              <GetEventUrl
                ref={ r => { this.url = r; } }
                value={ this.state.url }
                onChange={ (url) => {
                  this.setState(() => ({ url }));
                } }
              />
              <GetEventDescription
                ref={ r => { this.description = r; } }
                value={ this.state.description }
                onChange={ (description) => {
                  this.setState(() => ({ description }));
                } }
              />
              <GetEventLocation
                location={ this.state.location }
                onLocationSelect={ (data, details = null) => {
                  this.setState(() => ({ location: { data, details } }));
                } }
                submitting={ this.state.submitting }
                onSubmit={ this.checkDataAndPush }
                keyboardHeight={ this.state.keyboardHeight }
              />
            </Swiper>
          </Otherwise>
        </Choose>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    justifyContent: 'center',
    alignItems: 'center',
  },
  swiperWrapper: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  slide: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
<|endoftext|>


<commit_before>Ti._5.createClass("Ti.UI.ImageView", function(args){
	args = require.mix({
		unselectable: true
	}, args);

	var obj = this,
		domNode = Ti._5.DOMView(obj, "img", args, "ImageView"),
		domStyle = domNode.style,
		isError = false,
		_reverse = false,
		_canScale = true,
		_src = "",
		_images = [],
		_preventDefaultImage = false,
		_height;

	// Interfaces
	Ti._5.Touchable(obj, args);
	Ti._5.Styleable(obj, args);
	Ti._5.Positionable(obj, args);
	Ti._5.Clickable(obj, args);

	function loadImages(images) {
		isError = false;
		_preventDefaultImage || (domNode.src = Ti._5.getAbsolutePath(obj.defaultImage));

		var counter = 0,
			img = new Image(),
			h = require.on(img, "load", function () {
				h && h();
				if (++counter < images.length) {
					domNode.src = Ti._5.getAbsolutePath(images[0]);
					obj.fireEvent("load", {
						state: images.length > 1 ? obj.images : obj.image
					});
				}
			});

		require.on(img, "error",  function () {
			isError = true;
			h && h();
			counter++;
		});

		// start preloading
		require.each(images, function(i) {
			img.src = Ti._5.getAbsolutePath(i);
		});
	}

	// Properties
	Ti._5.prop(obj, {
		animating: null,
		canScale: {
			get: function(){return _canScale;},
			set: function(val){
				_canScale = !!val;
				if (!_canScale) {
					domStyle.width = "auto";
					domStyle.height = "auto";
				}
			}
		},
		defaultImage: "",
		duration: null,
		enableZoomControls: true,
		height: {
			get: function() {
				return _height;
			},
			set: function(val) {
				_height = val;
				domStyle.height = Ti._5.px(val);
			}
		},
		// indicates whether or not the source image is in 2x resolution for retina displays.
		// Use for remote images ONLY. (iOS)
		hires: false,
		image: {
			get: function(){return _src;},
			set: function(val){loadImages([_src = val]);}
		},
		images: {
			get: function(){return _images;},
			set: function(val){
				_images = -1 != val.constructor.toString().indexOf("Array") ? val : [val];
				loadImages(_images);
			}
		},
		paused: null,
		preventDefaultImage: {
			get: function(){return _preventDefaultImage;},
			set: function(val){_preventDefaultImage = !!val;}
		},
		repeatCount: 0,
		reverse: {
			get: function(){return _reverse;},
			set: function(val){_reverse = !!val;}
		},
		size: {
			get: function() {
				return {
					width	: obj.width,
					height	: obj.height
				}
			},
			set: function(val) {
				val.width && (obj.width = Ti._5.px(val.width));
				val.height && (obj.height = Ti._5.px(val.height));
			}
		},
		width: {
			get: function() {
				if (!domStyle.width || !obj.canScale) {
					return "";
				}
				return /%/.test(domStyle.width) ? parseInt(domStyle.width)+"%" : parseInt(domStyle.width);
			},
			set: function(val) {
				obj.canScale && (domStyle.width = /%/.test(val+"") ? parseInt(val) + "%" : parseInt(val) + "px");
			}
		}
	});

	require.mix(obj, args);

	// Methods
	obj.pause = function(){
		console.debug('Method "Titanium.UI.ImageView#.pause" is not implemented yet.');
	};
	obj.start = function(){
		console.debug('Method "Titanium.UI.ImageView#.start" is not implemented yet.');
	};
	obj.stop = function(){
		console.debug('Method "Titanium.UI.ImageView#.stop" is not implemented yet.');
	};
	obj.toBlob = function(){
		console.debug('Method "Titanium.UI.ImageView#.toBlob" is not implemented yet.');
	};

	// Events
	obj.addEventListener("change", function(){
		console.debug('Event "change" is not implemented yet.');
	});
	obj.addEventListener("start", function(){
		console.debug('Event "start" is not implemented yet.');
	});
	obj.addEventListener("stop", function(){
		console.debug('Event "stop" is not implemented yet.');
	});
});
<commit_msg>[TIMOB-6821] Fix for broken imageView when setting a defaultImage property<commit_after>Ti._5.createClass("Ti.UI.ImageView", function(args){
	args = require.mix({
		unselectable: true
	}, args);

	var obj = this,
		domNode = Ti._5.DOMView(obj, "img", args, "ImageView"),
		domStyle = domNode.style,
		isError = false,
		_reverse = false,
		_canScale = true,
		_src = "",
		_images = [],
		_preventDefaultImage = false,
		_height;

	// Interfaces
	Ti._5.Touchable(obj, args);
	Ti._5.Styleable(obj, args);
	Ti._5.Positionable(obj, args);
	Ti._5.Clickable(obj, args);

	function loadImages(images) {
		isError = false;
		_preventDefaultImage || (domNode.src = Ti._5.getAbsolutePath(obj.defaultImage));

		var counter = 0,
			img = new Image(),
			h = require.on(img, "load", function () {
				h && h();
				if (++counter < images.length) {
					domNode.src = Ti._5.getAbsolutePath(images[0]);
					obj.fireEvent("load", {
						state: images.length > 1 ? obj.images : obj.image
					});
				}
			});

		require.on(img, "error",  function () {
			isError = true;
			h && h();
			counter++;
		});

		// start preloading
		require.each(images, function(i) {
			domNode.src = Ti._5.getAbsolutePath(i);
		});
	}

	// Properties
	Ti._5.prop(obj, {
		animating: null,
		canScale: {
			get: function(){return _canScale;},
			set: function(val){
				_canScale = !!val;
				if (!_canScale) {
					domStyle.width = "auto";
					domStyle.height = "auto";
				}
			}
		},
		defaultImage: "",
		duration: null,
		enableZoomControls: true,
		height: {
			get: function() {
				return _height;
			},
			set: function(val) {
				_height = val;
				domStyle.height = Ti._5.px(val);
			}
		},
		// indicates whether or not the source image is in 2x resolution for retina displays.
		// Use for remote images ONLY. (iOS)
		hires: false,
		image: {
			get: function(){return _src;},
			set: function(val){loadImages([_src = val]);}
		},
		images: {
			get: function(){return _images;},
			set: function(val){
				_images = -1 != val.constructor.toString().indexOf("Array") ? val : [val];
				loadImages(_images);
			}
		},
		paused: null,
		preventDefaultImage: {
			get: function(){return _preventDefaultImage;},
			set: function(val){_preventDefaultImage = !!val;}
		},
		repeatCount: 0,
		reverse: {
			get: function(){return _reverse;},
			set: function(val){_reverse = !!val;}
		},
		size: {
			get: function() {
				return {
					width	: obj.width,
					height	: obj.height
				}
			},
			set: function(val) {
				val.width && (obj.width = Ti._5.px(val.width));
				val.height && (obj.height = Ti._5.px(val.height));
			}
		},
		width: {
			get: function() {
				if (!domStyle.width || !obj.canScale) {
					return "";
				}
				return /%/.test(domStyle.width) ? parseInt(domStyle.width)+"%" : parseInt(domStyle.width);
			},
			set: function(val) {
				obj.canScale && (domStyle.width = /%/.test(val+"") ? parseInt(val) + "%" : parseInt(val) + "px");
			}
		}
	});

	require.mix(obj, args);

	// Methods
	obj.pause = function(){
		console.debug('Method "Titanium.UI.ImageView#.pause" is not implemented yet.');
	};
	obj.start = function(){
		console.debug('Method "Titanium.UI.ImageView#.start" is not implemented yet.');
	};
	obj.stop = function(){
		console.debug('Method "Titanium.UI.ImageView#.stop" is not implemented yet.');
	};
	obj.toBlob = function(){
		console.debug('Method "Titanium.UI.ImageView#.toBlob" is not implemented yet.');
	};

	// Events
	obj.addEventListener("change", function(){
		console.debug('Event "change" is not implemented yet.');
	});
	obj.addEventListener("start", function(){
		console.debug('Event "start" is not implemented yet.');
	});
	obj.addEventListener("stop", function(){
		console.debug('Event "stop" is not implemented yet.');
	});
});
<|endoftext|>


<commit_before>(function () {
  if (!window.GIDEO) {
    window.GIDEO = true;

    window.gideoRoot = window.gideoRoot || (
      document.location.protocol + "//dmfrancisco.github.io/gideo/"
    );

    videojs.options.flash.swf = window.gideoRoot + "video-js.swf";

    function isMobile() {
      return navigator.userAgent.match(/(Android|iPod|iPhone|iPad)/);
    }

    function listen(eventName, elem, func) {
      if (elem.addEventListener) {
        elem.addEventListener(eventName, func, false);
      }
      else if (elem.attachEvent) {
        elem.attachEvent("on" + eventName, func);
      }
    }

    function isVisible(elem) {
      var rect = elem.getBoundingClientRect();

      return (
        rect.top > -elem.offsetHeight &&
        rect.top < (window.innerHeight || document.documentElement.clientHeight)
      );
    }

    // Add new CSS rules (based on goo.gl/Ygvaqy)
    function injectStyles(rules) {
      var div = document.createElement('div');
      div.innerHTML = '<style>' + rules + '</style>';
      document.body.appendChild(div.childNodes[1]);
    }

    if (!isMobile()) {
      window.setInterval(function () {
        var embeds = document.querySelectorAll('.gideo');

        for (var i = 0; i < embeds.length; i++) {
          var gideo = embeds[i].player;

          if (!gideo) {
            continue;
          } else if (isVisible(embeds[i])) {
            if (gideo.paused()) {
              try { gideo.currentTime(0); }
              catch (e) { /* Random error with the flash fallback */ }
              gideo.play();
            }
          } else if (!gideo.paused()) {
            gideo.pause();
          }
        }
      }, 1000);

      listen("click", document.querySelector('body'), function (e) {
        var target = e.target ? e.target : e.srcElement;

        if (target.className === "gideo-mute") {
          var gideo = target.nextSibling.player;

          if (!gideo) {
            return;
          } else if (gideo.muted()) {
            try { gideo.currentTime(0); }
            catch (e) { /* Random error with the flash fallback */ }

            gideo.muted(false);
            target.style.backgroundPosition = "0 -36px";
          } else {
            gideo.muted(true);
            target.style.backgroundPosition = "0 0";
          }
        }
      });

      // Inject styles for the mute button
      injectStyles(""
        + " .gideo-mute {"
          + " position: absolute; z-index: 2;"
          + " top: 20px; left: 20px;"
          + " width: 44px; height: 36px;"
          + " background: url("+ window.gideoRoot +"sprites.png);"
          + " cursor: pointer }");
    }

    // Inject styles for the play button (for devices without autoplay)
    injectStyles(""
      + " .gideo .vjs-big-play-button {"
        + " position: absolute; z-index: 2;"
        + " width: 68px; height: 68px;"
        + " top: 50%; left: 50%; margin: -34px auto auto -34px;"
        + " background: url("+ window.gideoRoot +"sprites.png) -44px 0 }"
      + " .gideo.vjs-has-started .vjs-big-play-button {"
        + " display: none }");
  }

  var embeds = document.querySelectorAll('.gideo');

  // Force mute (this is not done using the `muted` attribute in
  // order to work in browsers that require the flash fallback)
  function mute() {
    this.muted(!isMobile());
  }

  // Initialize all videos
  for (var i = 0; i < embeds.length; i++) {
    if (!embeds[i].player) {
      videojs(embeds[i]).ready(mute);
    }
  }
})();
<commit_msg>Add support for a replay / restart button<commit_after>(function () {
  if (!window.GIDEO) {
    window.GIDEO = true;

    window.gideoRoot = window.gideoRoot || (
      document.location.protocol + "//dmfrancisco.github.io/gideo/"
    );

    videojs.options.flash.swf = window.gideoRoot + "video-js.swf";

    function isMobile() {
      return navigator.userAgent.match(/(Android|iPod|iPhone|iPad)/);
    }

    function listen(eventName, elem, func) {
      if (elem.addEventListener) {
        elem.addEventListener(eventName, func, false);
      }
      else if (elem.attachEvent) {
        elem.attachEvent("on" + eventName, func);
      }
    }

    function isVisible(elem) {
      var rect = elem.getBoundingClientRect();

      return (
        rect.top > -elem.offsetHeight &&
        rect.top < (window.innerHeight || document.documentElement.clientHeight)
      );
    }

    // Add new CSS rules (based on goo.gl/Ygvaqy)
    function injectStyles(rules) {
      var div = document.createElement('div');
      div.innerHTML = '<style>' + rules + '</style>';
      document.body.appendChild(div.childNodes[1]);
    }

    if (!isMobile()) {
      window.setInterval(function () {
        var embeds = document.querySelectorAll('.gideo');

        for (var i = 0; i < embeds.length; i++) {
          var gideo = embeds[i].player;

          if (!gideo) {
            continue;
          } else if (isVisible(embeds[i])) {
            if (gideo.paused()) {
              try { gideo.currentTime(0); }
              catch (e) { /* Random error with the flash fallback */ }
              gideo.play();
            }
          } else if (!gideo.paused()) {
            gideo.pause();
          }
        }
      }, 1000);

      listen("click", document.querySelector('body'), function (e) {
        var target = e.target ? e.target : e.srcElement;

        if (target.className === "gideo-mute") {
          var gideo = target.nextSibling.player;

          if (!gideo) {
            return;
          } else if (gideo.muted()) {
            gideo.currentTime(0);
            gideo.muted(false);
            target.style.backgroundPosition = "0 -36px";
          } else {
            gideo.muted(true);
            target.style.backgroundPosition = "0 0";
          }
        } else if (target.className === "gideo-replay") {
          var gideo = target.previousSibling.player;
          if (gideo) { gideo.currentTime(0); }
        }
      });

      // Inject styles for controls
      injectStyles(""
        + " .gideo-mute, .gideo-replay {"
          + " position: absolute; z-index: 2;"
          + " width: 44px; height: 36px; left: 20px;"
          + " background: url("+ window.gideoRoot +"sprites.png);"
          + " cursor: pointer }"
        + " .gideo-mute { top: 20px }"
        + " .gideo-replay { bottom: 20px; background-position: 0 -72px }");
    }

    // Inject styles for the play button (for devices without autoplay)
    injectStyles(""
      + " .gideo .vjs-big-play-button {"
        + " position: absolute; z-index: 2;"
        + " width: 68px; height: 68px;"
        + " top: 50%; left: 50%; margin: -34px auto auto -34px;"
        + " background: url("+ window.gideoRoot +"sprites.png) -44px 0 }"
      + " .gideo.vjs-has-started .vjs-big-play-button {"
        + " display: none }");
  }

  var embeds = document.querySelectorAll('.gideo');

  // Force mute (this is not done using the `muted` attribute in
  // order to work in browsers that require the flash fallback)
  function mute() {
    this.muted(!isMobile());
  }

  // Initialize all videos
  for (var i = 0; i < embeds.length; i++) {
    if (!embeds[i].player) {
      videojs(embeds[i]).ready(mute);
    }
  }
})();
<|endoftext|>


<commit_before>/**
 * Superstore synchronous library
 *
 * @author Matt Andrews <matthew.andrews@ft.com>
 * @copyright The Financial Times [All Rights Reserved]
 */

var keys = {};
var store = {};
var persist = true;

// Watch for changes from other tabs
window.addEventListener("storage", function(e) {
  if(keys[e.key]) {
    keys[e.key] = true;
    store[e.key] = JSON.parse(e.newValue);
  }
});

exports.get = function(key) {
  if (!keys[key] && persist) {
    var data = localStorage[key];

    // Slightly weird hack because JSON.parse of an undefined value throws
    // a weird exception "SyntaxError: Unexpected token u"
    if (data) data = JSON.parse(data);
    store[key] = data;
    keys[key] = true;
  }
  return store[key];
};

exports.set = function(key, value) {
  if (persist) {
    try {
      localStorage[key] = JSON.stringify(value);
    } catch(err) {

      // Known iOS Private Browsing Bug - fall back to non-persistent storage
      if (err.code === 22) {
        persist = false;
      } else {
        throw err;
      }
    }
  }

  store[key] = value;
  keys[key] = true;
};

exports.unset = function(key) {
  delete store[key];
  delete keys[key];
  localStorage.removeItem(key);
};

/**
 * clear localstorage
 * @param clearPrefix will clear keys starting with `clearPrefix`
 * #clear(true) and #clear() clear cache and persistent layer, #clear(false) only clears cache
 *
 */
exports.clear = function(clearPrefix) {
  if(!clearPrefix) {
    if (persist) {
      localStorage.clear();
    }
    store = {};
    keys = {};
    return;
  }

  var clearKeyRegex = new RegExp("^" + clearPrefix);
  for (var key in keys) {
    if (key.match(clearKeyRegex)) {
      this.unset(key);
    }
  }
};
<commit_msg>More Safari annoyances<commit_after>/**
 * Superstore synchronous library
 *
 * @author Matt Andrews <matthew.andrews@ft.com>
 * @copyright The Financial Times [All Rights Reserved]
 */

var keys = {};
var store = {};
var persist = true;

// Watch for changes from other tabs
window.addEventListener("storage", function(e) {
  if(keys[e.key]) {
    keys[e.key] = true;
    store[e.key] = JSON.parse(e.newValue);
  }
});

exports.get = function(key) {
  if (!keys[key] && persist) {
    var data;
    try {
      data = localStorage[key];
    } catch(e) {
      persist = false; // Safari 8 with Cookies set to 'Never' throws on every read
    }

    // Slightly weird hack because JSON.parse of an undefined value throws
    // a weird exception "SyntaxError: Unexpected token u"
    if (data) data = JSON.parse(data);
    store[key] = data;
    keys[key] = true;
  }
  return store[key];
};

exports.set = function(key, value) {
  if (persist) {
    try {
      localStorage[key] = JSON.stringify(value);
    } catch(err) {

      // Known iOS Private Browsing Bug - fall back to non-persistent storage
      if (err.code === 22) {
        persist = false;
      } else {
        throw err;
      }
    }
  }

  store[key] = value;
  keys[key] = true;
};

exports.unset = function(key) {
  delete store[key];
  delete keys[key];
  localStorage.removeItem(key);
};

/**
 * clear localstorage
 * @param clearPrefix will clear keys starting with `clearPrefix`
 * #clear(true) and #clear() clear cache and persistent layer, #clear(false) only clears cache
 *
 */
exports.clear = function(clearPrefix) {
  if(!clearPrefix) {
    if (persist) {
      localStorage.clear();
    }
    store = {};
    keys = {};
    return;
  }

  var clearKeyRegex = new RegExp("^" + clearPrefix);
  for (var key in keys) {
    if (key.match(clearKeyRegex)) {
      this.unset(key);
    }
  }
};
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Sebastian
// Date:      28.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

M.STATE_UNDEFINED = 'state_undefined';
M.STATE_NEW = 'state_new';
M.STATE_INSYNCPOS = 'state_insyncpos';
M.STATE_INSYNCNEG = 'state_insyncneg';
M.STATE_LOCALCHANGED = 'state_localchange';
M.STATE_VALID = 'state_valid';
M.STATE_INVALID = 'state_invalid';
M.STATE_DELETED = 'state_deleted';

m_require('core/foundation/model_registry.js');

/**
 * @class
 *
 * M.Model is the prototype for every model and for every model record (a model itself is the blueprint for a model record).
 * Models hold the business data of an application respectively the application's state. It's usually the part of an application that is persisted to storage.
 * M.Model acts as the gatekeeper to storage. It uses data provider for persistence and validators to validate its records.
 *
 * @extends M.Object
 */
M.Model = M.Object.extend(
/** @scope M.Model.prototype */ {
    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.Model',

    /**
     * The name of the model.
     *
     * @type String
     */
    name: '',

    /**
     * Unique identifier for the model record.
     *
     * Note: Unique doesn't mean that this m_id is a global unique ID, it is just unique
     * for records of this type of model.
     *
     * @type Number
     */
    m_id: null,

    /**
     * The model's record defines the properties that are semantically bound to this model:
     * e.g. a person's record is in simplest case: firstname, lastname, age.
     *
     * @type Object record
     */
    record: null,

    /**
     * Object containing all meta information for the object's properties
     * @type Object
     */
    __meta: {},

    /**
     * Manages records of this model
     * @type Object
     */
    recordManager: null,

    /**
     * List containing all models in application
     * @type Object|Array
     */
    modelList: {},

    /**
     * A constant defining the model's state. Important e.g. for syncing storage
     * @type String
     */
    state: M.STATE_UNDEFINED,

    /**
     * determines whether model shall be validated before saving to storage or not.
     * @type Boolean
     */
    usesValidation: YES,

    /**
     * The model's data provider. A data provider persists the model to a certain storage.
     *
     * @type Object
     */
    dataProvider: null,

    /**
     * Creates a new record of the model, means an instance of the model based on the blueprint.
     * You pass the object's specific attributes to it as an object.
     *
     * @param {Object} obj The properties object, e.g. {firstname: 'peter', lastname ='fox'}
     * @returns {Object} The model record with the passed properties set. State depends on newly creation or fetch from storage: if
     * from storage then state is M.STATE_NEW or 'state_new', if fetched from database then it is M.STATE_VALID or 'state_valid'
     */
    createRecord: function(obj) {
        var rec = this.extend({
            m_id: obj.m_id ? obj.m_id : M.Application.modelRegistry.getNextId(this.name),
            record: obj /* properties that are added to record here, but are not part of __meta, are deleted later (see below) */
        });
        delete obj.m_id;
        rec.state = obj.state ? obj.state : M.STATE_NEW;
        delete obj.state;

        /* set timestamps if new */
        if(rec.state === M.STATE_NEW) {
            rec.record[M.META_CREATED_AT] = M.Date.now().format('yyyy/mm/dd HH:MM:ss');
            rec.record[M.META_UPDATED_AT] = M.Date.now().format('yyyy/mm/dd HH:MM:ss');
        }

        /* if record contains properties that are not part of __meta (means that are not defined in the model blueprint) delete them */
        for(var i in rec.record) {
            if(i === 'ID') {
                continue;
            }
            if(!rec.__meta.hasOwnProperty(i)) {
                delete rec.record[i];
            }
        }
        this.recordManager.add(rec);
        return rec;
    },

    /**
     * Create defines a new model blueprint. It is passed an object with the model's attributes and the model's business logic
     * and after it the type of data provider to use.
     *
     * @param {Object} obj An object defining the model's
     * @param {Object} dp The data provider to use, e. g. M.LocalStorageProvider
     * @returns {Object} The model blueprint: acts as blueprint to all records created with @link M.Model#createRecord
     */
    create: function(obj, dp) {
        var model = M.Model.extend({
            __meta: {},
            name: obj.__name__,
            dataProvider: dp,
            recordManager: {},
            usesValidation: obj.usesValidation === null || obj.usesValidation === undefined ? this.usesValidation : obj.usesValidation
        });
        delete obj.__name__;
        delete obj.usesValidation;

        for(var prop in obj) {
            if(typeof(obj[prop]) === 'function') {
                model[prop] = obj[prop];
            } else if(obj[prop].type === 'M.ModelAttribute') {
                model.__meta[prop] = obj[prop];
            }
        }

        /* add _createdAt und _modifiedAt properties in meta for timestamps  */
        model.__meta[M.META_CREATED_AT] = this.attr('String', { // could be 'Date', too
            isRequired:YES
        });
        model.__meta[M.META_UPDATED_AT] = this.attr('String', { // could be 'Date', too
            isRequired:YES
        });

        model.recordManager = M.RecordManager.extend({});

        /* if dataprovider is WebSqlProvider, create table for this model */
        if(model.dataProvider.type === 'M.WebSqlProvider') {
            model.dataProvider.init({model: model, onError:function(err){console.log(err);}}, function() {});
            model.dataProvider.isInitialized = YES;
        }

        M.Application.modelRegistry.register(model.name);

        /* save model in modelList with model name as key */
        this.modelList[model.name] = this;

        /* Re-set the just registered model's id, if there is a value stored */
        /* Model Registry stores the current id of a model type into localStorage */
        var m_id = localStorage.getItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + model.name);
        if(m_id) {
            M.Application.modelRegistry.setId(model.name, parseInt(m_id));
        }
        return model;
    },

    /**
     * Defines a to-one-relationship.
     * @param refName
     * @param refEntity
     */
    hasOne: function(refEntity, obj) {
        var relAttr = this.attr('Reference', {
            refType: 'toOne',
            reference: refEntity,
            validators: obj.validators,
            isRequired: obj.isRequired
        });
        return relAttr;
    },

    /**
     * Defines a to-many-relationship
     * @param colName
     * @param refEntity
     * @param invRel
     */
    hasMany: function(colName, refEntity, invRel) {
        var relAttr = this.attr('Reference', {
            refType: 'toMany',
            reference: refEntity
        });
        return relAttr;
    },

    /**
     * Returns a M.ModelAttribute object to map an attribute in our record.
     *
     * @param {String} type type of the attribute
     * @param {Object} opts options for the attribute, like required flag and validators array
     * @returns {Object} An M.ModelAttribute object configured with the type and options passed to the function.
     */
    attr: function(type, opts) {
        return M.ModelAttribute.attr(type, opts);
    },

    /*
     * get and set methods for encapsulated attribute access
     */

    /**
     * Get attribute propName from model
     * @param {String} propName the name of the property whose value shall be returned
     * @returns {Object|String} value of property
     */
    get: function(propName) {
        return this.record[propName];
    },

    /**
     * Set attribute propName of model with value val, sets' property to isUpdated (=> will be included in UPDATE call)
     * and sets a new timestamp to _updatedAt.
     * @param {String} propName the name of the property whose value shall be set
     * @param {String|Object} val the new value
     */
    set: function(propName, val) {
        this.record[propName] = val;
        this.__meta[propName].isUpdated = YES;
        /* mark record as updated with new timestamp*/
        this.record['_updatedAt'] = M.Date.now().format('yyyy/mm/dd HH:MM:ss');
    },

    /**
     * Returns the records array of the model's record manager.
     * @returns {Object|Array} The records array of record manager.
     */
    records: function() {
        if(this.recordManager && this.recordManager.records) {
            return this.recordManager.records;
        }
    },

    /**
     * Validates the model, means calling validate for each property.
     * @returns {Boolean} Indicating whether this record is valid (YES|true) or not (NO|false).
     */
    validate: function() {
        var isValid = YES;
        var validationErrorOccured = NO;
        /* clear validation error buffer before validation */
        M.Validator.clearErrorBuffer();

        /*
        * validationBasis depends on the state of the model: if the model is in state NEW, all properties (__meta includes all)
        * shall be considered for validation. if model is in another state, the model's record is used. example: the model is loaded from
        * a database with only two properties included (select name, age FROM...). record now only contains these two properties but __meta
        * still has all properties listed. models are valid if loaded from database so when saved again only the loaded properties need to get
        * validated because all others have not been touched. that's why then record is used.
        * */
        var validationBasis = this.state === M.STATE_NEW ? this.__meta : this.record;

        for (var i in validationBasis) {
            if(i === 'ID') { // skip property ID
                continue;
            }
            var prop = this.__meta[i];
            var obj = {
                value: this.record[i],
                modelId: this.name + '_' + this.m_id,
                property: i
            };
            if (!prop.validate(obj)) {
                isValid = NO;
            }
        }
        /* set state of model */
        /*if(!isValid) {
            this.state = M.STATE_INVALID;
        } else {
            this.state = M.STATE_VALID;
        }*/
        return isValid;
    },

    /* CRUD Methods below */
    /**
     * Calls the corresponding find() of the data provider to fetch data based on the passed query or key.
     *
     * @param {Object} obj The param object with query or key and callbacks.
     * @returns {Boolean|Object} Depends on data provider used. When WebSQL used, a boolean is returned, the find result is returned asynchronously,
     * because the call itself is asynchronous. If LocalStorage is used, the result of the query is returned.
     */
    find: function(obj){
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }
        obj = obj ? obj : {};
        /* check if the record list shall be cleared (default) before new found model records are appended to the record list */
        /* TODO: needs to be placed in callback */
        obj['deleteRecordList'] = obj['deleteRecordList'] ? obj.deleteRecordList : YES;
        if(obj.deleteRecordList) {
            this.recordManager.removeAll();
        }
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }

        /* extends the given obj with self as model property in obj */
        return this.dataProvider.find( $.extend(obj, {model: this}) );
    },

    /**
     * Create or update a record in storage if it is valid (first check this).
     *
     * @param {Object} obj The param object with query and callbacks.
     * @returns {Boolean} The result of the data provider function call. Is a boolean. With LocalStorage used, it indicates if the save operation was successful.
     * When WebSQL is used, the result of the save operation returns asynchronously. The result then is just the standard result returned by the web sql provider's save method
     * which does not necessarily indicate whether the operation was successful, because the operation is asynchronous, means the operation's end is not predictable.
     */
    save: function(obj) {
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }
        obj = obj ? obj: {};
        if(!this.m_id) {
            return NO;
        }
        var isValid = YES;

        if(this.usesValidation) {
            isValid = this.validate();
        }

        if(isValid) {
            return this.dataProvider.save($.extend(obj, {model: this}));
        }
    },

    /**
     * Delete a record in storage.
     * @returns {Boolean} Indicating whether deletion was successful or not (only with synchronous data providers, e.g. LocalStorage). When asynchronous data providers
     * are used, e.g. WebSQL provider the real result comes asynchronous and here just the result of the del() function call of the @link M.WebSqlProvider is used.
     */
    del: function(obj) {
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }
        obj = obj ? obj : {};
        if(!this.m_id) {
            return NO;
        }

       var isDel = this.dataProvider.del($.extend(obj, {model: this}));
        if(isDel) {
            this.state = M.STATE_DELETED;
            return YES
        }

    }

});<commit_msg>set now checks if value is not the same: set only done if new value is different from old value<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Sebastian
// Date:      28.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

M.STATE_UNDEFINED = 'state_undefined';
M.STATE_NEW = 'state_new';
M.STATE_INSYNCPOS = 'state_insyncpos';
M.STATE_INSYNCNEG = 'state_insyncneg';
M.STATE_LOCALCHANGED = 'state_localchange';
M.STATE_VALID = 'state_valid';
M.STATE_INVALID = 'state_invalid';
M.STATE_DELETED = 'state_deleted';

m_require('core/foundation/model_registry.js');

/**
 * @class
 *
 * M.Model is the prototype for every model and for every model record (a model itself is the blueprint for a model record).
 * Models hold the business data of an application respectively the application's state. It's usually the part of an application that is persisted to storage.
 * M.Model acts as the gatekeeper to storage. It uses data provider for persistence and validators to validate its records.
 *
 * @extends M.Object
 */
M.Model = M.Object.extend(
/** @scope M.Model.prototype */ {
    /**
     * The type of this object.
     *
     * @type String
     */
    type: 'M.Model',

    /**
     * The name of the model.
     *
     * @type String
     */
    name: '',

    /**
     * Unique identifier for the model record.
     *
     * Note: Unique doesn't mean that this m_id is a global unique ID, it is just unique
     * for records of this type of model.
     *
     * @type Number
     */
    m_id: null,

    /**
     * The model's record defines the properties that are semantically bound to this model:
     * e.g. a person's record is in simplest case: firstname, lastname, age.
     *
     * @type Object record
     */
    record: null,

    /**
     * Object containing all meta information for the object's properties
     * @type Object
     */
    __meta: {},

    /**
     * Manages records of this model
     * @type Object
     */
    recordManager: null,

    /**
     * List containing all models in application
     * @type Object|Array
     */
    modelList: {},

    /**
     * A constant defining the model's state. Important e.g. for syncing storage
     * @type String
     */
    state: M.STATE_UNDEFINED,

    /**
     * determines whether model shall be validated before saving to storage or not.
     * @type Boolean
     */
    usesValidation: YES,

    /**
     * The model's data provider. A data provider persists the model to a certain storage.
     *
     * @type Object
     */
    dataProvider: null,

    /**
     * Creates a new record of the model, means an instance of the model based on the blueprint.
     * You pass the object's specific attributes to it as an object.
     *
     * @param {Object} obj The properties object, e.g. {firstname: 'peter', lastname ='fox'}
     * @returns {Object} The model record with the passed properties set. State depends on newly creation or fetch from storage: if
     * from storage then state is M.STATE_NEW or 'state_new', if fetched from database then it is M.STATE_VALID or 'state_valid'
     */
    createRecord: function(obj) {
        var rec = this.extend({
            m_id: obj.m_id ? obj.m_id : M.Application.modelRegistry.getNextId(this.name),
            record: obj /* properties that are added to record here, but are not part of __meta, are deleted later (see below) */
        });
        delete obj.m_id;
        rec.state = obj.state ? obj.state : M.STATE_NEW;
        delete obj.state;

        /* set timestamps if new */
        if(rec.state === M.STATE_NEW) {
            rec.record[M.META_CREATED_AT] = M.Date.now().format('yyyy/mm/dd HH:MM:ss');
            rec.record[M.META_UPDATED_AT] = M.Date.now().format('yyyy/mm/dd HH:MM:ss');
        }

        /* if record contains properties that are not part of __meta (means that are not defined in the model blueprint) delete them */
        for(var i in rec.record) {
            if(i === 'ID') {
                continue;
            }
            if(!rec.__meta.hasOwnProperty(i)) {
                delete rec.record[i];
            }
        }
        this.recordManager.add(rec);
        return rec;
    },

    /**
     * Create defines a new model blueprint. It is passed an object with the model's attributes and the model's business logic
     * and after it the type of data provider to use.
     *
     * @param {Object} obj An object defining the model's
     * @param {Object} dp The data provider to use, e. g. M.LocalStorageProvider
     * @returns {Object} The model blueprint: acts as blueprint to all records created with @link M.Model#createRecord
     */
    create: function(obj, dp) {
        var model = M.Model.extend({
            __meta: {},
            name: obj.__name__,
            dataProvider: dp,
            recordManager: {},
            usesValidation: obj.usesValidation === null || obj.usesValidation === undefined ? this.usesValidation : obj.usesValidation
        });
        delete obj.__name__;
        delete obj.usesValidation;

        for(var prop in obj) {
            if(typeof(obj[prop]) === 'function') {
                model[prop] = obj[prop];
            } else if(obj[prop].type === 'M.ModelAttribute') {
                model.__meta[prop] = obj[prop];
            }
        }

        /* add _createdAt und _modifiedAt properties in meta for timestamps  */
        model.__meta[M.META_CREATED_AT] = this.attr('String', { // could be 'Date', too
            isRequired:YES
        });
        model.__meta[M.META_UPDATED_AT] = this.attr('String', { // could be 'Date', too
            isRequired:YES
        });

        model.recordManager = M.RecordManager.extend({});

        /* if dataprovider is WebSqlProvider, create table for this model */
        if(model.dataProvider.type === 'M.WebSqlProvider') {
            model.dataProvider.init({model: model, onError:function(err){console.log(err);}}, function() {});
            model.dataProvider.isInitialized = YES;
        }

        M.Application.modelRegistry.register(model.name);

        /* save model in modelList with model name as key */
        this.modelList[model.name] = this;

        /* Re-set the just registered model's id, if there is a value stored */
        /* Model Registry stores the current id of a model type into localStorage */
        var m_id = localStorage.getItem(M.LOCAL_STORAGE_PREFIX + M.Application.name + M.LOCAL_STORAGE_SUFFIX + model.name);
        if(m_id) {
            M.Application.modelRegistry.setId(model.name, parseInt(m_id));
        }
        return model;
    },

    /**
     * Defines a to-one-relationship.
     * @param refName
     * @param refEntity
     */
    hasOne: function(refEntity, obj) {
        var relAttr = this.attr('Reference', {
            refType: 'toOne',
            reference: refEntity,
            validators: obj.validators,
            isRequired: obj.isRequired
        });
        return relAttr;
    },

    /**
     * Defines a to-many-relationship
     * @param colName
     * @param refEntity
     * @param invRel
     */
    hasMany: function(colName, refEntity, invRel) {
        var relAttr = this.attr('Reference', {
            refType: 'toMany',
            reference: refEntity
        });
        return relAttr;
    },

    /**
     * Returns a M.ModelAttribute object to map an attribute in our record.
     *
     * @param {String} type type of the attribute
     * @param {Object} opts options for the attribute, like required flag and validators array
     * @returns {Object} An M.ModelAttribute object configured with the type and options passed to the function.
     */
    attr: function(type, opts) {
        return M.ModelAttribute.attr(type, opts);
    },

    /*
     * get and set methods for encapsulated attribute access
     */

    /**
     * Get attribute propName from model
     * @param {String} propName the name of the property whose value shall be returned
     * @returns {Object|String} value of property
     */
    get: function(propName) {
        return this.record[propName];
    },

    /**
     * Set attribute propName of model with value val, sets' property to isUpdated (=> will be included in UPDATE call)
     * and sets a new timestamp to _updatedAt. Will not do anything, if newVal is the same as the current prop value.
     * @param {String} propName the name of the property whose value shall be set
     * @param {String|Object} val the new value
     */
    set: function(propName, val) {
        if(this.record[propName] !== val) {
            console.log('isch anders');
            this.record[propName] = val;
            this.__meta[propName].isUpdated = YES;
            /* mark record as updated with new timestamp*/
            this.record['_updatedAt'] = M.Date.now().format('yyyy/mm/dd HH:MM:ss');
        }
    },

    /**
     * Returns the records array of the model's record manager.
     * @returns {Object|Array} The records array of record manager.
     */
    records: function() {
        if(this.recordManager && this.recordManager.records) {
            return this.recordManager.records;
        }
    },

    /**
     * Validates the model, means calling validate for each property.
     * @returns {Boolean} Indicating whether this record is valid (YES|true) or not (NO|false).
     */
    validate: function() {
        var isValid = YES;
        var validationErrorOccured = NO;
        /* clear validation error buffer before validation */
        M.Validator.clearErrorBuffer();

        /*
        * validationBasis depends on the state of the model: if the model is in state NEW, all properties (__meta includes all)
        * shall be considered for validation. if model is in another state, the model's record is used. example: the model is loaded from
        * a database with only two properties included (select name, age FROM...). record now only contains these two properties but __meta
        * still has all properties listed. models are valid if loaded from database so when saved again only the loaded properties need to get
        * validated because all others have not been touched. that's why then record is used.
        * */
        var validationBasis = this.state === M.STATE_NEW ? this.__meta : this.record;

        for (var i in validationBasis) {
            if(i === 'ID') { // skip property ID
                continue;
            }
            var prop = this.__meta[i];
            var obj = {
                value: this.record[i],
                modelId: this.name + '_' + this.m_id,
                property: i
            };
            if (!prop.validate(obj)) {
                isValid = NO;
            }
        }
        /* set state of model */
        /*if(!isValid) {
            this.state = M.STATE_INVALID;
        } else {
            this.state = M.STATE_VALID;
        }*/
        return isValid;
    },

    /* CRUD Methods below */
    /**
     * Calls the corresponding find() of the data provider to fetch data based on the passed query or key.
     *
     * @param {Object} obj The param object with query or key and callbacks.
     * @returns {Boolean|Object} Depends on data provider used. When WebSQL used, a boolean is returned, the find result is returned asynchronously,
     * because the call itself is asynchronous. If LocalStorage is used, the result of the query is returned.
     */
    find: function(obj){
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }
        obj = obj ? obj : {};
        /* check if the record list shall be cleared (default) before new found model records are appended to the record list */
        /* TODO: needs to be placed in callback */
        obj['deleteRecordList'] = obj['deleteRecordList'] ? obj.deleteRecordList : YES;
        if(obj.deleteRecordList) {
            this.recordManager.removeAll();
        }
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }

        /* extends the given obj with self as model property in obj */
        return this.dataProvider.find( $.extend(obj, {model: this}) );
    },

    /**
     * Create or update a record in storage if it is valid (first check this).
     *
     * @param {Object} obj The param object with query and callbacks.
     * @returns {Boolean} The result of the data provider function call. Is a boolean. With LocalStorage used, it indicates if the save operation was successful.
     * When WebSQL is used, the result of the save operation returns asynchronously. The result then is just the standard result returned by the web sql provider's save method
     * which does not necessarily indicate whether the operation was successful, because the operation is asynchronous, means the operation's end is not predictable.
     */
    save: function(obj) {
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }
        obj = obj ? obj: {};
        if(!this.m_id) {
            return NO;
        }
        var isValid = YES;

        if(this.usesValidation) {
            isValid = this.validate();
        }

        if(isValid) {
            return this.dataProvider.save($.extend(obj, {model: this}));
        }
    },

    /**
     * Delete a record in storage.
     * @returns {Boolean} Indicating whether deletion was successful or not (only with synchronous data providers, e.g. LocalStorage). When asynchronous data providers
     * are used, e.g. WebSQL provider the real result comes asynchronous and here just the result of the del() function call of the @link M.WebSqlProvider is used.
     */
    del: function(obj) {
        if(!this.dataProvider) {
            M.Logger.log('No data provider given.', M.ERROR);
        }
        obj = obj ? obj : {};
        if(!this.m_id) {
            return NO;
        }

       var isDel = this.dataProvider.del($.extend(obj, {model: this}));
        if(isDel) {
            this.state = M.STATE_DELETED;
            return YES
        }

    }

});<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var logger = require('morgan');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//= DATABASE_REQUIRE
//= PASSPORT_REQUIRE
//= SASS_MIDDLEWARE_REQUIRE

var app = express();
//= DATABASE_CONNECTION
//= TEMPLATE_ENGINE

app.set('port', process.env.PORT || 3000);
//= SASS_MIDDLEWARE
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
  secret: 'keyboard cat',
  resave: true,
  saveUninitialized: true
}));
//= PASSPORT_MIDDLEWARE
app.use(express.static(path.join(__dirname, 'public')));

// development error handler
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    // TODO: replace if no template engine provided
    // TODO: need to replace for other engines?
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

app.listen(app.get('port'), function() {
  console.log('Express server listening on port ' + app.get('port'));
});
<commit_msg>Added less middleware strings<commit_after>var express = require('express');
var path = require('path');
var logger = require('morgan');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//= DATABASE_REQUIRE
//= PASSPORT_REQUIRE
//= SASS_MIDDLEWARE_REQUIRE
//= LESS_MIDDLEWARE_REQUIRE

var app = express();
//= DATABASE_CONNECTION
//= TEMPLATE_ENGINE

app.set('port', process.env.PORT || 3000);
//= SASS_MIDDLEWARE
//= LESS_MIDDLEWARE
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
  secret: 'keyboard cat',
  resave: true,
  saveUninitialized: true
}));
//= PASSPORT_MIDDLEWARE
app.use(express.static(path.join(__dirname, 'public')));

// development error handler
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    // TODO: replace if no template engine provided
    // TODO: need to replace for other engines?
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});

app.listen(app.get('port'), function() {
  console.log('Express server listening on port ' + app.get('port'));
});
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var path = require('path');
var constants = require('constants');

var async = require('async');

var config = require('util/config');
var fsutil = require('util/fs');
var misc = require('util/misc');
var log = require('util/log');

/**
 * Manages a directory for temporary files.
 * @constructor
 */
function TempFileManager() {
  var conf = config.get();
  this.root = conf['temp_dir'];
  this.used = {};
}

/**
 * Initialize the temporary file manager. This will remove any existing
 * files in the tmp directory, so it should generally only be called during
 * initialization.
 * @param {Function} callback A callback fired with (err).
 */
TempFileManager.prototype.init = function(callback) {
  var self = this;

  function removeExisting(callback) {
    path.exists(self.root, function(exists) {
      if (exists) {
        fsutil.rmtree(self.root, callback);
      } else {
        callback();
      }
    });
  }

  function recreate(callback) {
    fs.mkdir(self.root, 0700, callback);
  }

  async.series([removeExisting, recreate], callback);
};

/**
 * Retrieve a path for a temporary file.
 * @param {String} extension An optional extension to use for the path.
 * @returns {String}
 */
TempFileManager.prototype.allocate = function(extension) {
  extension = extension || '';
  var name = '.cast_tmp_' + misc.randstr(8) + extension;

  if (this.used[name]) {
    return this.allocate(extension);
  } else {
    this.used[name] = true;
    return path.join(this.root, name);
  }
};

/**
 * Remove a temporary file (or directory) and free its name for (potential)
 * re-use. You should call this when you are done with a temporary file, even
 * if you have manually deleted or moved the file. Errors aren't practically
 * actionable, so this takes no callback.
 * @param {String} tmpPath The path to the file to remove.
 */
TempFileManager.prototype.free = function(tmpPath) {
  var self = this;
  var name = path.basename(tmpPath);
  fsutil.rmtree(tmpPath, function(err) {
    if (!err) {
      delete this.used[name];
    } else if (err.errno !== constants.EEXIST) {
      log.warn('error delting temporary file: ' + err.message);
    }
  });
};

exports.TempFileManager = TempFileManager;
<commit_msg>fix tempfiles file removal bug<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var path = require('path');
var constants = require('constants');

var async = require('async');

var config = require('util/config');
var fsutil = require('util/fs');
var misc = require('util/misc');
var log = require('util/log');

/**
 * Manages a directory for temporary files.
 * @constructor
 */
function TempFileManager() {
  var conf = config.get();
  this.root = conf['temp_dir'];
  this.used = {};
}

/**
 * Initialize the temporary file manager. This will remove any existing
 * files in the tmp directory, so it should generally only be called during
 * initialization.
 * @param {Function} callback A callback fired with (err).
 */
TempFileManager.prototype.init = function(callback) {
  var self = this;

  function removeExisting(callback) {
    path.exists(self.root, function(exists) {
      if (exists) {
        fsutil.rmtree(self.root, callback);
      } else {
        callback();
      }
    });
  }

  function recreate(callback) {
    fs.mkdir(self.root, 0700, callback);
  }

  async.series([removeExisting, recreate], callback);
};

/**
 * Retrieve a path for a temporary file.
 * @param {String} extension An optional extension to use for the path.
 * @returns {String}
 */
TempFileManager.prototype.allocate = function(extension) {
  extension = extension || '';
  var name = '.cast_tmp_' + misc.randstr(8) + extension;

  if (this.used[name]) {
    return this.allocate(extension);
  } else {
    this.used[name] = true;
    return path.join(this.root, name);
  }
};

/**
 * Remove a temporary file (or directory) and free its name for (potential)
 * re-use. You should call this when you are done with a temporary file, even
 * if you have manually deleted or moved the file. Errors aren't practically
 * actionable, so this takes no callback.
 * @param {String} tmpPath The path to the file to remove.
 */
TempFileManager.prototype.free = function(tmpPath) {
  var self = this;
  var name = path.basename(tmpPath);
  fsutil.rmtree(tmpPath, function(err) {
    if (!err) {
      delete self.used[name];
    } else if (err.errno !== constants.ENOENT) {
      log.warn('error delting temporary file: ' + err.message);
    }
  });
};

exports.TempFileManager = TempFileManager;
<|endoftext|>


<commit_before>const utils = require('../utils/utils.js');

module.exports = {
  run: function(filepath) {
    const Mocha = require('mocha'),
    fs = require('fs-extra'),
    path = require('path');

    const mocha = new Mocha();

    if (filepath) {
      if (filepath.substr(-1) === '/') {
        // Add each .js file to the mocha instance
        fs.readdirSync(filepath).filter(function(file){
          // Only keep the .js files
          // TODO: make this a configuration in embark.json
          return file.substr(-3) === '.js';
        }).forEach(function(file){
          mocha.addFile(
            path.join(filepath, file)
          );
        });
      } else {
        mocha.addFile(filepath);
      }
    } else {
      var testDir = 'test/';

      // Add each .js file to the mocha instance
      fs.readdirSync(testDir).filter(function(file){
        // Only keep the .js files
        // TODO: make this a configuration in embark.json
        return file.substr(-3) === '.js';
      }).forEach(function(file){
        mocha.addFile(
          path.join(testDir, file)
        );
      });
    }

    let Test = require('./test.js');

    global.assert = require('assert');

    let configOptions = {
      gasPrice: 1
    };
    global.config = function(config) {
      configOptions = utils.recursiveMerge(configOptions, config);
    };
    // TODO: check how to pass the options
    //global.EmbarkSpec = new Test(options);

    // TODO: this global here might not be necessary at all
    global.EmbarkSpec = new Test({});
    global.web3 = global.EmbarkSpec.web3;

    global.contract = function(describeName, callback) {
      return Mocha.describe(describeName, callback);
    };

    // Run the tests.
    let runner = mocha.run(function(failures) {
      // Clean contracts folder for next test run
      fs.remove('.embark/contracts', (_err) => {
        process.on('exit', function () {
          process.exit(failures);  // exit with non-zero status if there were failures
        });
        process.exit();
      });
    });

    runner.on('suite', function() {
      global.assert = require('assert');
      global.EmbarkSpec = new Test({simulatorOptions: configOptions});
      global.web3 = global.EmbarkSpec.web3;
    });

  }
};
<commit_msg>reformat run_test<commit_after>const async = require('async');
const fs = require('fs-extra');
const Mocha = require('mocha');
const path = require('path');
const Test = require('./test.js');
const utils = require('../utils/utils.js');

function getFilesFromDir(filePath, cb) {
  fs.readdir(filePath, (err, files) => {
    if (err) {
      return cb(err);
    }
    const testFiles = files.filter((file) => {
      // Only keep the .js files
      // TODO: make this a configuration in embark.json
      return file.substr(-3) === '.js';
    }).map((file) => {
      return path.join(filePath, file);
    });
    cb(null, testFiles);
  });
}

module.exports = {
  run: function(filePath) {
    const mocha = new Mocha();
    if (!filePath) {
      filePath = 'test/';
    }
    let configOptions = {
      gasPrice: 1
    };

    async.waterfall([
      function getFiles(next) {
        if (filePath.substr(-1) !== '/') {
          mocha.addFile(filePath);
          return next();
        }
        getFilesFromDir(filePath, (err, files) => {
          if (err) {
            console.error('Error while reading the directory');
            return next(err);
          }
          files.forEach(file => {
            mocha.addFile(file);
          });
          next();
        });
      },
      function setupGlobalNamespace(next) {
        // ---------------- Deprecated code ------------------------------------------------------------
        global.assert = require('assert');

        global.config = function(config) {
          configOptions = utils.recursiveMerge(configOptions, config);
        };
        // TODO: check how to pass the options
        //global.EmbarkSpec = new Test(options);

        // TODO: this global here might not be necessary at all
        global.EmbarkSpec = new Test({});
        global.web3 = global.EmbarkSpec.web3;

        global.contract = function(describeName, callback) {
          return Mocha.describe(describeName, callback);
        };
        next();
        // ---------------- Deprecated code ------------------------------------------------------------
      }
    ], (err) => {
      if (err) {
        console.error(err);
        process.exit(1);
      }
      // Run the tests.
      let runner = mocha.run(function(failures) {
        // Clean contracts folder for next test run
        fs.remove('.embark/contracts', (_err) => {
          process.on('exit', function () {
            process.exit(failures);  // exit with non-zero status if there were failures
          });
          process.exit();
        });
      });

      runner.on('suite', function() {
        global.assert = require('assert');
        global.EmbarkSpec = new Test({simulatorOptions: configOptions});
        global.web3 = global.EmbarkSpec.web3;
      });
    });
  }
};
<|endoftext|>