<commit_before>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2015, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */

(function(Utils, API) {
  'use strict';

  var OSjs = window.OSjs = window.OSjs || {};
  //var WL   = window.WL   = window.WL || {};

  OSjs.Helpers = OSjs.Helpers || {};

  var redirectURI = window.location.href.replace(/\/$/, '') + '/vendor/wlOauthReceiver.html';

  /////////////////////////////////////////////////////////////////////////////
  // API
  /////////////////////////////////////////////////////////////////////////////

  var SingletonInstance = null;

  /**
   * The WindowsLiveAPI wrapper class
   *
   * This is a private class and can only be aquired through
   * OSjs.Helpers.WindowsLiveAPI.createInsatance()
   *
   * Generally you want to create an instance of this helper
   * and when successfully created use `window.WL`.
   *
   * @see OSjs.Helpers.WindowsLiveAPI.createInsatance()
   * @api OSjs.Helpers.WindowsLiveAPI.WindowsLiveAPI
   *
   * @link http://msdn.microsoft.com/en-us/library/hh826547.aspx
   * @link http://msdn.microsoft.com/en-us/library/hh826538.aspx
   * @link http://msdn.microsoft.com/en-us/library/hh550837.aspx
   * @link http://msdn.microsoft.com/en-us/library/dn631844.aspx
   * @link http://msdn.microsoft.com/en-us/library/dn631839.aspx
   * @link http://msdn.microsoft.com/en-us/library/hh243643.aspx
   * @link https://account.live.com/developers/applications/index
   *
   * @private
   * @class
   */
  function WindowsLiveAPI(clientId) {
    this.hasSession = false;
    this.clientId = clientId;
    this.loaded = false;
    this.inited = false;
    this.accessToken = null;
    this.lastScope = null;
    this.preloads = [{
      type: 'javascript',
      src: '//js.live.net/v5.0/wl.js'
    }];
  }

  /**
   * Destroy the class
   */
  WindowsLiveAPI.prototype.destroy = function() {
  };

  /**
   * Initializes (preloads) the API
   */
  WindowsLiveAPI.prototype.init = function(callback) {
    callback = callback || function() {};
    var self = this;
    if ( this.loaded ) {
      callback(false, true);
    } else {
      Utils.preload(this.preloads, function(total, failed) {
        if ( !failed.length ) {
          self.loaded = true;
        }
        callback(failed.join('\n'));
      });
    }
  };

  /**
   * Loads the API
   */
  WindowsLiveAPI.prototype.load = function(scope, callback) {
    console.debug('WindowsLiveAPI::load()', scope);

    var self = this;
    var WL = window.WL || {};

    function _login() {
      var lastScope = (self.lastScope || []).sort();
      var currScope = (scope || []).sort();

      if ( self.hasSession && (lastScope.toString() === currScope.toString()) ) {
        callback(false, true);
        return;
      }

      self.login(scope, function(error, response) {
        if ( error ) {
          callback(error);
          return;
        }

        setTimeout(function() {
          callback(false, true);
        }, 10);
      });
    }

    this.init(function(error) {
      if ( error ) {
        callback(error);
        return;
      }

      if ( !window.WL ) {
        callback(API._('WLAPI_LOAD_FAILURE'));
        return;
      }
      WL = window.WL || {};

      if ( self.inited ) {
        _login();
      } else {
        self.inited = true;
        WL.Event.subscribe('auth.login', function() {
          self.onLogin.apply(self, arguments);
        });
        WL.Event.subscribe('auth.logout', function() {
          self.onLogout.apply(self, arguments);
        });
        WL.Event.subscribe('wl.log', function() {
          self.onLog.apply(self, arguments);
        });
        WL.Event.subscribe('auth.sessionChange', function() {
          self.onSessionChange.apply(self, arguments);
        });

        WL.init({
          client_id: self.clientId,
          display: 'popup',
          redirect_uri: redirectURI
        }).then(function(result) {
          console.debug('WindowsLiveAPI::load()', '=>', result);

          if ( result.session ) {
            self.accessToken = result.session.access_token || null;
          }

          if ( result.status === 'connected' ) {
            callback(false, true);
          } else if ( result.status === 'success' ) {
            _login();
          } else {
            callback(API._('WLAPI_INIT_FAILED_FMT', result.status.toString()));
          }
        }, function(result) {
          console.error('WindowsLiveAPI::load()', 'init() error', result);
          callback(result.error_description);
        });
      }
    });
  };

  WindowsLiveAPI.prototype._removeRing = function() {
    var ring = API.getServiceNotificationIcon();
    if ( ring ) {
      ring.remove('Windows Live API');
    }
  };

  /**
   * Sign out of WindowsLiveAPI
   *
   * @param   Function    cb      Callback => fn(error, result)
   *
   * @return  void
   *
   * @method  WindowsLiveAPI::logout()
   */
  WindowsLiveAPI.prototype.logout = function(callback) {
    callback = callback || function() {};

    var self = this;
    var WL = window.WL || {};

    if ( this.hasSession ) {
      callback(false, false);
    }

    WL.Event.unsubscribe('auth.logout');
    WL.Event.subscribe('auth.logout', function() {
      self._removeRing();

      WL.Event.unsubscribe('auth.logout');
      callback(false, true);
    });

    WL.logout();

    if ( OSjs.VFS.Modules.OneDrive ) {
      OSjs.VFS.Modules.OneDrive.unmount();
    }
  };

  /**
   * Authenticates the user
   */
  WindowsLiveAPI.prototype.login = function(scope, callback) {
    var self = this;
    var WL = window.WL || {};

    if ( this.hasSession ) {
      callback(false, true);
      return;
    }

    WL.login({
      scope: scope,
      redirect_uri: redirectURI
    }).then(function(result) {
      if ( result.status === 'connected' ) {
        callback(false, true);
      } else {
        callback(API._('WLAPI_LOGIN_FAILED'));
      }
    }, function(result) {
        callback(API._('WLAPI_LOGIN_FAILED_FMT', result.error_description));
    });
  };

  /**
   * If the API session was changed
   */
  WindowsLiveAPI.prototype.onSessionChange = function() {
    console.warn('WindowsLiveAPI::onSessionChange()', arguments);
    var WL = window.WL || {};
    var session = WL.getSession();
    if ( session ) {
      this.hasSession = true;
    } else {
      this.hasSession = false;
    }
  };

  /**
   * When user logged in
   */
  WindowsLiveAPI.prototype.onLogin = function() {
    console.warn('WindowsLiveAPI::onLogin()', arguments);
    this.hasSession = true;

    var self = this;
    var ring = API.getServiceNotificationIcon();
    if ( ring ) {
      ring.add('Windows Live API', [{
        title: API._('WLAPI_SIGN_OUT'),
        onClick: function() {
          self.logout();
        }
      }]);
    }
  };

  /**
   * When user logs out
   */
  WindowsLiveAPI.prototype.onLogout = function() {
    console.warn('WindowsLiveAPI::onLogout()', arguments);
    this.hasSession = false;
    this._removeRing();
  };

  /**
   * When API sends a log message
   */
  WindowsLiveAPI.prototype.onLog = function() {
    console.debug('WindowsLiveAPI::onLog()', arguments);
  };

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.Helpers.WindowsLiveAPI = OSjs.Helpers.WindowsLiveAPI || {};

  /**
   * Gets the currently running instance
   *
   * @api OSjs.Helpers.WindowsLiveAPI.getInstance()
   *
   * @return  WindowsLiveAPI       Can also be null
   */
  OSjs.Helpers.WindowsLiveAPI.getInstance = function() {
    return SingletonInstance;
  };

  /**
   * Create an instance of WindowsLiveAPI
   *
   * @param   Object    args      Arguments
   * @param   Function  callback  Callback function => fn(error, instance)
   *
   * @option  args    Array     scope     What scope to load
   *
   * @api OSjs.Helpers.WindowsLiveAPI.createInstance()
   *
   * @return  void
   */
  OSjs.Helpers.WindowsLiveAPI.createInstance = function(args, callback) {
    args = args || {};

    function _run() {
      var scope = args.scope;
      SingletonInstance.load(scope, function() {
        callback(false, SingletonInstance);
      });
    }

    if ( SingletonInstance ) {
      _run();
      return;
    }

    var clientId = null;
    var config = OSjs.Core.getConfig();
    try {
      clientId = config.WindowsLiveAPI.ClientId;
    } catch ( e ) {
      console.warn('getWindowsLiveAPI()', e, e.stack);
    }

    if ( !clientId ) {
      callback(API._('WLAPI_DISABLED'));
      return;
    }

    SingletonInstance = new WindowsLiveAPI(clientId);
    _run();
  };

})(OSjs.Utils, OSjs.API);
<commit_msg>windows-live-api: Properly return error on init fail<commit_after>/*!
 * OS.js - JavaScript Operating System
 *
 * Copyright (c) 2011-2015, Anders Evenrud <andersevenrud@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author  Anders Evenrud <andersevenrud@gmail.com>
 * @licence Simplified BSD License
 */

(function(Utils, API) {
  'use strict';

  var OSjs = window.OSjs = window.OSjs || {};
  //var WL   = window.WL   = window.WL || {};

  OSjs.Helpers = OSjs.Helpers || {};

  var redirectURI = window.location.href.replace(/\/$/, '') + '/vendor/wlOauthReceiver.html';

  /////////////////////////////////////////////////////////////////////////////
  // API
  /////////////////////////////////////////////////////////////////////////////

  var SingletonInstance = null;

  /**
   * The WindowsLiveAPI wrapper class
   *
   * This is a private class and can only be aquired through
   * OSjs.Helpers.WindowsLiveAPI.createInsatance()
   *
   * Generally you want to create an instance of this helper
   * and when successfully created use `window.WL`.
   *
   * @see OSjs.Helpers.WindowsLiveAPI.createInsatance()
   * @api OSjs.Helpers.WindowsLiveAPI.WindowsLiveAPI
   *
   * @link http://msdn.microsoft.com/en-us/library/hh826547.aspx
   * @link http://msdn.microsoft.com/en-us/library/hh826538.aspx
   * @link http://msdn.microsoft.com/en-us/library/hh550837.aspx
   * @link http://msdn.microsoft.com/en-us/library/dn631844.aspx
   * @link http://msdn.microsoft.com/en-us/library/dn631839.aspx
   * @link http://msdn.microsoft.com/en-us/library/hh243643.aspx
   * @link https://account.live.com/developers/applications/index
   *
   * @private
   * @class
   */
  function WindowsLiveAPI(clientId) {
    this.hasSession = false;
    this.clientId = clientId;
    this.loaded = false;
    this.inited = false;
    this.accessToken = null;
    this.lastScope = null;
    this.preloads = [{
      type: 'javascript',
      src: '//js.live.net/v5.0/wl.js'
    }];
  }

  /**
   * Destroy the class
   */
  WindowsLiveAPI.prototype.destroy = function() {
  };

  /**
   * Initializes (preloads) the API
   */
  WindowsLiveAPI.prototype.init = function(callback) {
    callback = callback || function() {};
    var self = this;
    if ( this.loaded ) {
      callback(false, true);
    } else {
      Utils.preload(this.preloads, function(total, failed) {
        if ( !failed.length ) {
          self.loaded = true;
        }
        callback(failed.join('\n'));
      });
    }
  };

  /**
   * Loads the API
   */
  WindowsLiveAPI.prototype.load = function(scope, callback) {
    console.debug('WindowsLiveAPI::load()', scope);

    var self = this;
    var WL = window.WL || {};

    function _login() {
      var lastScope = (self.lastScope || []).sort();
      var currScope = (scope || []).sort();

      if ( self.hasSession && (lastScope.toString() === currScope.toString()) ) {
        callback(false, true);
        return;
      }

      self.login(scope, function(error, response) {
        if ( error ) {
          callback(error);
          return;
        }

        setTimeout(function() {
          callback(false, true);
        }, 10);
      });
    }

    this.init(function(error) {
      if ( error ) {
        callback(error);
        return;
      }

      if ( !window.WL ) {
        callback(API._('WLAPI_LOAD_FAILURE'));
        return;
      }
      WL = window.WL || {};

      if ( self.inited ) {
        _login();
      } else {
        self.inited = true;
        WL.Event.subscribe('auth.login', function() {
          self.onLogin.apply(self, arguments);
        });
        WL.Event.subscribe('auth.logout', function() {
          self.onLogout.apply(self, arguments);
        });
        WL.Event.subscribe('wl.log', function() {
          self.onLog.apply(self, arguments);
        });
        WL.Event.subscribe('auth.sessionChange', function() {
          self.onSessionChange.apply(self, arguments);
        });

        WL.init({
          client_id: self.clientId,
          display: 'popup',
          redirect_uri: redirectURI
        }).then(function(result) {
          console.debug('WindowsLiveAPI::load()', '=>', result);

          if ( result.session ) {
            self.accessToken = result.session.access_token || null;
          }

          if ( result.status === 'connected' ) {
            callback(false, true);
          } else if ( result.status === 'success' ) {
            _login();
          } else {
            callback(API._('WLAPI_INIT_FAILED_FMT', result.status.toString()));
          }
        }, function(result) {
          console.error('WindowsLiveAPI::load()', 'init() error', result);
          callback(result.error_description);
        });
      }
    });
  };

  WindowsLiveAPI.prototype._removeRing = function() {
    var ring = API.getServiceNotificationIcon();
    if ( ring ) {
      ring.remove('Windows Live API');
    }
  };

  /**
   * Sign out of WindowsLiveAPI
   *
   * @param   Function    cb      Callback => fn(error, result)
   *
   * @return  void
   *
   * @method  WindowsLiveAPI::logout()
   */
  WindowsLiveAPI.prototype.logout = function(callback) {
    callback = callback || function() {};

    var self = this;
    var WL = window.WL || {};

    if ( this.hasSession ) {
      callback(false, false);
    }

    WL.Event.unsubscribe('auth.logout');
    WL.Event.subscribe('auth.logout', function() {
      self._removeRing();

      WL.Event.unsubscribe('auth.logout');
      callback(false, true);
    });

    WL.logout();

    if ( OSjs.VFS.Modules.OneDrive ) {
      OSjs.VFS.Modules.OneDrive.unmount();
    }
  };

  /**
   * Authenticates the user
   */
  WindowsLiveAPI.prototype.login = function(scope, callback) {
    var self = this;
    var WL = window.WL || {};

    if ( this.hasSession ) {
      callback(false, true);
      return;
    }

    WL.login({
      scope: scope,
      redirect_uri: redirectURI
    }).then(function(result) {
      if ( result.status === 'connected' ) {
        callback(false, true);
      } else {
        callback(API._('WLAPI_LOGIN_FAILED'));
      }
    }, function(result) {
        callback(API._('WLAPI_LOGIN_FAILED_FMT', result.error_description));
    });
  };

  /**
   * If the API session was changed
   */
  WindowsLiveAPI.prototype.onSessionChange = function() {
    console.warn('WindowsLiveAPI::onSessionChange()', arguments);
    var WL = window.WL || {};
    var session = WL.getSession();
    if ( session ) {
      this.hasSession = true;
    } else {
      this.hasSession = false;
    }
  };

  /**
   * When user logged in
   */
  WindowsLiveAPI.prototype.onLogin = function() {
    console.warn('WindowsLiveAPI::onLogin()', arguments);
    this.hasSession = true;

    var self = this;
    var ring = API.getServiceNotificationIcon();
    if ( ring ) {
      ring.add('Windows Live API', [{
        title: API._('WLAPI_SIGN_OUT'),
        onClick: function() {
          self.logout();
        }
      }]);
    }
  };

  /**
   * When user logs out
   */
  WindowsLiveAPI.prototype.onLogout = function() {
    console.warn('WindowsLiveAPI::onLogout()', arguments);
    this.hasSession = false;
    this._removeRing();
  };

  /**
   * When API sends a log message
   */
  WindowsLiveAPI.prototype.onLog = function() {
    console.debug('WindowsLiveAPI::onLog()', arguments);
  };

  /////////////////////////////////////////////////////////////////////////////
  // EXPORTS
  /////////////////////////////////////////////////////////////////////////////

  OSjs.Helpers.WindowsLiveAPI = OSjs.Helpers.WindowsLiveAPI || {};

  /**
   * Gets the currently running instance
   *
   * @api OSjs.Helpers.WindowsLiveAPI.getInstance()
   *
   * @return  WindowsLiveAPI       Can also be null
   */
  OSjs.Helpers.WindowsLiveAPI.getInstance = function() {
    return SingletonInstance;
  };

  /**
   * Create an instance of WindowsLiveAPI
   *
   * @param   Object    args      Arguments
   * @param   Function  callback  Callback function => fn(error, instance)
   *
   * @option  args    Array     scope     What scope to load
   *
   * @api OSjs.Helpers.WindowsLiveAPI.createInstance()
   *
   * @return  void
   */
  OSjs.Helpers.WindowsLiveAPI.createInstance = function(args, callback) {
    args = args || {};

    function _run() {
      var scope = args.scope;
      SingletonInstance.load(scope, function(error) {
        callback(error ? error : false, SingletonInstance);
      });
    }

    if ( SingletonInstance ) {
      _run();
      return;
    }

    var clientId = null;
    var config = OSjs.Core.getConfig();
    try {
      clientId = config.WindowsLiveAPI.ClientId;
    } catch ( e ) {
      console.warn('getWindowsLiveAPI()', e, e.stack);
    }

    if ( !clientId ) {
      callback(API._('WLAPI_DISABLED'));
      return;
    }

    SingletonInstance = new WindowsLiveAPI(clientId);
    _run();
  };

})(OSjs.Utils, OSjs.API);
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

const program = require('commander');

const pkg = require('./../package.json');
const autoComplete = require('./lib/auto-complete');
const { handleError, GeneralError } = require('./lib/errors');

program
  .version(pkg.version);

program.command('install')
  .description(
    'Installs auto-completion for most of the mite subcommands, options and ' +
    'arguments. Compatible with bash, fish and zsh. ' +
    'No support for windows systems. Also note that it will only work ' +
    'when mite is installed globally.'
  )
  .action(() => {
    autoComplete.install()
      .catch(err => {
        throw new GeneralError('error while installing autocompletion for mite ' + err);
      })
      .catch(handleError);
  });

program.command('uninstall')
  .description('removes the auto-completion for mite')
  .action(() => {
    autoComplete.uninstall()
      .catch(err => {
        throw new GeneralError('error while un-installing autocompletion for mite ' + err);
      })
      .catch(handleError);
  });

program.parse(process.argv);

if (!program.args.length) {
  program.help();
  process.exit();
}
<commit_msg>fix: autocomplete install/uninstall wait for user input #101 (#102)<commit_after>#!/usr/bin/env node
'use strict';

const program = require('commander');

const pkg = require('./../package.json');
const autoComplete = require('./lib/auto-complete');
const { handleError, GeneralError } = require('./lib/errors');

program
  .version(pkg.version);

program.command('install')
  .description(
    'Installs auto-completion for most of the mite subcommands, options and ' +
    'arguments. Compatible with bash, fish and zsh. ' +
    'No support for windows systems. Also note that it will only work ' +
    'when mite is installed globally.'
  )
  .action(() => {
    return autoComplete.install()
      .catch(err => {
        throw new GeneralError('error while installing autocompletion for mite ' + err);
      })
      .catch(handleError);
  });

program.command('uninstall')
  .description('removes the auto-completion for mite')
  .action(() => {
    autoComplete.uninstall()
      .catch(err => {
        throw new GeneralError('error while un-installing autocompletion for mite ' + err);
      })
      .catch(handleError);
  });

program.on('command:*', function (operands) {
  console.error(`error: unknown command '${operands[0]}'`);
  process.exit(1);
});

program.parse(process.argv);
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import firebase, { reference, signIn } from '../firebase';
import { pick, map, extend } from 'lodash';

export default class Input extends Component {
  constructor(){
    super();
    this.state = {
      message: '',
    }
  }

  handleSubmit() {
    this.props.sendMessage(this.state)
    this.setState({ message: '' });
  }

  updateMessage(e) {
    const message = e.target.value
    this.setState({ message: message })
  }

  handleKeyUp(e) {
    if (e.keyCode === 13) {
      this.handleSubmit();
    }
  }

  render() {
    return (

          <input
            onChange={this.updateMessage.bind(this)}
            onKeyUp={this.handleKeyUp.bind(this)}
            value={this.state.message}>
          </input>

          <button onClick={this.handleSubmit.bind(this)}>Submit</button>
          <button>Clear</button>

    )
  }
}
<commit_msg>clear button functionality working. made clearinput function for simplicity<commit_after>import React, { Component } from 'react'
import firebase, { reference, signIn } from '../firebase';
import { pick, map, extend } from 'lodash';

export default class Input extends Component {
  constructor(){
    super();
    this.state = {
      message: '',
    }
  }

  handleSubmit() {
    this.props.sendMessage(this.state)
    this.clearInput();
  }

  updateMessage(e) {
    const message = e.target.value
    this.setState({ message: message })
  }

  handleKeyUp(e) {
    if (e.keyCode === 13) {
      this.handleSubmit();
    }
  }

  clearInput() {
    this.setState({ message: '' })
  }

  render() {
    return (

          <input
            onChange={this.updateMessage.bind(this)}
            onKeyUp={this.handleKeyUp.bind(this)}
            value={this.state.message}>
          </input>

          <button onClick={this.handleSubmit.bind(this)}>Submit</button>
          <button onClick={this.clearInput.bind(this)}>Clear</button>

    )
  }
}
<|endoftext|>


<commit_before>var settings = require('ep_etherpad-lite/node/utils/Settings');
var githubAuth = require('github-auth');
var config = {
    team: 'test',
    organization: settings.users.github.org,
    autologin: true // This automatically redirects you to github to login.
};
var gh = githubAuth(settings.users.github.appId,settings.users.github.appSecret, config);

exports.expressConfigure = function(hook_name, args, cb) {
  var app = args.app;
  app.get('/login', gh.login);
  app.use(gh.authenticate);
  app.use(function(req, res, next) {

    if (req.path.match(/^\/(static|javascripts|pluginfw)/)) {
      // Don't ask for github auth for static paths
      next();

    } else {

      // Use Github Auth
      if (!req.github) return res.send('Please login');
      if (!req.github.authenticated) return res.send('You shall not pass');
      next();

    }

  });
}
<commit_msg>Remove config team.<commit_after>var settings = require('ep_etherpad-lite/node/utils/Settings');
var githubAuth = require('github-auth');
var config = {
    organization: settings.users.github.org,
    autologin: true // This automatically redirects you to github to login.
};
var gh = githubAuth(settings.users.github.appId,settings.users.github.appSecret, config);

exports.expressConfigure = function(hook_name, args, cb) {
  var app = args.app;
  app.get('/login', gh.login);
  app.use(gh.authenticate);
  app.use(function(req, res, next) {

    if (req.path.match(/^\/(static|javascripts|pluginfw)/)) {
      // Don't ask for github auth for static paths
      next();

    } else {

      // Use Github Auth
      if (!req.github) return res.send('Please login');
      if (!req.github.authenticated) return res.send('You shall not pass');
      next();

    }

  });
}
<|endoftext|>


<commit_before>function getWeekNumber(d) {
    // Copy date so don't modify original
    d = new Date(+d);
    d.setHours(0, 0, 0);
    // Set to nearest Thursday: current date + 4 - current day number
    // Make Sunday's day number 7
    d.setDate(d.getDate() + 4 - (d.getDay() || 7));
    // Get first day of year
    var yearStart = new Date(d.getFullYear(), 0, 1);
    // Calculate full weeks to nearest Thursday
    var weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
    // Return array of year and week number
    return weekNo;
}
function GetUrlForWeekNo(nr) {
    return "http://dev3.bbs-os-brinkstr.de/fileadmin/00info/Stundenplan/1Stdplan_nur_Vertretung/" + nr + "/w/w00037.htm";
}

$(document).on("pageshow", "#vertretung", function () {
    "use strict";
    var weekNo = getWeekNumber(new Date());
    $('a[href="#one"]').click().focus();
    $("#vertretungDieseWoche").attr("src", GetUrlForWeekNo(weekNo));
    $("#vertretungNaechsteWoche").attr("src", GetUrlForWeekNo(weekNo + 1));
});
<commit_msg>Vertretungsplan korrigiert<commit_after>function getWeekNumber(d) {
    // Copy date so don't modify original
    d = new Date(+d);
    d.setHours(0, 0, 0);
    // Set to nearest Thursday: current date + 4 - current day number
    // Make Sunday's day number 7
    d.setDate(d.getDate() + 4 - (d.getDay() || 7));
    // Get first day of year
    var yearStart = new Date(d.getFullYear(), 0, 1);
    // Calculate full weeks to nearest Thursday
    var weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
    // Return array of year and week number
    return weekNo;
}
function GetUrlForWeekNo(nr) {
    return "http://dev3.bbs-os-brinkstr.de/fileadmin/00info/Stundenplan/1Stdplan_nur_Vertretung/" + nr + "/w/w00090.htm";
}

$(document).on("pageshow", "#vertretung", function () {
    "use strict";
    var weekNo = getWeekNumber(new Date());
    $('a[href="#one"]').click().focus();
    $("#vertretungDieseWoche").attr("src", GetUrlForWeekNo(weekNo));
    $("#vertretungNaechsteWoche").attr("src", GetUrlForWeekNo(weekNo + 1));
});
<|endoftext|>


<commit_before>'use strict';

var EventEmitter = require('events').EventEmitter,
  util = require('util'),
  _ = require('lodash'),
  logger = require('log4js').getLogger('Sensor');

function template(str, tokens) {
  return str.replace(/\{(\w+)\}/g, function (x, key) {
    return tokens[key];
  });
}

function lower1stLetter(string)
{
  return string.charAt(0).toLowerCase() + string.slice(1);
}

/*
 * Sensor
 */
function Sensor(sensorInfo, options) {
  var props = this.properties = this.constructor.properties;
  var id = sensorInfo.id;

  if (id) {
    this.id = id;
  } else {
    if (props && props.id) {
      this.id = template(props.id, options);
    }
  }
  this.info = sensorInfo;
  this.options = options;

  EventEmitter.call(this);
}

util.inherits(Sensor, EventEmitter);

Sensor.properties = {};

// listen 'data' event once unless interval is provided and not zero.
// listen 'change' event if 'change' is provided
// previous listener stops before enabling new one.
Sensor.prototype.listen = function (intervalOrEvent) {
  var self = this,
    interval, change;

  if (intervalOrEvent !== null && intervalOrEvent !== undefined) {
    if (typeof intervalOrEvent === 'number') {
      interval = intervalOrEvent;
    } else if (intervalOrEvent === 'change') {
      change = true;
    }
  } else {
    interval = this.properties.recommendedInterval;
  }

  if (interval > 0) {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
    this.timer = setInterval(function () {
      self._get();
    }, interval);
    self._get(); // get as soon as possible
  } else if (change) {
    self._enableChange();
  } else {
    self._get();
  }
};

Sensor.prototype.stopListening = function () {
  if (this.timer) {
    clearInterval(this.timer);
    this.timer = null;
  }
};

Sensor.prototype.get = function (cb) {
  this._get();
  if (cb) {
    this.once('data', function (data) {
      return cb(null, data);
    });
  }
};

Sensor.getLogger = function () {
  return logger;
};

Sensor.prototype.close = function () {};

/*
 * Actuator
 */
function Actuator(sensorInfo, options) {
  var props = this.properties = this.constructor.properties;
  var id = sensorInfo.id;

  if (id) {
    this.id = id;
  } else {
    if (props && props.id) {
      this.id = template(props.id, options);
    }
  }
  this.info = sensorInfo;
  this.options = options;

  EventEmitter.call(this);
}
util.inherits(Actuator, EventEmitter);
Actuator.properties = {};

Actuator.prototype.set = function (cmd, options, cb) {
  if (_.contains(this.properties.commands, cmd)) {
    return this[cmd](options, cb);
  } else {
    return cb && cb(new Error('unknown command'));
  }
};

Actuator.prototype.clear = function (cmd, options, cb) {
  this._clear();
};

Actuator.getStatus = function () {
  return undefined;
};

Actuator.getLogger = function () {
  return logger;
};

/*
 * Device
 */
function Device(network, addr, sensorInfos) {
  var self = this;
  this.network = network;
  this.address = addr;
  this.deviceHandle = {};
  this.url = ['sensorjs://', network.protocol, addr].join('/');
  this.sensorUrls = [];
  _.each(sensorInfos, function(sensorInfo) {
    var url = [self.url, sensorInfo.driverName, sensorInfo.id].join('/');
    self.sensorUrls.push(url);
    self.deviceHandle[sensorInfo.id] = sensorInfo.deviceHandle;
  });
  EventEmitter.call(this);
}
util.inherits(Device, EventEmitter);
Device.properties = {};
Device.getStatus = function () {
  return undefined;
};
exports.Sensor = Sensor;
exports.Actuator = Actuator;
exports.Device = Device;
<commit_msg>[driver] add clear method at sensor<commit_after>'use strict';

var EventEmitter = require('events').EventEmitter,
  util = require('util'),
  _ = require('lodash'),
  logger = require('log4js').getLogger('Sensor');

function template(str, tokens) {
  return str.replace(/\{(\w+)\}/g, function (x, key) {
    return tokens[key];
  });
}

function lower1stLetter(string)
{
  return string.charAt(0).toLowerCase() + string.slice(1);
}

/*
 * Sensor
 */
function Sensor(sensorInfo, options) {
  var props = this.properties = this.constructor.properties;
  var id = sensorInfo.id;

  if (id) {
    this.id = id;
  } else {
    if (props && props.id) {
      this.id = template(props.id, options);
    }
  }
  this.info = sensorInfo;
  this.options = options;

  EventEmitter.call(this);
}

util.inherits(Sensor, EventEmitter);

Sensor.properties = {};

// listen 'data' event once unless interval is provided and not zero.
// listen 'change' event if 'change' is provided
// previous listener stops before enabling new one.
Sensor.prototype.listen = function (intervalOrEvent) {
  var self = this,
    interval, change;

  if (intervalOrEvent !== null && intervalOrEvent !== undefined) {
    if (typeof intervalOrEvent === 'number') {
      interval = intervalOrEvent;
    } else if (intervalOrEvent === 'change') {
      change = true;
    }
  } else {
    interval = this.properties.recommendedInterval;
  }

  if (interval > 0) {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
    this.timer = setInterval(function () {
      self._get();
    }, interval);
    self._get(); // get as soon as possible
  } else if (change) {
    self._enableChange();
  } else {
    self._get();
  }
};

Sensor.prototype.stopListening = function () {
  if (this.timer) {
    clearInterval(this.timer);
    this.timer = null;
  }
};

Sensor.prototype.get = function (cb) {
  this._get();
  if (cb) {
    this.once('data', function (data) {
      return cb(null, data);
    });
  }
};

Sensor.prototype.clear = function () {
  this.stopListening();
}

Sensor.getLogger = function () {
  return logger;
};

Sensor.prototype.close = function () {};

/*
 * Actuator
 */
function Actuator(sensorInfo, options) {
  var props = this.properties = this.constructor.properties;
  var id = sensorInfo.id;

  if (id) {
    this.id = id;
  } else {
    if (props && props.id) {
      this.id = template(props.id, options);
    }
  }
  this.info = sensorInfo;
  this.options = options;

  EventEmitter.call(this);
}
util.inherits(Actuator, EventEmitter);
Actuator.properties = {};

Actuator.prototype.set = function (cmd, options, cb) {
  if (_.contains(this.properties.commands, cmd)) {
    return this[cmd](options, cb);
  } else {
    return cb && cb(new Error('unknown command'));
  }
};

Actuator.prototype.clear = function (cmd, options, cb) {
  this._clear();
};

Actuator.getStatus = function () {
  return undefined;
};

Actuator.getLogger = function () {
  return logger;
};

/*
 * Device
 */
function Device(network, addr, sensorInfos) {
  var self = this;
  this.network = network;
  this.address = addr;
  this.deviceHandle = {};
  this.url = ['sensorjs://', network.protocol, addr].join('/');
  this.sensorUrls = [];
  _.each(sensorInfos, function(sensorInfo) {
    var url = [self.url, sensorInfo.driverName, sensorInfo.id].join('/');
    self.sensorUrls.push(url);
    self.deviceHandle[sensorInfo.id] = sensorInfo.deviceHandle;
  });
  EventEmitter.call(this);
}
util.inherits(Device, EventEmitter);
Device.properties = {};
Device.getStatus = function () {
  return undefined;
};
exports.Sensor = Sensor;
exports.Actuator = Actuator;
exports.Device = Device;
<|endoftext|>


<commit_before>BetAnalysis.DigitInfo = function() {
    this.chart_config = {
        chart: {
                renderTo:'last_digit_histo',
                defaultSeriesType:'column',
                backgroundColor:'#eee',
                borderWidth:1,
                borderColor:'#ccc',
                plotBackgroundColor:'#fff',
                plotBorderWidth:1,
                plotBorderColor:'#ccc',
                height:225 // This is "unresponsive", but so is leaving it empty where it goes to 400px.
        },
        title:{text:''},
        credits:{enabled:false},
        exporting:{enabled:false},
        legend:{
            enabled:false
        },
        tooltip:{
            borderWidth:1,
            formatter:function() {
                var that = this;
                var total = $("select[name='tick_count']").val();
                var percentage = that.y/total*100;
                return 'Digit: '+ that.x +'
'+
                'Percentage: '+ percentage.toFixed(2) + " %";
            }
        },
        plotOptions:{
            column:{
                shadow:false,
                borderWidth:0.5,
                borderColor:'#666',
                pointPadding:0,
                groupPadding:0,
                color: 'rgba(204,204,204,.85)'
            },
        },
        xAxis:{
            categories: ['0','1','2','3','4','5','6','7','8','9'],
            lineWidth:0,
            lineColor:'#999',
            tickLength:10,
            tickColor:'#ccc',
        },
        yAxis:{
            title:{text:''},
            maxPadding:0,
            gridLineColor:'#e9e9e9',
            tickWidth:1,
            tickLength:3,
            tickColor:'#ccc',
            lineColor:'#ccc',
            endOnTick:true,
            labels: {
                formatter: function() {
                    var total = $("select[name='tick_count']").val();
                    var percentage = parseInt(this.value/total*100);
                    return percentage + " %";
                },
            },
        },
    };

    this.spots = [];
};

BetAnalysis.DigitInfo.prototype = {
    render: function(tab) {
        this.id = tab.id;
        var that = this;
        $.get(this.url(tab), function (texts) {
            tab.content.html(texts);
        }).done(function () {
            that.on_latest();
            that.show_chart(BetForm.attributes.underlying());
        });
    },
    url: function() {
        var existing_link = $('#tab_last_digit').find('a');
        var url = existing_link.attr('href').replace(/underlying=\w+/,'underlying='+ BetForm.attributes.underlying());
        existing_link.attr('href', url);
        return url;
    },
    on_latest: function() {
        var that = this;
        var tab = $('#' + this.id + "-content");
        var form = tab.find('form:first');
        form.on('submit', function(event) {
            event.preventDefault();
            return false;
        }).addClass('unbind_later');

        var get_latest = function() {
            var action = form.attr('action');
            $.ajax({
                url     : action,
                async   : true,
                data    : form.serialize(),
                success : function (texts) {
                    that.chart.destroy();
                    tab.html(texts);
                    that.on_latest();
                    var underlying = $('[name=underlying]', form).val();
                    that.show_chart(underlying);
                }
            });
        };
        $('[name=underlying]', form).on('change',  get_latest ).addClass('unbind_later');
        $('[name=tick_count]', form).on('change',  get_latest ).addClass('unbind_later');
    },
    show_chart: function(underlying) {
        this.chart_config.xAxis.title = {
            text: $('#last_digit_title').html(),
        };
        this.spots = $.parseJSON($('#last_digit_data').html());
        this.chart = new Highcharts.Chart(this.chart_config);
        this.chart.addSeries({name : underlying, data: []});

        this.update();
    },
    update: function(symbol, latest_spot) {
        if(typeof this.chart === "undefined") {
            return;
        }

        var series = this.chart.series[0]; // Where we put the final data.

        if (series.name != symbol) {
            latest_spot = undefined; // This simplifies the logic a bit later.
        }

        if (typeof latest_spot !== "undefined") { // This is a bit later. :D
            this.spots.unshift(latest_spot.slice(-1)); // Only last digit matters
            this.spots.pop();
        }

        // Always recompute and draw, even if theres no new data.
        // This is especially useful on first reuqest, but maybe in other ways.
        var filtered_spots = [];
        var digit = 10,
            filterFunc = function (el) { return el == digit; };
        while(digit--) {
            filtered_spots[digit] = this.spots.filter(filterFunc).length;
        }
        return series.setData(filtered_spots);
    },
    show_tab: function() {
        var tab_last_digit = $('#tab_last_digit');
        MenuContent.show_tab(tab_last_digit);
        var saved_anaysis_tab = SessionStore.get('bet_page.selected_analysis_tab');
        if(saved_anaysis_tab == 'tab_last_digit') {
            MenuContent.trigger({
                'tab_id': saved_anaysis_tab
            });
        }
    },
    hide_tab: function() {
        var tab_last_digit = $('#tab_last_digit');
        MenuContent.hide_tab(tab_last_digit);
        if(typeof this.chart !== "undefined") {
            this.chart.destroy();
        }
        this.chart = undefined;
        this.spots = [];
    }
};

BetAnalysis.tab_last_digit = new BetAnalysis.DigitInfo();
<commit_msg>enhancement on digit_info appearance<commit_after>BetAnalysis.DigitInfo = function() {
    this.chart_config = {
        chart: {
                renderTo:'last_digit_histo',
                defaultSeriesType:'column',
                backgroundColor:'#eee',
                borderWidth:1,
                borderColor:'#ccc',
                plotBackgroundColor:'#fff',
                plotBorderWidth:1,
                plotBorderColor:'#ccc',
                height:225 // This is "unresponsive", but so is leaving it empty where it goes to 400px.
        },
        title:{text:''},
        credits:{enabled:false},
        exporting:{enabled:false},
        legend:{
            enabled:false
        },
        tooltip:{
            borderWidth:1,
            formatter:function() {
                var that = this;
                var total = $("select[name='tick_count']").val();
                var percentage = that.y/total*100;
                return 'Digit: '+ that.x +'
'+
                'Percentage: '+ percentage.toFixed(1) + " %";
            }
        },
        plotOptions:{
            column:{
                shadow:false,
                borderWidth:0.5,
                borderColor:'#666',
                pointPadding:0,
                groupPadding:0,
                color: '#e1f0fb',
            },
            series: {
                dataLabels: {
                    enabled: true,
                    formatter: function() {
                        var total = $("select[name='tick_count']").val();
                        var percentage = this.point.y/total*100;
                        return percentage.toFixed(2) + ' %';
                    },
                },
            },
        },
        xAxis:{
            categories: ['0','1','2','3','4','5','6','7','8','9'],
            lineWidth:0,
            lineColor:'#999',
            tickLength:10,
            tickColor:'#ccc',
        },
        yAxis:{
            title:{text:''},
            maxPadding:0,
            gridLineColor:'#e9e9e9',
            tickWidth:1,
            tickLength:3,
            tickColor:'#ccc',
            lineColor:'#ccc',
            endOnTick:true,
            labels: {
                enabled: false,
                formatter: function() {
                    var total = $("select[name='tick_count']").val();
                    var percentage = parseInt(this.value/total*100);
                    return percentage + " %";
                },
            },
        },
    };

    this.spots = [];
};

BetAnalysis.DigitInfo.prototype = {
    render: function(tab) {
        this.id = tab.id;
        var that = this;
        $.get(this.url(tab), function (texts) {
            tab.content.html(texts);
        }).done(function () {
            that.on_latest();
            that.show_chart(BetForm.attributes.underlying());
        });
    },
    url: function() {
        var existing_link = $('#tab_last_digit').find('a');
        var url = existing_link.attr('href').replace(/underlying=\w+/,'underlying='+ BetForm.attributes.underlying());
        existing_link.attr('href', url);
        return url;
    },
    on_latest: function() {
        var that = this;
        var tab = $('#' + this.id + "-content");
        var form = tab.find('form:first');
        form.on('submit', function(event) {
            event.preventDefault();
            return false;
        }).addClass('unbind_later');

        var get_latest = function() {
            var action = form.attr('action');
            $.ajax({
                url     : action,
                async   : true,
                data    : form.serialize(),
                success : function (texts) {
                    that.chart.destroy();
                    tab.html(texts);
                    that.on_latest();
                    var underlying = $('[name=underlying]', form).val();
                    that.show_chart(underlying);
                }
            });
        };
        $('[name=underlying]', form).on('change',  get_latest ).addClass('unbind_later');
        $('[name=tick_count]', form).on('change',  get_latest ).addClass('unbind_later');
    },
    show_chart: function(underlying) {
        this.chart_config.xAxis.title = {
            text: $('#last_digit_title').html(),
        };
        this.spots = $.parseJSON($('#last_digit_data').html());
        this.chart = new Highcharts.Chart(this.chart_config);
        this.chart.addSeries({name : underlying, data: []});

        this.update();
    },
    update: function(symbol, latest_spot) {
        if(typeof this.chart === "undefined") {
            return;
        }

        var series = this.chart.series[0]; // Where we put the final data.

        if (series.name != symbol) {
            latest_spot = undefined; // This simplifies the logic a bit later.
        }

        if (typeof latest_spot !== "undefined") { // This is a bit later. :D
            this.spots.unshift(latest_spot.slice(-1)); // Only last digit matters
            this.spots.pop();
        }

        // Always recompute and draw, even if theres no new data.
        // This is especially useful on first reuqest, but maybe in other ways.
        var filtered_spots = [];
        var digit = 10,
            filterFunc = function (el) { return el == digit; };
        var min_max_counter = [];
        while(digit--) {
            var val = this.spots.filter(filterFunc).length;
            filtered_spots[digit] = val;
            if (typeof min_max_counter[val] === 'undefined') {
                min_max_counter[val] = 0;
            }
            min_max_counter[val]++;
        }
        var min = Math.min.apply(null, filtered_spots);
        var max = Math.max.apply(null, filtered_spots);
        var min_index = filtered_spots.indexOf(min);
        var max_index = filtered_spots.indexOf(max);
        // changing color
        if (min_max_counter[min] === 1) {
            filtered_spots[min_index] = {y: min, color: '#CC0000'};
        }

        if (min_max_counter[max] === 1) {
            filtered_spots[max_index] = {y: max, color: '#2E8836'};
        }
        return series.setData(filtered_spots);
    },
    show_tab: function() {
        var tab_last_digit = $('#tab_last_digit');
        MenuContent.show_tab(tab_last_digit);
        var saved_anaysis_tab = SessionStore.get('bet_page.selected_analysis_tab');
        if(saved_anaysis_tab == 'tab_last_digit') {
            MenuContent.trigger({
                'tab_id': saved_anaysis_tab
            });
        }
    },
    hide_tab: function() {
        var tab_last_digit = $('#tab_last_digit');
        MenuContent.hide_tab(tab_last_digit);
        if(typeof this.chart !== "undefined") {
            this.chart.destroy();
        }
        this.chart = undefined;
        this.spots = [];
    }
};

BetAnalysis.tab_last_digit = new BetAnalysis.DigitInfo();
<|endoftext|>


<commit_before>var OpenLayersPlusLegend = function(opts) {
    var self = this;
    this.map = $(opts[0]).data('map');

    this.setLegend = function(layer) {
        // The layer param may vary based on the context from which we are called.
        layer = layer.object ? layer.object : layer;
        if ('legend' in layer) {
            var legend_content = layer.legend || 'your mother';
            var legends = $('div.openlayers-legends', self.map.div);
            if (layer.visibility && !('legendDiv' in layer)) {
                layer.legendDiv = $("

").append(legend_content);
                legends.append(layer.legendDiv);
            }
            else if (!layer.visibility && ('legendDiv' in layer)) {
                layer.legendDiv.remove();
                delete layer.legendDiv;
            }
        }
    };

    for (i in this.map.layers) {
        var layer = this.map.layers[i];
        if (!$('div.openlayers-legends', self.map.div).size()) {
            $(self.map.div).append("

");
        }
        layer.events.register('visibilitychanged', layer, self.setLegend);
        self.setLegend(layer);
    }
};
<commit_msg>Allow legend behavior to be called without arguments.<commit_after>var OpenLayersPlusLegend = function(opts) {
    if (opts == null) {
        return;
    }
    var self = this;
    this.map = $(opts).data('map');

    this.setLegend = function(layer) {
        // The layer param may vary based on the context from which we are called.
        layer = layer.object ? layer.object : layer;
        if ('legend' in layer) {
            var legend_content = layer.legend || 'your mother';
            var legends = $('div.openlayers-legends', self.map.div);
            if (layer.visibility && !('legendDiv' in layer)) {
                layer.legendDiv = $("

").append(legend_content);
                legends.append(layer.legendDiv);
            }
            else if (!layer.visibility && ('legendDiv' in layer)) {
                layer.legendDiv.remove();
                delete layer.legendDiv;
            }
        }
    };

    for (i in this.map.layers) {
        var layer = this.map.layers[i];
        if (!$('div.openlayers-legends', self.map.div).size()) {
            $(self.map.div).append("

");
        }
        layer.events.register('visibilitychanged', layer, self.setLegend);
        self.setLegend(layer);
    }
};
<|endoftext|>


<commit_before>import _ from 'lodash';
import moment from 'moment-timezone';

class PostListCtrl {
    constructor($rootScope, Posts, $stateParams, $timeout, PostNotifications, DateTime, Hosts, Changelog) {
        this.Posts = Posts;
        this.DateTime = DateTime;
        this.PostNotifications = PostNotifications;
        this.Hosts = Hosts;
        this.Changelog = Changelog;
        this.moment = moment;

        this.showFilters = false;

        this.filters = {
            search: '',
            region: post => !_.contains(Posts.disabledRegions, post.region.toLowerCase()),
            // Check if all of its gamemodes are enabled or not
            gamemode: post => !_.any(post.gamemodes, gamemode => {
                return _.contains(Posts.disabledGamemodes, gamemode.toLowerCase());
            }),
            teamType: post => !_.contains(Posts.disabledTeamTypes, post.teams.toLowerCase()),
            favourited: post => Posts.showFavouritedHostsOnly ? Hosts.isFavouriteHost(post.author) : true
        };

        this.filteredPosts = [];

        // Handle 'anchor' links to specific posts
        this.scrolled = false;
        $rootScope.$on('postsUpdated', () => {
            $timeout(() => {
                if (this.scrolled) {
                    return;
                }

                if ($stateParams.post !== null) {
                    let element = document.getElementById('post-' + $stateParams.post);
                    if (element !== null) {
                        element.scrollIntoView();
                        element.click();
                    }
                }

                this.scrolled = true;
            });
        });
    }

    postClasses(post) {
        let classes = ['match-post'];

        if (this.Hosts.isFavouriteHost(post.author)) {
            classes.push('favourite-host');
        }

        return classes;
    }

    buttonEnabledClass(enabled) {
        return enabled ? 'btn-success' : 'btn-danger';
    }
}
PostListCtrl.$inject = ['$rootScope', 'Posts', '$stateParams', '$timeout', 'PostNotifications', 'DateTime', 'Hosts',
    'Changelog', 'Subreddits', 'Templates'];

let controllerName = 'PostListCtrl';

let state = {
    name: 'app.list',
    url: '/list?post',
    template: require('./template.html'),
    controller: `${controllerName} as postList`,
    resolve: {
        savedData: ['$q', 'Hosts', 'Posts', 'Subreddits', 'PostNotifications', '$q', function($q, ...others) {
            return $q.all(others.map(o => o.initialised));
        }]
    }
};

export { PostListCtrl as controller, controllerName, state };

export default state;
<commit_msg>feat(PostList): add support for blocked hosts filtering<commit_after>import _ from 'lodash';
import moment from 'moment-timezone';

class PostListCtrl {
    constructor($rootScope, Posts, $stateParams, $timeout, PostNotifications, DateTime, Hosts, Changelog) {
        this.Posts = Posts;
        this.DateTime = DateTime;
        this.PostNotifications = PostNotifications;
        this.Hosts = Hosts;
        this.Changelog = Changelog;
        this.moment = moment;

        this.showFilters = false;

        this.filters = {
            search: '',
            region: post => !_.contains(Posts.disabledRegions, post.region.toLowerCase()),
            // Check if all of its gamemodes are enabled or not
            gamemode: post => !_.any(post.gamemodes, gamemode => {
                return _.contains(Posts.disabledGamemodes, gamemode.toLowerCase());
            }),
            teamType: post => !_.contains(Posts.disabledTeamTypes, post.teams.toLowerCase()),
            favourited: post => Posts.showFavouritedHostsOnly ? Hosts.isFavouriteHost(post.author) : true,
            blocked: post => Posts.showBlockedHosts ? true : !Hosts.isBlockedHost(post.author)
        };

        this.filteredPosts = [];

        // Handle 'anchor' links to specific posts
        this.scrolled = false;
        $rootScope.$on('postsUpdated', () => {
            $timeout(() => {
                if (this.scrolled) {
                    return;
                }

                if ($stateParams.post !== null) {
                    let element = document.getElementById('post-' + $stateParams.post);
                    if (element !== null) {
                        element.scrollIntoView();
                        element.click();
                    }
                }

                this.scrolled = true;
            });
        });
    }

    postClasses(post) {
        let classes = ['match-post'];

        if (this.Hosts.isFavouriteHost(post.author)) {
            classes.push('favourite-host');
        }

        return classes;
    }

    buttonEnabledClass(enabled) {
        return enabled ? 'btn-success' : 'btn-danger';
    }
}
PostListCtrl.$inject = ['$rootScope', 'Posts', '$stateParams', '$timeout', 'PostNotifications', 'DateTime', 'Hosts',
    'Changelog', 'Subreddits', 'Templates'];

let controllerName = 'PostListCtrl';

let state = {
    name: 'app.list',
    url: '/list?post',
    template: require('./template.html'),
    controller: `${controllerName} as postList`,
    resolve: {
        savedData: ['$q', 'Hosts', 'Posts', 'Subreddits', 'PostNotifications', '$q', function($q, ...others) {
            return $q.all(others.map(o => o.initialised));
        }]
    }
};

export { PostListCtrl as controller, controllerName, state };

export default state;
<|endoftext|>


<commit_before>module.exports = function (grunt) {
    grunt.initConfig({
        "pkg": grunt.file.readJSON("package.json"),
        "meta": {
            "paths": {
                "source": "Source",
                "dist": "Distribution"
            }
        },
        "tslint": {
            "options": {
                "configuration": grunt.file.readJSON("tslint.json")
            },
            "files": {
                "src": ["<%= meta.paths.source %>/<%= pkg.name %>.ts"]
            }
        },
        "typescript": {
            "base": {
                "src": "<%= meta.paths.source %>/<%= pkg.name %>.ts",
                "dest": "<%= meta.paths.source %>/<%= pkg.name %>.js"
            }
        },
        "clean": ["<%= meta.paths.dist %>"],
        "copy": {
            "default": {
                "files": [{
                    "src": "<%= meta.paths.source %>/<%= pkg.name %>.js",
                    "dest": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.js"
                }, {
                    "src": "<%= meta.paths.source %>/<%= pkg.name %>.ts",
                    "dest": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.ts"
                }, {
                    "src": "<%= meta.paths.source %>/References/*.ts",
                    "dest": "<%= meta.paths.dist %>/",
                    "expand": true,
                    "flatten": true
                }, {
                    "src": "README.md",
                    "dest": "<%= meta.paths.dist %>/"
                }, {
                    "src": "README.md",
                    "dest": "<%= meta.paths.source %>/"
                }, {
                    "src": "LICENSE.txt",
                    "dest": "<%= meta.paths.dist %>/"
                }, {
                    "src": "LICENSE.txt",
                    "dest": "<%= meta.paths.source %>/"
                }]
            }
        },
        "uglify": {
            "options": {
                "compress": true,
                "sourceMap": true
            },
            "dist": {
                "files": {
                    "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.min.js": ["<%= meta.paths.source %>/<%= pkg.name %>.js"],
                }
            }
        },
        "preprocess": {
            "dist": {
                "src": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.ts",
                "dest": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.ts"
            }
        },
        "mocha_phantomjs": {
            "all": ["Tests/*.html"]
        }
    });

    grunt.loadNpmTasks("grunt-contrib-clean");
    grunt.loadNpmTasks("grunt-contrib-copy");
    grunt.loadNpmTasks("grunt-contrib-uglify");
    grunt.loadNpmTasks("grunt-mocha-phantomjs");
    grunt.loadNpmTasks("grunt-preprocess");
    grunt.loadNpmTasks("grunt-tslint");
    grunt.loadNpmTasks("grunt-typescript");
    grunt.registerTask("default", [
        "tslint", "typescript", "clean", "copy", "uglify", "preprocess", "mocha_phantomjs"
    ]);
};<commit_msg>Updated Gruntfile for better distribution<commit_after>module.exports = function (grunt) {
    grunt.initConfig({
        "pkg": grunt.file.readJSON("package.json"),
        "meta": {
            "paths": {
                "source": "Source",
                "dist": "Distribution"
            }
        },
        "tslint": {
            "options": {
                "configuration": grunt.file.readJSON("tslint.json")
            },
            "files": {
                "src": ["<%= meta.paths.source %>/<%= pkg.name %>.ts"]
            }
        },
        "typescript": {
            "base": {
                "src": "<%= meta.paths.source %>/<%= pkg.name %>.ts"
            }
        },
        "clean": ["<%= meta.paths.dist %>"],
        "copy": {
            "default": {
                "files": [{
                    "src": "<%= meta.paths.source %>/<%= pkg.name %>.js",
                    "dest": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.js"
                }, {
                    "src": "<%= meta.paths.source %>/<%= pkg.name %>.ts",
                    "dest": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.ts"
                }, {
                    "src": "<%= meta.paths.source %>/<%= pkg.name %>.d.ts",
                    "dest": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.d.ts"
                }, {
                    "src": "<%= meta.paths.source %>/References/*.ts",
                    "dest": "<%= meta.paths.dist %>/",
                    "expand": true,
                    "flatten": true
                }, {
                    "src": "README.md",
                    "dest": "<%= meta.paths.dist %>/"
                }, {
                    "src": "README.md",
                    "dest": "<%= meta.paths.source %>/"
                }, {
                    "src": "LICENSE.txt",
                    "dest": "<%= meta.paths.dist %>/"
                }, {
                    "src": "LICENSE.txt",
                    "dest": "<%= meta.paths.source %>/"
                }]
            }
        },
        "uglify": {
            "options": {
                "compress": true,
                "sourceMap": true
            },
            "dist": {
                "files": {
                    "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.min.js": ["<%= meta.paths.source %>/<%= pkg.name %>.js"],
                }
            }
        },
        "preprocess": {
            "dist": {
                "src": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.ts",
                "dest": "<%= meta.paths.dist %>/<%= pkg.name %>-<%= pkg.version %>.ts"
            }
        },
        "mocha_phantomjs": {
            "all": ["Tests/*.html"]
        }
    });

    grunt.loadNpmTasks("grunt-contrib-clean");
    grunt.loadNpmTasks("grunt-contrib-copy");
    grunt.loadNpmTasks("grunt-contrib-uglify");
    grunt.loadNpmTasks("grunt-mocha-phantomjs");
    grunt.loadNpmTasks("grunt-preprocess");
    grunt.loadNpmTasks("grunt-tslint");
    grunt.loadNpmTasks("grunt-typescript");
    grunt.registerTask("default", [
        "tslint", "typescript", "clean", "copy", "uglify", "preprocess", "mocha_phantomjs"
    ]);
};<|endoftext|>


<commit_before>var userSchema = new mongoose.Schema({
         active: Boolean,
         email: { type: String, trim: true, lowercase: true },
         firstName: { type: String, trim: true },
         lastName: { type: String, trim: true },
         sp_api_key_id: { type: String, trim: true },
         sp_api_key_secret: { type: String, trim: true },
         subs: { type: [mongoose.Schema.Types.ObjectId], default: [] },
         created: { type: Date, default: Date.now },
         lastLogin: { type: Date, default: Date.now },
     },
     { collection: 'user' }
);

userSchema.index({email : 1}, {unique:true});
userSchema.index({sp_api_key_id : 1}, {unique:true});
<commit_msg>create user model from schema<commit_after>var userSchema = new mongoose.Schema({
         active: Boolean,
         email: { type: String, trim: true, lowercase: true },
         firstName: { type: String, trim: true },
         lastName: { type: String, trim: true },
         sp_api_key_id: { type: String, trim: true },
         sp_api_key_secret: { type: String, trim: true },
         subs: { type: [mongoose.Schema.Types.ObjectId], default: [] },
         created: { type: Date, default: Date.now },
         lastLogin: { type: Date, default: Date.now },
     },
     { collection: 'user' }
);

userSchema.index({email : 1}, {unique:true});
userSchema.index({sp_api_key_id : 1}, {unique:true});

var UserModel = mongoose.model( 'User', userSchema );

<|endoftext|>


<commit_before>import { safeGetObjectProperty, $ } from '../../utils'

import moment from 'moment'
import { parse as parseQueryString } from 'query-string'
/*****
* Originally I was using the url search params to check if the page was set to do instant search by
* checking if there were search query params (e.g. search?q=skyrim) in the url, but unfortunately it's possible
* to have search params present and still be in instant search; the url would look something
* like this (logged out): https://www.google.co.uk/search?q=skyrim+walkthrough+ps3#q=skyrim+walkthrough+pdf
* I cant seem to find anything in the cookies or local/session storage to indicate that it's instant search,
* so gonna check the html on the page. (we can still use search params to get the search query quickly
* though)
* Note: query-string automatically removes the ? or # at the start.
*/

let isInstantSearch = false

function checkIfInstantSearch(){
  if($('#tsf>input[value="psy-ab"][name="sclient"]')){
    isInstantSearch = true
  }
  return isInstantSearch
}

function getPageHash(){
  return parseQueryString(window.location.hash)
}

function getPageQuery(){
  return parseQueryString(window.location.search)
}

function getSearchQueryFromUrl(){
  if(isInstantSearch){
    return getPageHash().q
  }
  return getPageQuery().q
}

function parseDateFilter(dateFilter){
  const dateFilterRange = {
    startDate: null,
    endDate: null,
  }
  const startDateShortcuts = {
    h: 'hour',
    d: 'day',
    w: 'week',
    m: 'month',
    y: 'year'
  }
  /*****
  * 'qdr:' is one of the date shortcuts that's available (i.e. not a custom range)
  */
  if(dateFilter.startsWith('qdr:')){
    dateFilterRange.endDate = moment().valueOf()
    const startDateShortcutText = startDateShortcuts[dateFilter.split('qdr:')[1]]
    dateFilterRange.startDate = moment().subtract(1, startDateShortcutText).valueOf()
  }
  /*****
  * 'cdr:' is a custom date range
  */
  if(dateFilter.startsWith('cdr:')){
    /*****
    * cdr example: cdr:1,cd_min:30/10/2016,cd_max:23/11/2016
    * Note: google fixes it if you set an end date before the start date, or it reverts to the previous legit date
    * range - it does this by reloading the page (as a non-instant search).
    */
    const cdrStartDate = dateFilter.slice(dateFilter.indexOf('cd_min:') + 7, dateFilter.lastIndexOf(','))
    const cdrEndDate = dateFilter.slice(dateFilter.indexOf('cd_max:') + 7)
    dateFilterRange.startDate = moment(cdrStartDate, 'DD-MM-YYYY').startOf('day').valueOf()
    dateFilterRange.endDate = moment(cdrEndDate, 'DD-MM-YYYY').endOf('day').valueOf()
  }
  return dateFilterRange
}

function getDateFilterFromUrl(){
  let dateFilterParams = null
  if(isInstantSearch){
    dateFilterParams = getPageHash().tbs
  }
  else{
    dateFilterParams = getPageQuery().tbs
  }
  if(!dateFilterParams || !dateFilterParams.length){
    return
  }
  return parseDateFilter(dateFilterParams)
}

function checkIfMutationOccuredOnTargetElement(mutations, targetId){
  return mutations.find(({target: {id}}) => id === targetId)
}

function getAddedNodesForTargetElement(mutations, targetId){
  return safeGetObjectProperty(checkIfMutationOccuredOnTargetElement(mutations, targetId), 'addedNodes')
}

function getRemovedNodesForTargetElement(mutations, targetId){
  return safeGetObjectProperty(checkIfMutationOccuredOnTargetElement(mutations, targetId), 'removedNodes')
}

function findElementInNodeList(searchType, searchData, nodeList){
  if(!nodeList){
    return
  }
  if(searchType === 'nodeName'){
    return Array.from(nodeList).find(elem => elem.nodeName.toLowerCase() === searchData)
  }
  if(searchType === 'id'){
    return Array.from(nodeList).find(elem => elem.id === searchData)
  }
}
/*****
* We check the url params for the 'tbm' key as that indicates that it's not a general search.
*
* Notes:
*   * This is only for non-instant, as we cant rely on the tbm url param not being there on instant.
*   * We dont have to bother checking Flights search or Maps search, as they both are missing the '#lst-ib'
*   search input element, which we check for at the start of the googleSearch_ContentScript init().
*   * The document body contains the class 'hp' when it is on the search page (for both normal and instant search).
*   We have a css rule in our stylesheet to display: none for the MS results box when the page body has a class of
*   'hp', but we should check here for that class because this can prevent the MS results box from being created
*   and inserted, as there is no need for it to be inserted on the search page when it's not instant search.
*/
function generalResultsPageIsDisplayedForNonInstantSearch(){
  return !document.body.classList.contains('hp') && !getPageHash().tbm && !getPageQuery().tbm
}

export {
  getSearchQueryFromUrl,
  getDateFilterFromUrl,
  parseDateFilter,
  checkIfInstantSearch,
  checkIfMutationOccuredOnTargetElement,
  getAddedNodesForTargetElement,
  getRemovedNodesForTargetElement,
  findElementInNodeList,
  generalResultsPageIsDisplayedForNonInstantSearch,
}
<commit_msg>See description<commit_after>import { safeGetObjectProperty, $ } from '../../utils'

import moment from 'moment'
import { parse as parseQueryString } from 'query-string'
/*****
* Originally I was using the url search params to check if the page was set to do instant search by
* checking if there were search query params (e.g. search?q=skyrim) in the url, but unfortunately it's possible
* to have search params present and still be in instant search; the url would look something
* like this (logged out): https://www.google.co.uk/search?q=skyrim+walkthrough+ps3#q=skyrim+walkthrough+pdf
* I cant seem to find anything in the cookies or local/session storage to indicate that it's instant search,
* so gonna check the html on the page. (we can still use search params to get the search query quickly
* though)
* Note: query-string automatically removes the ? or # at the start.
*/

let isInstantSearch = false

function checkIfInstantSearch(){
  if($('#tsf>input[value="psy-ab"][name="sclient"]')){
    isInstantSearch = true
  }
  return isInstantSearch
}

function getUrlHashParams(){
  return parseQueryString(window.location.hash)
}

function getUrlQueryParams(){
  return parseQueryString(window.location.search)
}

function getSearchQueryFromUrl(){
  const urlHashParams = getUrlHashParams().q
  const urlQueryParams = getUrlQueryParams().q
  /*****
  * Normally instant search uses hash params for the search, but on occasion, it will use the query
  * params (?q=foo) instead, so return that if it's there and there is not a hash search param.
  */
  if(isInstantSearch){
    if(urlHashParams){
      return urlHashParams
    }
    if(urlQueryParams){
      return urlQueryParams
    }
  }
  return urlQueryParams
}

function parseDateFilter(dateFilter){
  const dateFilterRange = {
    startDate: null,
    endDate: null,
  }
  const startDateShortcuts = {
    h: 'hour',
    d: 'day',
    w: 'week',
    m: 'month',
    y: 'year'
  }
  /*****
  * 'qdr:' is one of the date shortcuts that's available (i.e. not a custom range)
  */
  if(dateFilter.startsWith('qdr:')){
    dateFilterRange.endDate = moment().valueOf()
    const startDateShortcutText = startDateShortcuts[dateFilter.split('qdr:')[1]]
    dateFilterRange.startDate = moment().subtract(1, startDateShortcutText).valueOf()
  }
  /*****
  * 'cdr:' is a custom date range
  */
  if(dateFilter.startsWith('cdr:')){
    /*****
    * cdr example: cdr:1,cd_min:30/10/2016,cd_max:23/11/2016
    * Note: google fixes it if you set an end date before the start date, or it reverts to the previous legit date
    * range - it does this by reloading the page (as a non-instant search).
    */
    const cdrStartDate = dateFilter.slice(dateFilter.indexOf('cd_min:') + 7, dateFilter.lastIndexOf(','))
    const cdrEndDate = dateFilter.slice(dateFilter.indexOf('cd_max:') + 7)
    dateFilterRange.startDate = moment(cdrStartDate, 'DD-MM-YYYY').startOf('day').valueOf()
    dateFilterRange.endDate = moment(cdrEndDate, 'DD-MM-YYYY').endOf('day').valueOf()
  }
  return dateFilterRange
}

function getDateFilterFromUrl(){
  let dateFilterParams = null
  if(isInstantSearch){
    dateFilterParams = getUrlHashParams().tbs
  }
  else{
    dateFilterParams = getUrlQueryParams().tbs
  }
  if(!dateFilterParams || !dateFilterParams.length){
    return
  }
  return parseDateFilter(dateFilterParams)
}

function checkIfMutationOccuredOnTargetElement(mutations, targetId){
  return mutations.find(({target: {id}}) => id === targetId)
}

function getAddedNodesForTargetElement(mutations, targetId){
  return safeGetObjectProperty(checkIfMutationOccuredOnTargetElement(mutations, targetId), 'addedNodes')
}

function getRemovedNodesForTargetElement(mutations, targetId){
  return safeGetObjectProperty(checkIfMutationOccuredOnTargetElement(mutations, targetId), 'removedNodes')
}

function findElementInNodeList(searchType, searchData, nodeList){
  if(!nodeList){
    return
  }
  if(searchType === 'nodeName'){
    return Array.from(nodeList).find(elem => elem.nodeName.toLowerCase() === searchData)
  }
  if(searchType === 'id'){
    return Array.from(nodeList).find(elem => elem.id === searchData)
  }
}
/*****
* We check the url params for the 'tbm' key as that indicates that it's not a general search.
*
* Notes:
*   * This is only for non-instant, as we cant rely on the tbm url param not being there on instant.
*   * We dont have to bother checking Flights search or Maps search, as they both are missing the '#lst-ib'
*   search input element, which we check for at the start of the googleSearch_ContentScript init().
*   * The document body contains the class 'hp' when it is on the search page (for both normal and instant search).
*   We have a css rule in our stylesheet to display: none for the MS results box when the page body has a class of
*   'hp', but we should check here for that class because this can prevent the MS results box from being created
*   and inserted, as there is no need for it to be inserted on the search page when it's not instant search.
*/
function generalResultsPageIsDisplayedForNonInstantSearch(){
  return !document.body.classList.contains('hp') && !getUrlHashParams().tbm && !getUrlQueryParams().tbm
}

export {
  getSearchQueryFromUrl,
  getDateFilterFromUrl,
  parseDateFilter,
  checkIfInstantSearch,
  checkIfMutationOccuredOnTargetElement,
  getAddedNodesForTargetElement,
  getRemovedNodesForTargetElement,
  findElementInNodeList,
  generalResultsPageIsDisplayedForNonInstantSearch,
}
<|endoftext|>


<commit_before>/* @flow weak */

/**
 * OfflineMobile Android Stocktakes Page
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  StyleSheet,
  View,
  TouchableOpacity,
} from 'react-native';

import {
  Cell,
  DataTable,
  Header,
  HeaderCell,
  Row,
} from '../widgets/DataTable';

import Icon from 'react-native-vector-icons/Ionicons';
import { generateUUID } from '../database';
import { ListView } from 'realm/react-native';
import { Button, DeleteModal, ToggleBar } from '../widgets';
import globalStyles, { SUSSOL_ORANGE } from '../globalStyles';
const SORT_BY = 'createdDate'
/**
* Renders the page for displaying Stocktakes.
* @prop   {Realm}               database        App wide database.
* @prop   {func}                navigateTo      callback for navigation stack.
* @const  {string}              SORT_BY          Locked to createdDate via created date column.
* @state  {ListView.DataSource} dataSource      DataTable input, used to update rows being rendered.
* @state  {Realm.Results}       Stocktakes      Results object containing all objects in the
*                                               Database of type Stocktake.
* @state  {boolean}             isAscending     Direction SORT_BY should sort.
*                                               (ascending/descending:true/false).
* @state  {boolean}             showCurrent     Boolean control of toggle bar options.
* @state  {array}               deleteSelection Stores id of the stocktakes selected for deletion.
*/
export class StocktakesPage extends React.Component {
  constructor(props) {
    super(props);
    const dataSource = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });
    this.state = {
      dataSource: dataSource,
      stocktakes: props.database.objects('Stocktake'),
      isAscending: false,
      showCurrent: true,
      deleteSelection: [],
    };
    this.onDeleteConfirm = this.onDeleteConfirm.bind(this);
    this.onDeleteCancel = this.onDeleteCancel.bind(this);
    this.onDeleteButtonPress = this.onDeleteButtonPress.bind(this);
    this.onColumnSort = this.onColumnSort.bind(this);
    this.renderHeader = this.renderHeader.bind(this);
    this.renderRow = this.renderRow.bind(this);
    this.refreshData = this.refreshData.bind(this);
    this.onNewStockTake = this.onNewStockTake.bind(this);
  }

  componentWillMount() {
    this.refreshData();
  }

  onColumnSort() {
    this.setState({ isAscending: !this.state.isAscending });
    this.refreshData();
  }

  onNewStockTake() {
    this.props.database.write(() => {
      this.props.database.create('Stocktake', {
        id: generateUUID(),
        name: 'best stocktake',
        createdDate: new Date(),
        status: 'new',
        comment: 'Testing StocktakesPage',
        serialNumber: '1337',
        lines: [],
      });
    });
    this.props.navigateTo('stocktakeManager', 'New StockTake');
  }

  /**
   * Takes an array of stocktakes and deletes them from database
   */
  onDeleteConfirm() {
    const { stocktakes, deleteSelection } = this.state;
    const { database } = this.props;
    database.write(() => {
      for (let i = 0; i < deleteSelection.length; i++) {
        const stocktake = stocktakes.filtered('id == $0', deleteSelection[i])[0];
        database.delete('Stocktake', stocktake);
      }
    });
    this.setState({ deleteSelection: [] });
    this.refreshData();
  }

  onDeleteCancel() {
    this.setState({ deleteSelection: [] });
    this.refreshData();
  }

  onDeleteButtonPress(stocktake) {
    const { deleteSelection } = this.state;
    if (deleteSelection.indexOf(stocktake.id) >= 0) {
      deleteSelection.splice(deleteSelection.indexOf(stocktake.id), 1);
    } else {
      deleteSelection.push(stocktake.id);
    }
    this.refreshData();
  }

  onToggleStatusFilter(isCurrent) {
    this.setState({
      showCurrent: isCurrent,
    });
    this.refreshData();
  }

  /**
   * Updates data within dataSource in state according to SORT_BY and
   * isAscending. SortBy is const set to 'createdDate'.
   */
  refreshData() {
    const { stocktakes, showCurrent, dataSource, isAscending } = this.state;
    const toggleFilter = showCurrent ? 'status == "new"' : 'status != "new"';
    const data = stocktakes
                  .filtered(toggleFilter)
                  .sorted(SORT_BY, !isAscending); // 2nd arg: reverse sort order if true
    this.setState({ dataSource: dataSource.cloneWithRows(data) });
  }

  renderHeader() {
    return (
      <Header style={globalStyles.dataTableHeader}>
        <HeaderCell
          style={globalStyles.dataTableHeaderCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[0]}
          text={'DESCRIPTION'}
        />
        <HeaderCell
          style={globalStyles.dataTableHeaderCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[1]}
          onPress={() => this.onColumnSort()}
          isAscending={this.state.isAscending}
          isSelected={true}
          text={'CREATED DATE'}
        />
        <HeaderCell
          style={globalStyles.dataTableHeaderCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[2]}
          text={'STATUS'}
        />
        <HeaderCell
          style={[
            globalStyles.dataTableHeaderCell,
            localStyles.rightMostCell,
            localStyles.deleteCell,
          ]}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[3]}
          text={'DELETE'}
        />
      </Header>
    );
  }

  renderRow(stocktake) {
    const deleteColor = this.state.deleteSelection.indexOf(stocktake.id) >= 0 ?
                                          SUSSOL_ORANGE :
                                          'grey';
    return (
      <Row
        style={globalStyles.dataTableRow}
        onPress={() => this.props.navigateTo('stocktakeManager', 'Create Stocktake')}
      >
        <Cell
          style={globalStyles.dataTableCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[0]}
        >
          {stocktake.comment}
        </Cell>
        <Cell
          style={globalStyles.dataTableCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[1]}
        >
          {stocktake.createdDate.toLocaleString()}
        </Cell>
        <Cell
          style={globalStyles.dataTableCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[2]}
        >
          {stocktake.status}
        </Cell>
        <TouchableOpacity
          style={{ flex: COLUMN_WIDTHS[3] }}
          onPress={() => this.onDeleteButtonPress(stocktake)}
        >
          <Cell
            style={[globalStyles.dataTableCell, localStyles.rightMostCell, localStyles.deleteCell]}
            textStyle={globalStyles.dataTableText}
            width={COLUMN_WIDTHS[3]}
          >
            <Icon name="md-remove-circle" size={15} color={deleteColor} />
          </Cell>
        </TouchableOpacity>
      </Row>
    );
  }

  render() {
    const { showCurrent } = this.state;
    return (
      <View style={globalStyles.pageContentContainer}>
        <View style={globalStyles.container}>
          <View style={globalStyles.pageTopSectionContainer}>
            <ToggleBar
              style={globalStyles.toggleBar}
              textStyle={globalStyles.toggleText}
              textSelectedStyle={globalStyles.toggleTextSelected}
              optionStyle={globalStyles.toggleOption}
              optionSelectedStyle={globalStyles.toggleOptionSelected}
              options={[
                {
                  text: 'Current',
                  onPress: () => this.onToggleStatusFilter(true),
                  selected: showCurrent,
                },
                {
                  text: 'Past',
                  onPress: () => this.onToggleStatusFilter(false),
                  selected: !showCurrent,
                },
              ]}
            />
            <View style={localStyles.buttonViewTop}>
              <Button
                style={globalStyles.button}
                textStyle={globalStyles.buttonText}
                text="New StockTake"
                onPress={this.onNewStockTake}
              />
            </View>
          </View>
          <DataTable
            style={globalStyles.dataTable}
            listViewStyle={localStyles.listView}
            dataSource={this.state.dataSource}
            renderRow={this.renderRow}
            renderHeader={this.renderHeader}
          />
          <DeleteModal
            isOpen={this.state.deleteSelection.length > 0}
            questionText="Are you sure you want to delete these stocktakes?"
            onCancel={() => this.onDeleteCancel()}
            onConfirm={() => this.onDeleteConfirm()}
          />
        </View>
      </View>
    );
  }
}

StocktakesPage.propTypes = {
  database: React.PropTypes.object,
  navigateTo: React.PropTypes.func.isRequired,
};
const COLUMN_WIDTHS = [6, 2, 2, 1];
const localStyles = StyleSheet.create({
  listView: {
    flex: 1,
  },
  buttonViewTop: {
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
  deleteCell: {
    alignItems: 'center',
  },
  rightMostCell: {
    borderRightWidth: 0,
  },
  dataTable: {
    flex: 1,
  },
});
<commit_msg>toLocaleString to toDateString<commit_after>/* @flow weak */

/**
 * OfflineMobile Android Stocktakes Page
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  StyleSheet,
  View,
  TouchableOpacity,
} from 'react-native';

import {
  Cell,
  DataTable,
  Header,
  HeaderCell,
  Row,
} from '../widgets/DataTable';

import Icon from 'react-native-vector-icons/Ionicons';
import { generateUUID } from '../database';
import { ListView } from 'realm/react-native';
import { Button, DeleteModal, ToggleBar } from '../widgets';
import globalStyles, { SUSSOL_ORANGE } from '../globalStyles';
const SORT_BY = 'createdDate'
/**
* Renders the page for displaying Stocktakes.
* @prop   {Realm}               database        App wide database.
* @prop   {func}                navigateTo      callback for navigation stack.
* @const  {string}              SORT_BY          Locked to createdDate via created date column.
* @state  {ListView.DataSource} dataSource      DataTable input, used to update rows being rendered.
* @state  {Realm.Results}       Stocktakes      Results object containing all objects in the
*                                               Database of type Stocktake.
* @state  {boolean}             isAscending     Direction SORT_BY should sort.
*                                               (ascending/descending:true/false).
* @state  {boolean}             showCurrent     Boolean control of toggle bar options.
* @state  {array}               deleteSelection Stores id of the stocktakes selected for deletion.
*/
export class StocktakesPage extends React.Component {
  constructor(props) {
    super(props);
    const dataSource = new ListView.DataSource({
      rowHasChanged: (row1, row2) => row1 !== row2,
    });
    this.state = {
      dataSource: dataSource,
      stocktakes: props.database.objects('Stocktake'),
      isAscending: false,
      showCurrent: true,
      deleteSelection: [],
    };
    this.onDeleteConfirm = this.onDeleteConfirm.bind(this);
    this.onDeleteCancel = this.onDeleteCancel.bind(this);
    this.onDeleteButtonPress = this.onDeleteButtonPress.bind(this);
    this.onColumnSort = this.onColumnSort.bind(this);
    this.renderHeader = this.renderHeader.bind(this);
    this.renderRow = this.renderRow.bind(this);
    this.refreshData = this.refreshData.bind(this);
    this.onNewStockTake = this.onNewStockTake.bind(this);
  }

  componentWillMount() {
    this.refreshData();
  }

  onColumnSort() {
    this.setState({ isAscending: !this.state.isAscending });
    this.refreshData();
  }

  onNewStockTake() {
    this.props.database.write(() => {
      this.props.database.create('Stocktake', {
        id: generateUUID(),
        name: 'best stocktake',
        createdDate: new Date(),
        status: 'new',
        comment: 'Testing StocktakesPage',
        serialNumber: '1337',
        lines: [],
      });
    });
    this.props.navigateTo('stocktakeManager', 'New StockTake');
  }

  /**
   * Takes an array of stocktakes and deletes them from database
   */
  onDeleteConfirm() {
    const { stocktakes, deleteSelection } = this.state;
    const { database } = this.props;
    database.write(() => {
      for (let i = 0; i < deleteSelection.length; i++) {
        const stocktake = stocktakes.filtered('id == $0', deleteSelection[i])[0];
        database.delete('Stocktake', stocktake);
      }
    });
    this.setState({ deleteSelection: [] });
    this.refreshData();
  }

  onDeleteCancel() {
    this.setState({ deleteSelection: [] });
    this.refreshData();
  }

  onDeleteButtonPress(stocktake) {
    const { deleteSelection } = this.state;
    if (deleteSelection.indexOf(stocktake.id) >= 0) {
      deleteSelection.splice(deleteSelection.indexOf(stocktake.id), 1);
    } else {
      deleteSelection.push(stocktake.id);
    }
    this.refreshData();
  }

  onToggleStatusFilter(isCurrent) {
    this.setState({
      showCurrent: isCurrent,
    });
    this.refreshData();
  }

  /**
   * Updates data within dataSource in state according to SORT_BY and
   * isAscending. SortBy is const set to 'createdDate'.
   */
  refreshData() {
    const { stocktakes, showCurrent, dataSource, isAscending } = this.state;
    const toggleFilter = showCurrent ? 'status == "new"' : 'status != "new"';
    const data = stocktakes
                  .filtered(toggleFilter)
                  .sorted(SORT_BY, !isAscending); // 2nd arg: reverse sort order if true
    this.setState({ dataSource: dataSource.cloneWithRows(data) });
  }

  renderHeader() {
    return (
      <Header style={globalStyles.dataTableHeader}>
        <HeaderCell
          style={globalStyles.dataTableHeaderCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[0]}
          text={'DESCRIPTION'}
        />
        <HeaderCell
          style={globalStyles.dataTableHeaderCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[1]}
          onPress={() => this.onColumnSort()}
          isAscending={this.state.isAscending}
          isSelected={true}
          text={'CREATED DATE'}
        />
        <HeaderCell
          style={globalStyles.dataTableHeaderCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[2]}
          text={'STATUS'}
        />
        <HeaderCell
          style={[
            globalStyles.dataTableHeaderCell,
            localStyles.rightMostCell,
            localStyles.deleteCell,
          ]}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[3]}
          text={'DELETE'}
        />
      </Header>
    );
  }

  renderRow(stocktake) {
    const deleteColor = this.state.deleteSelection.indexOf(stocktake.id) >= 0 ?
                                          SUSSOL_ORANGE :
                                          'grey';
    return (
      <Row
        style={globalStyles.dataTableRow}
        onPress={() => this.props.navigateTo('stocktakeManager', 'Create Stocktake')}
      >
        <Cell
          style={globalStyles.dataTableCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[0]}
        >
          {stocktake.comment}
        </Cell>
        <Cell
          style={globalStyles.dataTableCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[1]}
        >
          {stocktake.createdDate.toDateString()}
        </Cell>
        <Cell
          style={globalStyles.dataTableCell}
          textStyle={globalStyles.dataTableText}
          width={COLUMN_WIDTHS[2]}
        >
          {stocktake.status}
        </Cell>
        <TouchableOpacity
          style={{ flex: COLUMN_WIDTHS[3] }}
          onPress={() => this.onDeleteButtonPress(stocktake)}
        >
          <Cell
            style={[globalStyles.dataTableCell, localStyles.rightMostCell, localStyles.deleteCell]}
            textStyle={globalStyles.dataTableText}
            width={COLUMN_WIDTHS[3]}
          >
            <Icon name="md-remove-circle" size={15} color={deleteColor} />
          </Cell>
        </TouchableOpacity>
      </Row>
    );
  }

  render() {
    const { showCurrent } = this.state;
    return (
      <View style={globalStyles.pageContentContainer}>
        <View style={globalStyles.container}>
          <View style={globalStyles.pageTopSectionContainer}>
            <ToggleBar
              style={globalStyles.toggleBar}
              textStyle={globalStyles.toggleText}
              textSelectedStyle={globalStyles.toggleTextSelected}
              optionStyle={globalStyles.toggleOption}
              optionSelectedStyle={globalStyles.toggleOptionSelected}
              options={[
                {
                  text: 'Current',
                  onPress: () => this.onToggleStatusFilter(true),
                  selected: showCurrent,
                },
                {
                  text: 'Past',
                  onPress: () => this.onToggleStatusFilter(false),
                  selected: !showCurrent,
                },
              ]}
            />
            <View style={localStyles.buttonViewTop}>
              <Button
                style={globalStyles.button}
                textStyle={globalStyles.buttonText}
                text="New StockTake"
                onPress={this.onNewStockTake}
              />
            </View>
          </View>
          <DataTable
            style={globalStyles.dataTable}
            listViewStyle={localStyles.listView}
            dataSource={this.state.dataSource}
            renderRow={this.renderRow}
            renderHeader={this.renderHeader}
          />
          <DeleteModal
            isOpen={this.state.deleteSelection.length > 0}
            questionText="Are you sure you want to delete these stocktakes?"
            onCancel={() => this.onDeleteCancel()}
            onConfirm={() => this.onDeleteConfirm()}
          />
        </View>
      </View>
    );
  }
}

StocktakesPage.propTypes = {
  database: React.PropTypes.object,
  navigateTo: React.PropTypes.func.isRequired,
};
const COLUMN_WIDTHS = [6, 2, 2, 1];
const localStyles = StyleSheet.create({
  listView: {
    flex: 1,
  },
  buttonViewTop: {
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
  deleteCell: {
    alignItems: 'center',
  },
  rightMostCell: {
    borderRightWidth: 0,
  },
  dataTable: {
    flex: 1,
  },
});
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash/fp');

module.exports = function extendWithConfigueGetter(Configue) {
    Configue.prototype.get = get;
    Configue.prototype.getFirst = getFirst;
    Configue.prototype.getAll = getAll;
    Configue.prototype.template = template;
    Configue.prototype.t = template;
    Configue.prototype.getObject = getObject;
    Configue.prototype.load = load;
    return Configue;
}

function get(key, defaultValue) {
    const result = this.nconf.get(key);
    return result === undefined ? defaultValue : result;
}

function getFirst (keys) {
    // TODO refactor once es6 full support
    for(const key of (Array.isArray(keys)? keys : Array.from(arguments))) {
        const result = this.nconf.get(key);
        if (result !== undefined) return result;
    }
}

function getAll (keys) {
    return (Array.isArray(keys)? keys : Array.from(arguments))
        .map((key) => this.nconf.get(key));
}

const configueTemplate = (configue, defaults = {}) => (chains, ...keys) => {
    return _.reduce(_.zip(chains, keys),
        (acc, [chain, key]) => {
            const base = acc + chain;
            if (!key) return base;
            return base + configue.get(key, _.get(defaults, key));
        },
        '')
};

// TODO: cover with test!! and document!
 function template(defaultOrChain, ...keys){
    if(_.isPlainObject(defaultOrChain))
       return configueTemplate(this, defaultOrChain)
    else
        return configueTemplate(this)(defaultOrChain, ...keys)

}

function getObject (...args) {
    const keys = Array.isArray(_.first(args)) ? _.first(args): args;
    return _.reduce((key, memo) => ({...memo, [key]: this.get(key)}), {}, keys);
}

const getPaths = (obj, basePath = []) => _.reduce(
    (memo, path) => (_.isPlainObject(obj[path])) ?
        [...memo, ...getPaths(obj[path], [...basePath, path])]
        : [...memo, [...basePath, path]],
    [],
    _.keys(obj)
);

const populateObj = (configue, obj, paths) => _.reduce(
    (memo, path) => _.set(path, configue.getFirst(_.get(path, obj)), memo), {}, paths)

// FIXME TEST, List of key!! (filter)

function load(model) {
    return model ?
        populateObj(this, model, getPaths(model))
        : this.nconf.load();
}
<commit_msg>refactor: replace object spread with lodash set<commit_after>'use strict';

const _ = require('lodash/fp');

module.exports = function extendWithConfigueGetter(Configue) {
    Configue.prototype.get = get;
    Configue.prototype.getFirst = getFirst;
    Configue.prototype.getAll = getAll;
    Configue.prototype.template = template;
    Configue.prototype.t = template;
    Configue.prototype.getObject = getObject;
    Configue.prototype.load = load;
    return Configue;
};

function get(key, defaultValue) {
    const result = this.nconf.get(key);
    return result === undefined ? defaultValue : result;
}

function getFirst (keys) {
    // TODO refactor once es6 full support
    for(const key of (Array.isArray(keys)? keys : Array.from(arguments))) {
        const result = this.nconf.get(key);
        if (result !== undefined) return result;
    }
}

function getAll (keys) {
    return (Array.isArray(keys)? keys : Array.from(arguments))
        .map((key) => this.nconf.get(key));
}

const configueTemplate = (configue, defaults = {}) => (chains, ...keys) => {
    return _.reduce(_.zip(chains, keys),
        (acc, [chain, key]) => {
            const base = acc + chain;
            if (!key) return base;
            return base + configue.get(key, _.get(defaults, key));
        },
        '');
};

// TODO: cover with test!! and document!
function template(defaultOrChain, ...keys) {
    return _.isPlainObject(defaultOrChain)
        ? configueTemplate(this, defaultOrChain)
        : configueTemplate(this)(defaultOrChain, ...keys);
}

function getObject (...args) {
    const keys = Array.isArray(_.first(args)) ? _.first(args): args;
    return _.reduce((key, memo) => _.set(key, this.get(key), memo), {}, keys);
}

const getPaths = (obj, basePath = []) => _.reduce(
    (memo, path) => (_.isPlainObject(obj[path])) ?
        [...memo, ...getPaths(obj[path], [...basePath, path])]
        : [...memo, [...basePath, path]],
    [],
    _.keys(obj)
);

const populateObj = (configue, obj, paths) => _.reduce(
    (memo, path) => _.set(path, configue.getFirst(_.get(path, obj)), memo), {}, paths)

// FIXME TEST, List of key!! (filter)

function load(model) {
    return model ?
        populateObj(this, model, getPaths(model))
        : this.nconf.load();
}
<|endoftext|>