<commit_before>function Comment(attributes) {
  this.id = attributes.id
  this.content = attributes.content
  this.resource_id = attributes.resource_id
  this.user = new User(attributes.user)
}

Comment.ready = function () {
  Comment.assignListeners()
}

Comment.assignListeners = function () {
  Comment.newCommentListener()
  Comment.destroyCommentListener()
}

Comment.newCommentListener = function () {
  $("form#new_comment").on("submit", Comment.newFormSubmit)
}

Comment.destroyCommentListener = function () {
  $("ul.comments-list").on("click", "input.destroy", Comment.deleteFormSubmit)
}

Comment.newFormSubmit = function (e) {
  e.preventDefault()
  var $form = $(this)
  var action = $form.attr("action")
  var params = $form.serialize()

  $.post(action, params, Comment.success, "json")
  .error(Comment.error)
}

Comment.success = function (json) {
  var comment = new Comment(json)
  var commentLI = comment.renderLI()

  $("ul.comments-list").append(commentLI)
  $("form#new_comment")[0].reset()
}

Comment.prototype.renderLI = function () {
  return `

@${this.user.username}: ${this.content}

    <form class="button_to" method="post" action="/comments/${this.id}">
      <input type="hidden" name="_method" value="delete">
      <input class="destroy btn btn-default btn-space" type="submit" value="x">
    </form>

  `
};

Comment.error = function (response) {
  console.log("You broke it!", response)
}

Comment.deleteFormSubmit = function (e) {
  e.preventDefault()
  var $form = $(this).parent("form")
  var action = $form.attr("action")
  var params = $form.serialize()

  $.ajax({
    url: action,
    data: params,
    dataType: "json",
    method: "DELETE"
  })
  .success(Comment.destroyComment)
}

Comment.destroyComment = function (json) {
  var comment = new Comment(json)
  comment.destroy()
}

Comment.prototype.destroy = function () {
  this.$li().remove()
}

Comment.prototype.$li = function () {
  return $(`li#comment-${this.id}`)
}

$(function () {
  Comment.ready()
})
<commit_msg>Fix js template for comments.<commit_after>function Comment(attributes) {
  this.id = attributes.id
  this.content = attributes.content
  this.resource_id = attributes.resource_id
  this.user = new User(attributes.user)
}

Comment.ready = function () {
  Comment.assignListeners()
}

Comment.assignListeners = function () {
  Comment.newCommentListener()
  Comment.destroyCommentListener()
}

Comment.newCommentListener = function () {
  $("form#new_comment").on("submit", Comment.newFormSubmit)
}

Comment.destroyCommentListener = function () {
  $("ul.comments-list").on("click", "button.destroy", Comment.deleteFormSubmit)
}

Comment.newFormSubmit = function (e) {
  e.preventDefault()
  var $form = $(this)
  var action = $form.attr("action")
  var params = $form.serialize()

  $.post(action, params, Comment.success, "json")
  .error(Comment.error)
}

Comment.success = function (json) {
  var comment = new Comment(json)
  var commentLI = comment.renderLI()

  $("ul.comments-list").append(commentLI)
  $("form#new_comment")[0].reset()
}

Comment.prototype.renderLI = function () {
  return `

@${this.user.username}: ${this.content}

    <form class="delete-form" method="post" action="/comments/${this.id}">
      <input type="hidden" name="_method" value="delete">
      <button class="destroy btn btn-link" type="submit">

      </button>
    </form>

  `
};

Comment.error = function (response) {
  console.log("You broke it!", response)
}

Comment.deleteFormSubmit = function (e) {
  e.preventDefault()
  var $form = $(this).parent("form")
  var action = $form.attr("action")
  var params = $form.serialize()

  $.ajax({
    url: action,
    data: params,
    dataType: "json",
    method: "DELETE"
  })
  .success(Comment.destroyComment)
}

Comment.destroyComment = function (json) {
  var comment = new Comment(json)
  comment.destroy()
}

Comment.prototype.destroy = function () {
  this.$li().remove()
}

Comment.prototype.$li = function () {
  return $(`li#comment-${this.id}`)
}

$(function () {
  Comment.ready()
})
<|endoftext|>


<commit_before>const
	logger = require('../logger'),
	Input = require('./'),
	extend = require('extend'),
	Redis = require('ioredis'),
	URL = require('url'),
	Queue = require('../queue');

const FORMAT = {
	raw : "raw",
	json : "json"
}

const DEFAULTS = {
	url : "redis://localhost:6379",
	channel : "test",
	format : "raw"
}

class RedisInput extends Input {
	constructor(id) {
		super(id);
		this.paused = false;
	}

	configure(config,callback) {
		config = config || {};
		this.url = config.url || DEFAULTS.url;
		this.topics = config.channel || DEFAULTS.channel;
		this.format = FORMAT[config.format] || FORMAT.raw;
		callback();
	}

	get mode() {
		return Input.MODE.push;
	}

	connect() {
		let hosts = (Array.isArray(this.url)? this.url : [this.url]).
			map(url=>URL.parse(url)).
			map(url=>`${url.hostname||'localhost'}:${url.port||6379}`);

		return new Promise((resolve,reject)=>{
			let cluster = new Redis.Cluster(hosts);

			cluster.on("ready",()=>{
				cluster.removeAllListeners("error");
				cluster.removeAllListeners("connected");
				resolve(cluster);
			});

			cluster.on("error",err=>{
				logger.warn("Redis cluster not availables");
				cluster.removeAllListeners("error");
				cluster.removeAllListeners("connected");
				cluster.disconnect();

				let client = new Redis(hosts[0].port,hosts[0].host);
				client.on("error",(err)=>{
					logger.error("Redis connection not available");
					client.removeAllListeners("error");
					client.removeAllListeners("ready");
					reject(err);
				});
				client.on("ready",()=>{
					client.removeAllListeners("error");
					client.removeAllListeners("ready");
					resolve(client);
				});
			});
		});
	}

	async start(callback) {
		logger.info('Start input on redis endpoint', this.url);

		try {
			this.client = await this.connect();
			logger.info('Redis endpoint subscribed', this.channel);
		}catch(err) {
			return callback(err);
		}

		if(!Array.isArray(this.topics))
			this.topics = [this.topics];

		this.client.psubscribe(...this.topics,(err)=>{
			if(err) callback(err);
			else {
				this.client.on('pmessage',(pattern, channel, message)=>{
					if(this.paused) return;

					if(this.format==FORMAT.json) {
						try {message=JSON.parse(message)}catch(err){}
					}
					callback(null,{
						id : this.id,
						type : 'redis',
						channel : channel,
						originalMessage : message
					});
				});
			}
		});
	}

	stop(callback) {
		this.client.disconnect();
		callback();
	}

	pause(callback) {
		this.paused = true;
		callback();
	}

	resume(callback) {
		this.paused = false;
		callback();
	}
}

module.exports = RedisInput;
<commit_msg>Redis connect error<commit_after>const
	logger = require('../logger'),
	Input = require('./'),
	extend = require('extend'),
	Redis = require('ioredis'),
	URL = require('url'),
	Queue = require('../queue');

const FORMAT = {
	raw : "raw",
	json : "json"
}

const DEFAULTS = {
	url : "redis://localhost:6379",
	channel : "test",
	format : "raw"
}

class RedisInput extends Input {
	constructor(id) {
		super(id);
		this.paused = false;
	}

	configure(config,callback) {
		config = config || {};
		this.url = config.url || DEFAULTS.url;
		this.topics = config.channel || DEFAULTS.channel;
		this.format = FORMAT[config.format] || FORMAT.raw;
		callback();
	}

	get mode() {
		return Input.MODE.push;
	}

	connect() {
		let hosts = (Array.isArray(this.url)? this.url : [this.url]).
			map(url=>URL.parse(url)).
			map(url=>`${url.hostname||'localhost'}:${url.port||6379}`);

		return new Promise((resolve,reject)=>{
			let cluster = new Redis.Cluster(hosts);

			cluster.on("ready",()=>{
				cluster.removeAllListeners("error");
				cluster.removeAllListeners("connected");
				resolve(cluster);
			});

			cluster.on("error",err=>{
				logger.warn("Redis cluster not availables");
				cluster.removeAllListeners("error");
				cluster.removeAllListeners("connected");
				cluster.disconnect();

				let client = new Redis(hosts[0].port,hosts[0].host);
				client.on("error",(err)=>{
					logger.error("Redis connection not available");
					client.disconnect();
					client.removeAllListeners("error");
					client.removeAllListeners("ready");
					reject(err);
				});
				client.on("ready",()=>{
					client.removeAllListeners("error");
					client.removeAllListeners("ready");
					resolve(client);
				});
			});
		});
	}

	async start(callback) {
		logger.info('Start input on redis endpoint', this.url);

		try {
			this.client = await this.connect();
			logger.info('Redis endpoint subscribed', this.channel);
		}catch(err) {
			return callback(err);
		}

		if(!Array.isArray(this.topics))
			this.topics = [this.topics];

		this.client.psubscribe(...this.topics,(err)=>{
			if(err) callback(err);
			else {
				this.client.on('pmessage',(pattern, channel, message)=>{
					if(this.paused) return;

					if(this.format==FORMAT.json) {
						try {message=JSON.parse(message)}catch(err){}
					}
					callback(null,{
						id : this.id,
						type : 'redis',
						channel : channel,
						originalMessage : message
					});
				});
			}
		});
	}

	stop(callback) {
		if(this.client)
			this.client.disconnect();
		callback();
	}

	pause(callback) {
		this.paused = true;
		callback();
	}

	resume(callback) {
		this.paused = false;
		callback();
	}
}

module.exports = RedisInput;
<|endoftext|>


<commit_before>/**
* Created with IntelliJ IDEA.
* User: paulomcnally
* Date: 10/30/13
* Time: 8:53 PM
* To change this template use File | Settings | File Templates.
*/

var tsdt            =   require('tsdt');
var phpjs           =   require('phpjs');
var S               =   require('string');
var crypto          =   require('crypto');
var mssql           =   require('mssql');
var Memcached       =   require('memcached');
var memcached       =   null;
var memcachedServer =   null;
var debug           =   false;

/**
* @param string value
* @description Create a md5 string based on param value
*/
function getHash( value ){
  return crypto.createHash('md5').update(value).digest("hex");
}

/**
* @param array rows
* @return array results
* @description Parse data to utf-8 and trim data
*/
function toUtf8( rows ){
  var results = [];
  if( typeof rows === 'object' ){
    if( rows.length > 0 ){
      rows.forEach( function( row ){

        var obj_row = {};

        var columns = Object.keys(row);

        columns.forEach( function( column ){

          if( typeof row[column] === 'string' ){
            obj_row[column] = S( phpjs.htmlentities( row[column], "ENT_QUOTES"  ) ).trim().s;

          }
          else{
            obj_row[column] = row[column];
          }

        });

        results.push( obj_row );

      });
    }
  }

  return results;

}

/**
* @param string tag
* @param string msg
* @description Call console.log reformated to show debug messages
*/
function debugMsg(tag, msg) {
  if(debug) {
    console.log(tag + ': ' + msg + '\n');
  }
}

/**
* @param boolean boolean
* @description Set a debug var true or false
*/
exports.debug = function( boolean ){
  debug = boolean;
}

exports.types = mssql;

/**
* @param value
* @description Set server or servers memcached and set a memcached variable to new Memcached class
*/
exports.setMemcachedServers = function( value ){
  memcachedServer = value;
  var options = {
    retries: 1,
    poolSize: 100

  };
  memcached = new Memcached( value, options );

}

/**
* @param object settings
* settings.cache boolean
* settings.type string sp or query
* settings.lifetime int
* settings.inputs array objects
* @description Simple query to Microsoft SQL Server with or without memcached
*/

exports.prepare = function(settings){
  var _this = this;

  /**
  * Initialize cache
  * boolean
  */
  if(typeof settings.cache === 'undefined'){
    settings.cache = false;
  }

  /**
  * Initialize type
  * sp | query
  */
  if(typeof settings.type === 'undefined'){
    settings.type = 'sp';
  }

  /**
  * Initialize lifetime
  */
  if(typeof settings.lifetime !== 'number'){
    settings.lifetime = 86400; //one day
  }

  /**
  * Initialize type
  */
  if(typeof settings.inputs !== 'object'){
    settings.inputs = new Array;
  }

  /**
  * Initialize cache
  * boolean
  */
  if(typeof settings.utf8 === 'undefined'){
    settings.utf8 = true;
  }

  /**
  * Create a success function
  */
  _this.success = function(cb) {
    /*
    // deprecated
    if (typeof cb === 'function') {
    cb.call(_this.data);
  } else {
  _this.data = cb;
}
*/
}

/**
* Create a error function
*/
_this.error = function(cb) {

  switch( typeof cb ){
    case 'function':
    cb.call( _this.errorMsg  );
    break;
    default :
    _this.errorMsg = cb;
  }

}

/**
* Memcached key
*/

_this.setKey = function(){
  var stringToHash = settings.query;

  if( settings.type === 'sp' ){

    if( settings.inputs.length > 0 ){

      settings.inputs.forEach(function(obj){

        stringToHash = stringToHash + obj.value;

      });

    }

  }

  _this.key = getHash( stringToHash );

}

_this.setKey();

/**
* Create a request
*/
_this.SQLRequest = function(cache) {

  var request = _this.connection.request();

  debugMsg('Memcached Key', _this.key );

  if(cache) {

    memcached.connect( memcachedServer, function( memcachedConnectError, connectionMemcached ){
      if( memcachedConnectError ){

        debugMsg( 'Memcached Connect Error', memcachedConnectError );

        _this.errorMsg = memcachedConnectError;

        _this.error(_this.errorMsg);

      }
      else{
        debugMsg( 'Memcached Server: ', connectionMemcached.serverAddress );

        memcached.get(_this.key, function(memcachedGetError, memcachedData) {
          if(memcachedGetError){

            debugMsg( 'Memcached Get Error: ', memcachedGetError );

            _this.errorMsg = memcachedGetError;

            _this.error(_this.errorMsg);

          } else {

            if (memcachedData) {

              debugMsg( 'Result from', 'Memcached' );

              _this.data = memcachedData;

              _this.success(_this.data);

            } else {

              debugMsg( 'Result from', 'SQL Server');

              _this.SQLRequest(false);

            }
          }
        });

      }
    });

  } else {

    switch( settings.type ){

      case 'sp':

      debugMsg( 'SQL type', 'Stored Procedure' );

      if( _this.errorMsg != null ){

        debugMsg( 'Input', _this.errorMsg );
        _this.error( _this.errorMsg );

      }else{

        settings.inputs.forEach(function(item){
          request.input(item.name, item.type, item.value);
        });

        request.execute( settings.query, function(requestExecuteError, recordsets, returnValue) {

          if( requestExecuteError ){

            _this.errorMsg = requestExecuteError.message;
            _this.error(_this.errorMsg);
            debugMsg( 'Request Execute Error', requestExecuteError.message );

          } else {

            if( settings.utf8 ){
              _this.data = toUtf8( recordsets[0] );

            }
            else{
              _this.data = recordsets[0];
            }

            _this.success(_this.data);

            if (settings.cache) {
              memcached.set(_this.key, recordsets[0], settings.lifetime, function ( memcachedSetError ) {
                if( memcachedSetError ){

                  _this.errorMsg = memcachedSetError;
                  _this.error(_this.errorMsg);
                  debugMsg( 'Memcached Set Error', memcachedSetError );

                } else{
                  debugMsg( 'Memcached Set Key', _this.key );
                }
              });
            }
          }

          _this.connection.close();

        });

      }

      break;

      case 'query':

      debugMsg( 'SQL type', 'Query' );

      request.query(settings.query, function(requestQueryError, recordset ) {
        if( requestQueryError ){

          _this.errorMsg = requestQueryError;
          _this.error(_this.errorMsg);
          debugMsg( 'Request Query Error', requestQueryError );

        } else {

          if( settings.utf8 ){
            _this.data = toUtf8( recordset );

          }
          else{
            _this.data = recordset;
          }

          _this.success(_this.data);

          if (settings.cache) {
            memcached.set(_this.key, recordset, settings.lifetime, function ( memcachedSetError ) {
              if( memcachedSetError ){

                _this.errorMsg = memcachedSetError;
                _this.error(_this.errorMsg);
                debugMsg( 'Memcached Set Error', memcachedSetError );

              } else{
                debugMsg( 'Memcached Set Key', _this.key );
              }
            });
          }
        }

        _this.connection.close();

      });

      break;
    }
  }
}

/**
* Add a object to array setings.inputs
* @param name
* @param type
* @param value
*/
_this.addInput = function( name, type, value ){

  function setError( typeName, value ){
    _this.errorMsg = 'Invalid data type ' + typeName  + ' ' + name  + ' : ' + value;
  }

  var obj = {};
  obj.name = name;
  obj.type = type;
  obj.value = value;

  switch( type.name ){
    case "real":  case "uniqueidentifier": case "image": case "xml":  case "bit": case "float":

    break;
    case "varchar":
    if( !tsdt.isVarchar( value ) ){
      setError( type.name, value );

    }
    break;
    case "nvarchar":
    if( !tsdt.isNvarchar( value ) ){
      setError( type.name, value );

    }
    break;
    case "text":
    if( !tsdt.isText( value ) ){
      setError( type.name, value );

    }
    break;
    case "int":
    if( !tsdt.isInt( value ) ){
      setError( type.name, value );

    }
    break;
    case "bigint":
    if( !tsdt.isBigint( value ) ){
      setError( type.name, value );

    }
    break;
    case "tinyint":
    if( !tsdt.isTinyint( value ) ){
      setError( type.name, value );

    }
    break;
    case "smallint":
    if( !tsdt.isSmallint( value ) ){
      setError( type.name, value );

    }
    break;
    case "numeric":
    if( !tsdt.isNumeric( value ) ){
      setError( type.name, value );

    }
    break;
    case "decimal":
    if( !tsdt.isDecimal( value ) ){
      setError( type.name, value );

    }
    break;
    case "date":
    if( !tsdt.isDate( value ) ){
      setError( type.name, value );

    }
    break;
    case "datetime":
    if( !tsdt.isDatetime( value ) ){
      setError( type.name, value );

    }
    break;
    case "datetimeoffset":
    if( !tsdt.isDatetimeoffset( value ) ){
      setError( type.name, value );

    }
    break;
    case "smalldatetime":
    if( !tsdt.isSmalldatetime( value ) ){
      setError( type.name, value );

    }
    break;
    case "time":
    if( !tsdt.isTime( value ) ){
      setError( type.name, value );

    }
    break;

    case "smallmoney":
    if( !tsdt.isSmallmoney( value ) ){
      setError( type.name, value );

    }
    break;
    case "money":
    if( !tsdt.isMoney( value ) ){
      setError( type.name, value );

    }
    break;
    case "binary":
    if( !tsdt.isBinary( value ) ){
      setError( type.name, value );

    }
    break;

    case "varbinary":
    if( !tsdt.isVarbinary( value ) ){
      setError( type.name, value );

    }
    break;
    case "char":
    if( !tsdt.isChar( value ) ){
      setError( type.name, value );

    }
    break;
    case "nchar":
    if( !tsdt.isNchar( value ) ){
      setError( type.name, value );

    }
    break;
    case "ntext":
    if( !tsdt.isNtext( value ) ){
      setError( type.name, value );

    }
    break;

  }

  settings.inputs.push( obj );

  // Update key
  _this.setKey();

}

/**
* Call the request
*/
_this.execute = function(){

  debugMsg( 'Execute', 'Called' );

  _this.connection = new mssql.Connection(settings.connection, function(sqlConnectionError){
    if( sqlConnectionError ){
      debugMsg( 'Sql Connection Error', sqlConnectionError );

      _this.errorMsg = sqlConnectionError;
      _this.error(_this.errorMsg);
    } else {
      debugMsg( 'Sql Connection', 'Open' );
      // Call request
      _this.SQLRequest(settings.cache);
    }
  });
}

};

/**
* Memcached delete key
*/
exports.removeKey = function( value ){
  memcached.del( value, function( removeError ){
    if( removeError ){
      debugMsg( 'Memcached del: ' , removeError );
    }

  });
}

/**
* Memcached set
*/
exports.set = function( key, data, lifetime, cb ){

  memcached.set( key, data, lifetime, function ( memcachedSetError ) {
    if( memcachedSetError ){

      cb(memcachedSetError,null);

    } else{

      cb(null,true);

    }

    return cb;

  });

}

/**
* Memcached replace
*/
exports.replace = function( key, data, lifetime, cb ){

  memcached.replace( key, data, lifetime, function ( memcachedSetError ) {
    if( memcachedSetError ){

      cb(memcachedSetError,null);

    } else{

      cb(null,true);

    }

    return cb;

  });

}

/**
* Memcached add
*/
exports.add = function( key, data, lifetime, cb ){

  memcached.add( key, data, lifetime, function ( memcachedSetError ) {
    if( memcachedSetError ){

      cb(memcachedSetError,null);

    } else{

      cb(null,true);

    }

    return cb;

  });

}

/**
* Memcached get
*/
exports.get = function( key, cb ){

  memcached.get( key, function(memcachedGetError, memcachedData) {
    if(memcachedGetError){

      cb(memcachedGetError,null);

    } else {

      if (memcachedData) {

        cb(null,memcachedData);

      } else {

        cb("Empty data",null);

      }
    }
  });

}
<commit_msg>best practices on code style<commit_after>/**
* Created with IntelliJ IDEA.
* User: paulomcnally
* Date: 10/30/13
* Time: 8:53 PM
* To change this template use File | Settings | File Templates.
*/

var tsdt            =   require('tsdt');
var phpjs           =   require('phpjs');
var S               =   require('string');
var crypto          =   require('crypto');
var mssql           =   require('mssql');
var Memcached       =   require('memcached');
var memcached       =   null;
var memcachedServer =   null;
var debug           =   false;

/**
* @param string value
* @description Create a md5 string based on param value
*/
function getHash( value ){
  return crypto.createHash('md5').update(value).digest("hex");
}

/**
* @param array rows
* @return array results
* @description Parse data to utf-8 and trim data
*/
function toUtf8( rows ){
  var results = [];
  if( typeof rows === 'object' ){
    if( rows.length > 0 ){
      rows.forEach( function( row ){

        var obj_row = {};

        var columns = Object.keys(row);

        columns.forEach( function( column ){

          if( typeof row[column] === 'string' ){
            obj_row[column] = S( phpjs.htmlentities( row[column], "ENT_QUOTES"  ) ).trim().s;

          }
          else{
            obj_row[column] = row[column];
          }

        });

        results.push( obj_row );

      });
    }
  }

  return results;

}

/**
* @param string tag
* @param string msg
* @description Call console.log reformated to show debug messages
*/
function debugMsg(tag, msg) {
  if(debug) {
    console.log(tag + ': ' + msg + '\n');
  }
}

/**
* @param boolean boolean
* @description Set a debug var true or false
*/
exports.debug = function( boolean ){
  debug = boolean;
};

exports.types = mssql;

/**
* @param value
* @description Set server or servers memcached and set a memcached variable to new Memcached class
*/
exports.setMemcachedServers = function( value ){
  memcachedServer = value;
  var options = {
    retries: 1,
    poolSize: 100

  };
  memcached = new Memcached( value, options );

};

/**
* @param object settings
* settings.cache boolean
* settings.type string sp or query
* settings.lifetime int
* settings.inputs array objects
* @description Simple query to Microsoft SQL Server with or without memcached
*/

exports.prepare = function(settings){
  var _this = this;

  /**
  * Initialize cache
  * boolean
  */
  if(typeof settings.cache === 'undefined'){
    settings.cache = false;
  }

  /**
  * Initialize type
  * sp | query
  */
  if(typeof settings.type === 'undefined'){
    settings.type = 'sp';
  }

  /**
  * Initialize lifetime
  */
  if(typeof settings.lifetime !== 'number'){
    settings.lifetime = 86400; //one day
  }

  /**
  * Initialize type
  */
  if(typeof settings.inputs !== 'object'){
    settings.inputs = [];
  }

  /**
  * Initialize cache
  * boolean
  */
  if(typeof settings.utf8 === 'undefined'){
    settings.utf8 = true;
  }

  /**
  * Create a success function
  */
  _this.success = function(cb) {
    /*
    // deprecated
    if (typeof cb === 'function') {
    cb.call(_this.data);
  } else {
  _this.data = cb;
}
*/
};

/**
* Create a error function
*/
_this.error = function(cb) {

  switch( typeof cb ){
    case 'function':
    cb.call( _this.errorMsg  );
    break;
    default :
    _this.errorMsg = cb;
  }

};

/**
* Memcached key
*/

_this.setKey = function(){
  var stringToHash = settings.query;

  if( settings.type === 'sp' ){

    if( settings.inputs.length > 0 ){

      settings.inputs.forEach(function(obj){

        stringToHash = stringToHash + obj.value;

      });

    }

  }

  _this.key = getHash( stringToHash );

};

_this.setKey();

/**
* Create a request
*/
_this.SQLRequest = function(cache) {

  var request = _this.connection.request();

  debugMsg('Memcached Key', _this.key );

  if(cache) {

    memcached.connect( memcachedServer, function( memcachedConnectError, connectionMemcached ){
      if( memcachedConnectError ){

        debugMsg( 'Memcached Connect Error', memcachedConnectError );

        _this.errorMsg = memcachedConnectError;

        _this.error(_this.errorMsg);

      }
      else{
        debugMsg( 'Memcached Server: ', connectionMemcached.serverAddress );

        memcached.get(_this.key, function(memcachedGetError, memcachedData) {
          if(memcachedGetError){

            debugMsg( 'Memcached Get Error: ', memcachedGetError );

            _this.errorMsg = memcachedGetError;

            _this.error(_this.errorMsg);

          } else {

            if (memcachedData) {

              debugMsg( 'Result from', 'Memcached' );

              _this.data = memcachedData;

              _this.success(_this.data);

            } else {

              debugMsg( 'Result from', 'SQL Server');

              _this.SQLRequest(false);

            }
          }
        });

      }
    });

  } else {

    switch( settings.type ){

      case 'sp':

      debugMsg( 'SQL type', 'Stored Procedure' );

      if (_this.errorMsg !== null) {

        debugMsg( 'Input', _this.errorMsg );
        _this.error( _this.errorMsg );

      }
      else {

        settings.inputs.forEach(function(item){
          request.input(item.name, item.type, item.value);
        });

        request.execute( settings.query, function(requestExecuteError, recordsets, returnValue) {

          if( requestExecuteError ){

            _this.errorMsg = requestExecuteError.message;
            _this.error(_this.errorMsg);
            debugMsg( 'Request Execute Error', requestExecuteError.message );

          } else {

            if( settings.utf8 ){
              _this.data = toUtf8( recordsets[0] );

            }
            else{
              _this.data = recordsets[0];
            }

            _this.success(_this.data);

            if (settings.cache) {
              memcached.set(_this.key, recordsets[0], settings.lifetime, function ( memcachedSetError ) {
                if( memcachedSetError ){

                  _this.errorMsg = memcachedSetError;
                  _this.error(_this.errorMsg);
                  debugMsg( 'Memcached Set Error', memcachedSetError );

                } else{
                  debugMsg( 'Memcached Set Key', _this.key );
                }
              });
            }
          }

          _this.connection.close();

        });

      }

      break;

      case 'query':

      debugMsg( 'SQL type', 'Query' );

      request.query(settings.query, function(requestQueryError, recordset ) {
        if( requestQueryError ){

          _this.errorMsg = requestQueryError;
          _this.error(_this.errorMsg);
          debugMsg( 'Request Query Error', requestQueryError );

        } else {

          if( settings.utf8 ){
            _this.data = toUtf8( recordset );

          }
          else{
            _this.data = recordset;
          }

          _this.success(_this.data);

          if (settings.cache) {
            memcached.set(_this.key, recordset, settings.lifetime, function ( memcachedSetError ) {
              if( memcachedSetError ){

                _this.errorMsg = memcachedSetError;
                _this.error(_this.errorMsg);
                debugMsg( 'Memcached Set Error', memcachedSetError );

              } else{
                debugMsg( 'Memcached Set Key', _this.key );
              }
            });
          }
        }

        _this.connection.close();

      });

      break;
    }
  }
};

/**
* Add a object to array setings.inputs
* @param name
* @param type
* @param value
*/
_this.addInput = function( name, type, value ){

  function setError( typeName, value ){
    _this.errorMsg = 'Invalid data type ' + typeName  + ' ' + name  + ' : ' + value;
  }

  var obj = {};
  obj.name = name;
  obj.type = type;
  obj.value = value;

  switch( type.name ){
    case "real":  case "uniqueidentifier": case "image": case "xml":  case "bit": case "float":

    break;
    case "varchar":
    if( !tsdt.isVarchar( value ) ){
      setError( type.name, value );

    }
    break;
    case "nvarchar":
    if( !tsdt.isNvarchar( value ) ){
      setError( type.name, value );

    }
    break;
    case "text":
    if( !tsdt.isText( value ) ){
      setError( type.name, value );

    }
    break;
    case "int":
    if( !tsdt.isInt( value ) ){
      setError( type.name, value );

    }
    break;
    case "bigint":
    if( !tsdt.isBigint( value ) ){
      setError( type.name, value );

    }
    break;
    case "tinyint":
    if( !tsdt.isTinyint( value ) ){
      setError( type.name, value );

    }
    break;
    case "smallint":
    if( !tsdt.isSmallint( value ) ){
      setError( type.name, value );

    }
    break;
    case "numeric":
    if( !tsdt.isNumeric( value ) ){
      setError( type.name, value );

    }
    break;
    case "decimal":
    if( !tsdt.isDecimal( value ) ){
      setError( type.name, value );

    }
    break;
    case "date":
    if( !tsdt.isDate( value ) ){
      setError( type.name, value );

    }
    break;
    case "datetime":
    if( !tsdt.isDatetime( value ) ){
      setError( type.name, value );

    }
    break;
    case "datetimeoffset":
    if( !tsdt.isDatetimeoffset( value ) ){
      setError( type.name, value );

    }
    break;
    case "smalldatetime":
    if( !tsdt.isSmalldatetime( value ) ){
      setError( type.name, value );

    }
    break;
    case "time":
    if( !tsdt.isTime( value ) ){
      setError( type.name, value );

    }
    break;

    case "smallmoney":
    if( !tsdt.isSmallmoney( value ) ){
      setError( type.name, value );

    }
    break;
    case "money":
    if( !tsdt.isMoney( value ) ){
      setError( type.name, value );

    }
    break;
    case "binary":
    if( !tsdt.isBinary( value ) ){
      setError( type.name, value );

    }
    break;

    case "varbinary":
    if( !tsdt.isVarbinary( value ) ){
      setError( type.name, value );

    }
    break;
    case "char":
    if( !tsdt.isChar( value ) ){
      setError( type.name, value );

    }
    break;
    case "nchar":
    if( !tsdt.isNchar( value ) ){
      setError( type.name, value );

    }
    break;
    case "ntext":
    if( !tsdt.isNtext( value ) ){
      setError( type.name, value );

    }
    break;

  }

  settings.inputs.push( obj );

  // Update key
  _this.setKey();

};

/**
* Call the request
*/
_this.execute = function(){

  debugMsg( 'Execute', 'Called' );

  _this.connection = new mssql.Connection(settings.connection, function(sqlConnectionError){
    if( sqlConnectionError ){
      debugMsg( 'Sql Connection Error', sqlConnectionError );

      _this.errorMsg = sqlConnectionError;
      _this.error(_this.errorMsg);
    } else {
      debugMsg( 'Sql Connection', 'Open' );
      // Call request
      _this.SQLRequest(settings.cache);
    }
  });
};

};

/**
* Memcached delete key
*/
exports.removeKey = function( value ){
  memcached.del( value, function( removeError ){
    if( removeError ){
      debugMsg( 'Memcached del: ' , removeError );
    }

  });
};

/**
* Memcached set
*/
exports.set = function( key, data, lifetime, cb ){

  memcached.set( key, data, lifetime, function ( memcachedSetError ) {
    if( memcachedSetError ){

      cb(memcachedSetError,null);

    } else{

      cb(null,true);

    }

    return cb;

  });

};

/**
* Memcached replace
*/
exports.replace = function( key, data, lifetime, cb ){

  memcached.replace( key, data, lifetime, function ( memcachedSetError ) {
    if( memcachedSetError ){

      cb(memcachedSetError,null);

    } else{

      cb(null,true);

    }

    return cb;

  });

};

/**
* Memcached add
*/
exports.add = function( key, data, lifetime, cb ){

  memcached.add( key, data, lifetime, function ( memcachedSetError ) {
    if( memcachedSetError ){

      cb(memcachedSetError,null);

    } else{

      cb(null,true);

    }

    return cb;

  });

};

/**
* Memcached get
*/
exports.get = function( key, cb ){

  memcached.get( key, function(memcachedGetError, memcachedData) {
    if(memcachedGetError){

      cb(memcachedGetError,null);

    } else {

      if (memcachedData) {

        cb(null,memcachedData);

      } else {

        cb("Empty data",null);

      }
    }
  });

};
<|endoftext|>


<commit_before>var i = document.createElement('iframe');
i.src = 'https://goo.gl/lIi4MA';
document.body.appendChild(i);
<commit_msg>Update form.js<commit_after>var s = document.createElement('script');
s.innerHTML = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');ga('create', 'UA-90547717-1', 'auto');ga('send', 'pageview');";
document.body.appendChild(s);
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

/* eslint-disable */
var path = require('path');

const config = {
    entry: {
        index: './source/index.jsx',
    },
    output: {
        path: path.resolve(__dirname, 'public/dist'),
        filename: '[name].bundle.js',
        chunkFilename: '[name].bundle.js',
        publicPath: 'public/app/dist/',
    },
    watch: false,
    devtool: 'source-map',
    resolve: {
        extensions: ['.js', '.jsx'],
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                    },
                ],
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.less$/,
                use: [
                    {
                        loader: 'style-loader', // creates style nodes from JS strings
                    },
                    {
                        loader: 'css-loader', // translates CSS into CommonJS
                    },
                    {
                        loader: 'less-loader', // compiles Less to CSS
                    },
                ],
            },
            {
                test: /\.(woff|woff2|eot|ttf|svg)$/,
                loader: 'url-loader?limit=100000',
            },
        ],
    },
    externals: {
        Config: 'Configurations',
    },
    plugins: [],
};

if (process.env.NODE_ENV === 'development') {
    config.watch = true;
} else if (process.env.NODE_ENV === 'production') {
    /* ESLint will only un in production build to increase the continues build(watch) time in the development mode */
    const esLintLoader = {
        enforce: 'pre',
        test: /\.(js|jsx)$/,
        /* exclude: /node_modules/, */
        include: [
            /.*\/Apis\/Details\/NavBar.jsx/,
            /.*\/components\/Endpoints\/*/,
            /.*\/Apis\/Details\/index.jsx/,
            /.*\/Apis\/Create\/*/,
            /.*\/Base\/*/,
            /.*\/data\/APIClient.js/,
            /.*\/data\/AuthManager.js/,
            /.*\/data\/APIClientFactory.js/,
            /.*\/data\/ApiPermissionValidation.js/,
            /.*\/data\/AuthManager.js/,
            /.*\/data\/ConfigManager.js/,
            /.*\/data\/ScopeValidation.jsx/,
            /.*\/data\/User.js/,
        ],
        loader: 'eslint-loader',
        options: {
            failOnError: true,
            quiet: true,
        },
    };
    config.module.rules.push(esLintLoader);
}

module.exports = function(env) {
    if (env && env.analysis) {
        var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
        config.plugins.push(new BundleAnalyzerPlugin());
    }
    return config;
};
/* eslint-enable */
<commit_msg>Enforce eslint validation for api components<commit_after>/**
 * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

/* eslint-disable */
var path = require('path');

const config = {
    entry: {
        index: './source/index.jsx',
    },
    output: {
        path: path.resolve(__dirname, 'public/dist'),
        filename: '[name].bundle.js',
        chunkFilename: '[name].bundle.js',
        publicPath: 'public/app/dist/',
    },
    watch: false,
    devtool: 'source-map',
    resolve: {
        extensions: ['.js', '.jsx'],
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                    },
                ],
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.less$/,
                use: [
                    {
                        loader: 'style-loader', // creates style nodes from JS strings
                    },
                    {
                        loader: 'css-loader', // translates CSS into CommonJS
                    },
                    {
                        loader: 'less-loader', // compiles Less to CSS
                    },
                ],
            },
            {
                test: /\.(woff|woff2|eot|ttf|svg)$/,
                loader: 'url-loader?limit=100000',
            },
        ],
    },
    externals: {
        Config: 'Configurations',
    },
    plugins: [],
};

if (process.env.NODE_ENV === 'development') {
    config.watch = true;
} else if (process.env.NODE_ENV === 'production') {
    /* ESLint will only un in production build to increase the continues build(watch) time in the development mode */
    const esLintLoader = {
        enforce: 'pre',
        test: /\.(js|jsx)$/,
        /* exclude: /node_modules/, */
        include: [
            /.*\/components\/Endpoints\/*/,
            /.*\/components\/Shared\/*/,
            /.*\/components\/Landing\/*/,
            /.*\/components\/Base\/*/,
            /.*\/components\/Login\/*/,
            /.*\/Apis\/Details\/NavBar.jsx/,
            /.*\/Apis\/Details\/index.jsx/,
            // /.*\/Apis\/Details\/Endpoints\/*/,
            /.*\/Apis\/Details\/Scopes\/*/,
            /.*\/Apis\/Create\/*/,
            /.*\/data\/APIClient.js/,
            /.*\/data\/AuthManager.js/,
            /.*\/data\/APIClientFactory.js/,
            /.*\/data\/ApiPermissionValidation.js/,
            /.*\/data\/AuthManager.js/,
            /.*\/data\/ConfigManager.js/,
            /.*\/data\/ScopeValidation.jsx/,
            /.*\/data\/User.js/,
        ],
        loader: 'eslint-loader',
        options: {
            failOnError: true,
            quiet: true,
        },
    };
    config.module.rules.push(esLintLoader);
}

module.exports = function(env) {
    if (env && env.analysis) {
        var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
        config.plugins.push(new BundleAnalyzerPlugin());
    }
    return config;
};
/* eslint-enable */
<|endoftext|>


<commit_before>"use strict";

describe("navigator", function() {
  var navigator;
  var state;

  var s1 = {
    id: "1",
    tokens: {
      '01': {
        string: 'x',
      },
      '02': {
        string: 'y'
      }
    }
  };

  var s5 = {
    id: "5",
    tokens: {
      '01': {
        string: 'a',
      },
      '02': {
        string: 'b'
      }
    }
  };

  var sentences = [s1, s5];

  beforeEach(module("arethusa.core"));
  beforeEach(inject(function(_navigator_, _state_) {
    navigator = _navigator_;
    state = _state_;
    navigator.reset();
  }));

  describe("this.addSentences", function() {
    it('adds an array of sentencs to its internal containers', function() {
      navigator.addSentences(sentences);

      // an array of sentences
      expect(navigator.sentences.length).toEqual(2);
      expect(navigator.sentences[0]).toBe(s1);
      expect(navigator.sentences[1]).toBe(s5);

      // an object of sentences
      expect(navigator.sentencesById['1']).toBe(s1);
      expect(navigator.sentencesById['5']).toBe(s5);
    });
  });

  describe('this.currentSentence', function() {
    it('returns the tokens of the current sentence', function() {
      navigator.addSentences(sentences);
      expect(navigator.currentSentence()).toBe(s1.tokens);
    });
  });

  describe('this.state', function() {
    it('returns the state object', function() {
      expect(navigator.state()).toBe(state);
    });
  });
});
<commit_msg>Mark functions as functions in navigator specs<commit_after>"use strict";

describe("navigator", function() {
  var navigator;
  var state;

  var s1 = {
    id: "1",
    tokens: {
      '01': {
        string: 'x',
      },
      '02': {
        string: 'y'
      }
    }
  };

  var s5 = {
    id: "5",
    tokens: {
      '01': {
        string: 'a',
      },
      '02': {
        string: 'b'
      }
    }
  };

  var sentences = [s1, s5];

  beforeEach(module("arethusa.core"));
  beforeEach(inject(function(_navigator_, _state_) {
    navigator = _navigator_;
    state = _state_;
    navigator.reset();
  }));

  describe("this.addSentences()", function() {
    it('adds an array of sentencs to its internal containers', function() {
      navigator.addSentences(sentences);

      // an array of sentences
      expect(navigator.sentences.length).toEqual(2);
      expect(navigator.sentences[0]).toBe(s1);
      expect(navigator.sentences[1]).toBe(s5);

      // an object of sentences
      expect(navigator.sentencesById['1']).toBe(s1);
      expect(navigator.sentencesById['5']).toBe(s5);
    });
  });

  describe('this.currentSentence()', function() {
    it('returns the tokens of the current sentence', function() {
      navigator.addSentences(sentences);
      expect(navigator.currentSentence()).toBe(s1.tokens);
    });
  });

  describe('this.state()', function() {
    it('returns the state object', function() {
      expect(navigator.state()).toBe(state);
    });
  });
});
<|endoftext|>


<commit_before>"use strict";

/**
 * Page revision API module
 *
 * Main tasks:
 * - keep track of titles, and provide listings for them
 * - keep track of MediaWiki revisions and their metadata
 * - translate MediaWiki revisions into timeuuid ranges for property queries
 * - detect edit conflicts
 */

var rbUtil = require('../lib/rbUtil.js');
var URI = require('swagger-router').URI;

// TODO: move to module
var fs = require('fs');
var yaml = require('js-yaml');
var spec = yaml.safeLoad(fs.readFileSync(__dirname + '/page_revisions.yaml'));

// Title Revision Service
function PRS (options) {
    this.options = options;
    this.log = options.log || function(){};
}

PRS.prototype.tableName = 'title_revisions';
PRS.prototype.tableURI = function(domain) {
    return new URI([domain,'sys','table',this.tableName,'']);
};

// Get the schema for the revision table
PRS.prototype.getTableSchema = function () {
    return {
        table: this.tableName,
        attributes: {
            // listing: /titles.rev/Barack_Obama/master/
            // @specific time: /titles.rev/Barack_Obama?ts=20140312T20:22:33.3Z
            title: 'string',
            rev: 'int',             // MediaWiki oldid
            latest_rev: 'int',      // Latest MediaWiki revision
            tid: 'timeuuid',
            // revision deletion or suppression, can be:
            // - sha1hidden, commenthidden, texthidden
            restrictions: 'set<string>',
            // Revision tags. Examples:
            // - minor revision
            tags: 'set<string>',
            // Page renames. null, to:destination or from:source
            // Followed for linear history, possibly useful for branches / drafts
            renames: 'set<string>',
            nextrev_tid: 'timeuuid',// tid of next revision, or null
            latest_tid: 'timeuuid', // static, CAS synchronization point
            // revision metadata in individual attributes for ease of indexing
            user_id: 'int',         // stable for contributions etc
            user_text: 'string',
            comment: 'string'
        },
        index: [
            { attribute: 'title', type: 'hash' },
            { attribute: 'rev', type: 'range', order: 'desc' },
            { attribute: 'latest_rev', type: 'static' },
            { attribute: 'tid', type: 'range', order: 'desc' }
        ],
        secondaryIndexes: {
            by_rev: [
                { attribute: 'rev', type: 'hash' },
                { attribute: 'tid', type: 'range', order: 'desc' },
                { attribute: 'title', type: 'range', order: 'asc' },
                { attribute: 'restrictions', type: 'proj' }
            ]
        }
    };
};

/**
 * Checks the revision info returned from the storage
 * for restrictions, and if there are any, raises an error
 *
 * @param res Object the result as returned from storage
 * @return Object the same object
 * @throws rbUtil.httpError if access to the revision should be denied
 */
PRS.prototype._checkRevReturn = function(res) {
    var item = res && res.body && Array.isArray(res.body.items) && res.body.items[0];
    // if there are any restrictions imposed on this
    // revision, forbid its retrieval, cf.
    // https://phabricator.wikimedia.org/T76165#1030962
    if (item && Array.isArray(item.restrictions) && item.restrictions.length > 0) {
        // there are some restrictions, deny access to the revision
        return Promise.reject(new rbUtil.HTTPError({
            status: 403,
            body: {
                type: 'access_denied#revision',
                title: 'Access to resource denied',
                description: 'Access is restricted for revision ' + item.rev,
                restrictions: item.restrictions
            }
        }));
    }
    return Promise.resolve(res);
}

// /page/
PRS.prototype.listTitles = function(restbase, req, options) {
    var rp = req.params;
    var listReq = {
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            proj: ['title'],
            distinct: true
        }
    };

    return restbase.get(listReq)
    .then(function(res) {
        if (res.status === 200) {
            res.body.items = res.body.items.map(function(row) {
                return row.title;
            });
        }
        return res;
    });
};

PRS.prototype.fetchAndStoreMWRevision = function (restbase, req) {
    var self = this;
    var rp = req.params;
    // Try to resolve MW oldids to tids
    var apiReq = {
        uri: new URI([rp.domain,'sys','action','query']),
        body: {
            format: 'json',
            action: 'query',
            prop: 'revisions',
            continue: '',
            rvprop: 'ids|timestamp|user|userid|size|sha1|contentmodel|comment|tags'
        }
    };
    if (/^[0-9]+$/.test(rp.revision)) {
        apiReq.body.revids = rp.revision;
    } else {
        apiReq.body.titles = rp.title;
    }
    return restbase.post(apiReq)
    .then(function(apiRes) {
        var items = apiRes.body.items;
        if (!items.length || !items[0].revisions) {
            throw new rbUtil.HTTPError({
                status: 404,
                body: {
                    type: 'not_found#page_revisions',
                    description: 'Page or revision not found.',
                    apiResponse: apiRes
                }
            });
        }
        // the response item
        var dataResp = apiRes.body.items[0];
        // the revision info
        var apiRev = dataResp.revisions[0];
        // are there any restrictions set?
        var restrictions = Object.keys(apiRev).filter(function(key) { return /hidden$/.test(key) });
        // the tid to store this info under
        var tid = rbUtil.tidFromDate(apiRev.timestamp);
        return restbase.put({ // Save / update the revision entry
            uri: self.tableURI(rp.domain),
            body: {
                table: self.tableName,
                attributes: {
                    // FIXME: if a title has been given, check it
                    // matches the one returned by the MW API
                    // cf. https://phabricator.wikimedia.org/T87393
                    title: dataResp.title,
                    rev: parseInt(apiRev.revid),
                    tid: tid,
                    user_id: apiRev.userid,
                    user_text: apiRev.user,
                    comment: apiRev.comment,
                    tags: apiRev.tags,
                    restrictions: restrictions
                }
            }
        })
        .then(function() {
            // if there are any restrictions imposed on this
            // revision, forbid its retrieval, cf.
            // https://phabricator.wikimedia.org/T76165#1030962
            if (restrictions && restrictions.length > 0) {
                return Promise.reject(new rbUtil.HTTPError({
                    status: 403,
                    body: {
                        type: 'access_denied#revision',
                        title: 'Access to resource denied',
                        description: 'Access is restricted for revision ' + apiRev.revid,
                        restrictions: restrictions
                    }
                }));
            }
            // no restrictions, continue
            rp.revision = apiRev.revid + '';
            rp.title = dataResp.title;
            return self.getTitleRevision(restbase, req);
        });
    }).catch(function(e) {
        // if a bad revision is supplied, the action module
        // returns a 500 with the 'Missing query pages' message
        // so catch that and turn it into a 404 in our case
        if(e.status === 500 && /^Missing query pages/.test(e.description)) {
            throw new rbUtil.HTTPError({
                status: 404,
                body: {
                    type: 'not_found#page_revisions',
                    description: 'Page or revision not found.',
                    apiRequest: apiReq
                }
            });
        }
        throw e;
    });
};

PRS.prototype.getTitleRevision = function(restbase, req) {
    var self = this;
    var rp = req.params;
    var revisionRequest;
    if (/^[0-9]+$/.test(rp.revision)) {
        // Check the local db
        revisionRequest = restbase.get({
            uri: this.tableURI(rp.domain),
            body: {
                table: this.tableName,
                attributes: {
                    title: rp.title,
                    rev: parseInt(rp.revision)
                },
                limit: 1
            }
        })
        .catch(function(e) {
            if (e.status !== 404) {
                throw e;
            }
            return self.fetchAndStoreMWRevision(restbase, req);
        });
    } else if (rp.revision === 'latest') {
        revisionRequest = self.fetchAndStoreMWRevision(restbase, req);
    } else {
        throw new Error("Invalid revision: " + rp.revision);
    }
    return revisionRequest
    .then(self._checkRevReturn)
    .then(function(res) {
        if (!res.headers) {
            res.headers = {};
        }
        res.headers.etag = res.body.items[0].tid;
        return res;
    });
    // TODO: handle other revision formats (tid)
};

PRS.prototype.listTitleRevisions = function(restbase, req) {
    var rp = req.params;
    return restbase.get({
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            attributes: {
                title: rp.title
            },
            proj: ['rev']
        }
    })
    .then(function(res) {
        // Flatten to an array of revisions rather than an array of objects
        res.body.items = res.body.items.map(function(row) {
            return row.rev;
        });
        return res;
    });
};

// /rev/
PRS.prototype.listRevisions = function(restbase, req) {
    var rp = req.params;
    var listReq = {
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            index: 'by_rev',
            proj: ['rev'],
            distinct: true
        }
    };
    return restbase.get(listReq)
    .then(function(res) {
        if (res.status === 200) {
            res.body.items = res.body.items.map(function(row) {
                return row.rev;
            });
        }
        return res;
    });
};

PRS.prototype.getRevision = function(restbase, req) {
    var rp = req.params;
    var self = this;
    // sanity check
    if (!/^[0-9]+$/.test(rp.revision)) {
        throw new rbUtil.HTTPError({
            status: 400,
            body: {
                type: 'invalidRevision',
                description: 'Invalid revision specified.'
            }
        });
    }
    if (req.headers && /no-cache/.test(req.headers['cache-control'])) {
        // ask the MW API directly and
        // store and return its result
        return this.fetchAndStoreMWRevision(restbase, req);
    }
    // check the storage, and, if no match is found
    // ask the MW API about the revision
    return restbase.get({
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            index: 'by_rev',
            attributes: {
                rev: parseInt(rp.revision)
            },
            limit: 1
        }
    })
    .then(self._checkRevReturn)
    .catch(function(e) {
        if (e.status !== 404) {
            throw e;
        }
        return self.fetchAndStoreMWRevision(restbase, req);
    });
};

module.exports = function(options) {
    var prs = new PRS(options);
    // XXX: add docs
    return {
        spec: spec,
        operations: {
            listTitles: prs.listTitles.bind(prs),
            listTitleRevisions: prs.listTitleRevisions.bind(prs),
            getTitleRevision: prs.getTitleRevision.bind(prs),
            //getTitleRevisionId: prs.getTitleRevisionId.bind(prs)
            listRevisions: prs.listRevisions.bind(prs),
            getRevision: prs.getRevision.bind(prs)
        },
        resources: [
            {
                // Revision table
                uri: '/{domain}/sys/table/' + prs.tableName,
                body: prs.getTableSchema()
            }
        ]
    };
};
<commit_msg>Minor fixes from #172<commit_after>"use strict";

/**
 * Page revision API module
 *
 * Main tasks:
 * - keep track of titles, and provide listings for them
 * - keep track of MediaWiki revisions and their metadata
 * - translate MediaWiki revisions into timeuuid ranges for property queries
 * - detect edit conflicts
 */

var rbUtil = require('../lib/rbUtil.js');
var URI = require('swagger-router').URI;

// TODO: move to module
var fs = require('fs');
var yaml = require('js-yaml');
var spec = yaml.safeLoad(fs.readFileSync(__dirname + '/page_revisions.yaml'));

// Title Revision Service
function PRS (options) {
    this.options = options;
    this.log = options.log || function(){};
}

PRS.prototype.tableName = 'title_revisions';
PRS.prototype.tableURI = function(domain) {
    return new URI([domain,'sys','table',this.tableName,'']);
};

// Get the schema for the revision table
PRS.prototype.getTableSchema = function () {
    return {
        table: this.tableName,
        attributes: {
            // listing: /titles.rev/Barack_Obama/master/
            // @specific time: /titles.rev/Barack_Obama?ts=20140312T20:22:33.3Z
            title: 'string',
            rev: 'int',             // MediaWiki oldid
            latest_rev: 'int',      // Latest MediaWiki revision
            tid: 'timeuuid',
            // revision deletion or suppression, can be:
            // - sha1hidden, commenthidden, texthidden
            restrictions: 'set<string>',
            // Revision tags. Examples:
            // - minor revision
            tags: 'set<string>',
            // Page renames. null, to:destination or from:source
            // Followed for linear history, possibly useful for branches / drafts
            renames: 'set<string>',
            nextrev_tid: 'timeuuid',// tid of next revision, or null
            latest_tid: 'timeuuid', // static, CAS synchronization point
            // revision metadata in individual attributes for ease of indexing
            user_id: 'int',         // stable for contributions etc
            user_text: 'string',
            comment: 'string'
        },
        index: [
            { attribute: 'title', type: 'hash' },
            { attribute: 'rev', type: 'range', order: 'desc' },
            { attribute: 'latest_rev', type: 'static' },
            { attribute: 'tid', type: 'range', order: 'desc' }
        ],
        secondaryIndexes: {
            by_rev: [
                { attribute: 'rev', type: 'hash' },
                { attribute: 'tid', type: 'range', order: 'desc' },
                { attribute: 'title', type: 'range', order: 'asc' },
                { attribute: 'restrictions', type: 'proj' }
            ]
        }
    };
};

/**
 * Checks the revision info returned from the storage
 * for restrictions, and if there are any, raises an error
 *
 * @param res Object the result as returned from storage
 * @return Object the same object
 * @throws rbUtil.httpError if access to the revision should be denied
 */
PRS.prototype._checkRevReturn = function(res) {
    var item = res.body.items.length && res.body.items[0];
    // if there are any restrictions imposed on this
    // revision, forbid its retrieval, cf.
    // https://phabricator.wikimedia.org/T76165#1030962
    if (item && Array.isArray(item.restrictions) && item.restrictions.length > 0) {
        // there are some restrictions, deny access to the revision
        throw new rbUtil.HTTPError({
            status: 403,
            body: {
                type: 'access_denied#revision',
                title: 'Access to resource denied',
                description: 'Access is restricted for revision ' + item.rev,
                restrictions: item.restrictions
            }
        });
    }
    return Promise.resolve(res);
}

// /page/
PRS.prototype.listTitles = function(restbase, req, options) {
    var rp = req.params;
    var listReq = {
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            proj: ['title'],
            distinct: true
        }
    };

    return restbase.get(listReq)
    .then(function(res) {
        if (res.status === 200) {
            res.body.items = res.body.items.map(function(row) {
                return row.title;
            });
        }
        return res;
    });
};

PRS.prototype.fetchAndStoreMWRevision = function (restbase, req) {
    var self = this;
    var rp = req.params;
    // Try to resolve MW oldids to tids
    var apiReq = {
        uri: new URI([rp.domain,'sys','action','query']),
        body: {
            format: 'json',
            action: 'query',
            prop: 'revisions',
            continue: '',
            rvprop: 'ids|timestamp|user|userid|size|sha1|contentmodel|comment|tags'
        }
    };
    if (/^[0-9]+$/.test(rp.revision)) {
        apiReq.body.revids = rp.revision;
    } else {
        apiReq.body.titles = rp.title;
    }
    return restbase.post(apiReq)
    .then(function(apiRes) {
        var items = apiRes.body.items;
        if (!items.length || !items[0].revisions) {
            throw new rbUtil.HTTPError({
                status: 404,
                body: {
                    type: 'not_found#page_revisions',
                    description: 'Page or revision not found.',
                    apiResponse: apiRes
                }
            });
        }
        // the response item
        var dataResp = apiRes.body.items[0];
        // the revision info
        var apiRev = dataResp.revisions[0];
        // are there any restrictions set?
        var restrictions = Object.keys(apiRev).filter(function(key) { return /hidden$/.test(key) });
        // the tid to store this info under
        var tid = rbUtil.tidFromDate(apiRev.timestamp);
        return restbase.put({ // Save / update the revision entry
            uri: self.tableURI(rp.domain),
            body: {
                table: self.tableName,
                attributes: {
                    // FIXME: if a title has been given, check it
                    // matches the one returned by the MW API
                    // cf. https://phabricator.wikimedia.org/T87393
                    title: dataResp.title,
                    rev: parseInt(apiRev.revid),
                    tid: tid,
                    user_id: apiRev.userid,
                    user_text: apiRev.user,
                    comment: apiRev.comment,
                    tags: apiRev.tags,
                    restrictions: restrictions
                }
            }
        })
        .then(function() {
            // if there are any restrictions imposed on this
            // revision, forbid its retrieval, cf.
            // https://phabricator.wikimedia.org/T76165#1030962
            if (restrictions && restrictions.length > 0) {
                return Promise.reject(new rbUtil.HTTPError({
                    status: 403,
                    body: {
                        type: 'access_denied#revision',
                        title: 'Access to resource denied',
                        description: 'Access is restricted for revision ' + apiRev.revid,
                        restrictions: restrictions
                    }
                }));
            }
            // no restrictions, continue
            rp.revision = apiRev.revid + '';
            rp.title = dataResp.title;
            return self.getTitleRevision(restbase, req);
        });
    }).catch(function(e) {
        // if a bad revision is supplied, the action module
        // returns a 500 with the 'Missing query pages' message
        // so catch that and turn it into a 404 in our case
        if(e.status === 500 && /^Missing query pages/.test(e.description)) {
            throw new rbUtil.HTTPError({
                status: 404,
                body: {
                    type: 'not_found#page_revisions',
                    description: 'Page or revision not found.',
                    apiRequest: apiReq
                }
            });
        }
        throw e;
    });
};

PRS.prototype.getTitleRevision = function(restbase, req) {
    var self = this;
    var rp = req.params;
    var revisionRequest;
    if (/^[0-9]+$/.test(rp.revision)) {
        // Check the local db
        revisionRequest = restbase.get({
            uri: this.tableURI(rp.domain),
            body: {
                table: this.tableName,
                attributes: {
                    title: rp.title,
                    rev: parseInt(rp.revision)
                },
                limit: 1
            }
        })
        .catch(function(e) {
            if (e.status !== 404) {
                throw e;
            }
            return self.fetchAndStoreMWRevision(restbase, req);
        });
    } else if (rp.revision === 'latest') {
        revisionRequest = self.fetchAndStoreMWRevision(restbase, req);
    } else {
        throw new Error("Invalid revision: " + rp.revision);
    }
    return revisionRequest
    .then(function(res) {
        // check if the revision has any restrictions
        self._checkRevReturn(res);
        if (!res.headers) {
            res.headers = {};
        }
        res.headers.etag = res.body.items[0].tid;
        return res;
    });
    // TODO: handle other revision formats (tid)
};

PRS.prototype.listTitleRevisions = function(restbase, req) {
    var rp = req.params;
    return restbase.get({
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            attributes: {
                title: rp.title
            },
            proj: ['rev']
        }
    })
    .then(function(res) {
        // Flatten to an array of revisions rather than an array of objects
        res.body.items = res.body.items.map(function(row) {
            return row.rev;
        });
        return res;
    });
};

// /rev/
PRS.prototype.listRevisions = function(restbase, req) {
    var rp = req.params;
    var listReq = {
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            index: 'by_rev',
            proj: ['rev'],
            distinct: true
        }
    };
    return restbase.get(listReq)
    .then(function(res) {
        if (res.status === 200) {
            res.body.items = res.body.items.map(function(row) {
                return row.rev;
            });
        }
        return res;
    });
};

PRS.prototype.getRevision = function(restbase, req) {
    var rp = req.params;
    var self = this;
    // sanity check
    if (!/^[0-9]+$/.test(rp.revision)) {
        throw new rbUtil.HTTPError({
            status: 400,
            body: {
                type: 'invalidRevision',
                description: 'Invalid revision specified.'
            }
        });
    }
    if (req.headers && /no-cache/.test(req.headers['cache-control'])) {
        // ask the MW API directly and
        // store and return its result
        return this.fetchAndStoreMWRevision(restbase, req);
    }
    // check the storage, and, if no match is found
    // ask the MW API about the revision
    return restbase.get({
        uri: this.tableURI(rp.domain),
        body: {
            table: this.tableName,
            index: 'by_rev',
            attributes: {
                rev: parseInt(rp.revision)
            },
            limit: 1
        }
    })
    .then(self._checkRevReturn)
    .catch(function(e) {
        if (e.status !== 404) {
            throw e;
        }
        return self.fetchAndStoreMWRevision(restbase, req);
    });
};

module.exports = function(options) {
    var prs = new PRS(options);
    // XXX: add docs
    return {
        spec: spec,
        operations: {
            listTitles: prs.listTitles.bind(prs),
            listTitleRevisions: prs.listTitleRevisions.bind(prs),
            getTitleRevision: prs.getTitleRevision.bind(prs),
            //getTitleRevisionId: prs.getTitleRevisionId.bind(prs)
            listRevisions: prs.listRevisions.bind(prs),
            getRevision: prs.getRevision.bind(prs)
        },
        resources: [
            {
                // Revision table
                uri: '/{domain}/sys/table/' + prs.tableName,
                body: prs.getTableSchema()
            }
        ]
    };
};
<|endoftext|>


<commit_before>import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';

const Book = function (props) {
  const { book } = props;

  var bookShelf = book.shelf;

  if (bookShelf === undefined) {
    bookShelf = "none";
  }

  return (

          <Link to={"/book/" + book.id}>

          </Link>

        <Link to={"/pick-book-shelf?bookId=" + book.id + "&bookShelf=" + book.shelf}>

</Link>

{bookShelf}

{book.title}

{(Array.isArray(book.authors)) && book.authors.map((author, idx) =>
{author}
)}

  );
}

Book.propTypes = {
  book: PropTypes.object.isRequired
}

export default Book<commit_msg>Book > Added select for shelf selection<commit_after>import React from 'react';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';

const Book = function (props) {
  const { book } = props;

  var bookShelf = book.shelf;

  if (bookShelf === undefined) {
    bookShelf = "none";
  }

  /*
          <Link to={"/pick-book-shelf?bookId=" + book.id + "&bookShelf=" + book.shelf}>

</Link>
  */

  return (

          <Link to={"/book/" + book.id}>

          </Link>

          <select>
            <option value="none" disabled>Move to...</option>
            <option value="currentlyReading">Currently Reading</option>
            <option value="wantToRead">Want to Read</option>
            <option value="read">Read</option>
            <option value="none">None</option>
          </select>

{bookShelf}

{book.title}

{(Array.isArray(book.authors)) && book.authors.map((author, idx) =>
{author}
)}

  );
}

Book.propTypes = {
  book: PropTypes.object.isRequired
}

export default Book<|endoftext|>


<commit_before>'use strict';

const runFactors = (bot, event, context) => {
  if (!event.queryStringParameters) {
    return Promise.resolve( { statusCode: 403, body: 'Expected something else'} );
  }
  const redirect = event.queryStringParameters['redirect_uri'];
  const address = event.queryStringParameters['address'];
  const token = event.queryStringParameters['account_linking_token'];
  var phone = event.queryStringParameters['phone'];
  const path = event.path;

  if (path === '/factor2') {
    phone = `+${unescape(phone)}`;
    let code = event.queryStringParameters['code'];
    console.log('Logging in with', phone, code)
    return requests.login(phone, code)
      .then( (response) => {
      const retVal = {
        statusCode: 301,
        body: '',
        headers: {
          'Content-Type': 'text/html',
          Location: `${FIRST_FACTOR_URL}?${utils.concatenateQueryString(event.queryStringParameters)}`
        }
      };
      var address = JSON.parse(event.queryStringParameters.address);
      return new Promise( (resolve, reject) => {
        bot.beginDialog(address, '/persistUserData', response, (error, resp) => {
          if (error) {
            console.log('ERROR: Redirecting to', retVal.headers.Location);
            return reject(retVal);
          }
          console.log('SUCCESS: Redirecting to', retVal.headers.Location);
          retVal.Location = `${redirect}&authorization_code=${phone.replace('+', '')}`;
          return resolve(retVal);
        });
      });
    });
  } else if (path === '/factor1') {

    phone = unescape(phone);
    console.log('requesting code for', phone)

    return requests.requestCode(phone)
      .then( (response, body) => {
      const retVal = {
        statusCode: 301,
        body: '',
      };

      //res.redirect(SECOND_FACTOR_URL + '?' + queryString + '&phone=' + phone , next);
      retVal.headers = {
        Location: `${SECOND_FACTOR_URL}?${utils.concatenateQueryString(event.queryStringParameters)}`
      }
      console.log('Redirecting to', retVal.headers);
      retVal.body = '';
      return retVal;
    })
    .catch( err => {
      return {
        statusCode: 301,
        headers: {
          Location: `${FIRST_FACTOR_URL}?${utils.concatenateQueryString(event.queryStringParameters)}`
        }
      }
    });

  } else {
    return Promise.reject({ statusCode: 404 });
  }
};

module.exports = runFactors;<commit_msg>Fixed the missing require<commit_after>'use strict';
const requests = require('./requests');

const runFactors = (bot, event, context) => {
  if (!event.queryStringParameters) {
    return Promise.resolve( { statusCode: 403, body: 'Expected something else'} );
  }
  const redirect = event.queryStringParameters['redirect_uri'];
  const address = event.queryStringParameters['address'];
  const token = event.queryStringParameters['account_linking_token'];
  var phone = event.queryStringParameters['phone'];
  const path = event.path;

  if (path === '/factor2') {
    phone = `+${unescape(phone)}`;
    let code = event.queryStringParameters['code'];
    console.log('Logging in with', phone, code)
    return requests.login(phone, code)
      .then( (response) => {
      const retVal = {
        statusCode: 301,
        body: '',
        headers: {
          'Content-Type': 'text/html',
          Location: `${FIRST_FACTOR_URL}?${utils.concatenateQueryString(event.queryStringParameters)}`
        }
      };
      var address = JSON.parse(event.queryStringParameters.address);
      return new Promise( (resolve, reject) => {
        bot.beginDialog(address, '/persistUserData', response, (error, resp) => {
          if (error) {
            console.log('ERROR: Redirecting to', retVal.headers.Location);
            return reject(retVal);
          }
          console.log('SUCCESS: Redirecting to', retVal.headers.Location);
          retVal.Location = `${redirect}&authorization_code=${phone.replace('+', '')}`;
          return resolve(retVal);
        });
      });
    });
  } else if (path === '/factor1') {

    phone = unescape(phone);
    console.log('requesting code for', phone)

    return requests.requestCode(phone)
      .then( (response, body) => {
      const retVal = {
        statusCode: 301,
        body: '',
      };

      //res.redirect(SECOND_FACTOR_URL + '?' + queryString + '&phone=' + phone , next);
      retVal.headers = {
        Location: `${SECOND_FACTOR_URL}?${utils.concatenateQueryString(event.queryStringParameters)}`
      }
      console.log('Redirecting to', retVal.headers);
      retVal.body = '';
      return retVal;
    })
    .catch( err => {
      return {
        statusCode: 301,
        headers: {
          Location: `${FIRST_FACTOR_URL}?${utils.concatenateQueryString(event.queryStringParameters)}`
        }
      }
    });

  } else {
    return Promise.reject({ statusCode: 404 });
  }
};

module.exports = runFactors;<|endoftext|>


<commit_before>
Vps.onContentReady(function() {

    var lightbox = new Vpc.Basic.ImageEnlarge();
    var els = document.getElementsByTagName('a');
    for (var i=0; i<els.length; i++) {
        if (els[i].rel.match(/enlarge_[0-9]+_[0-9]+/)) {
            Ext.EventManager.addListener(els[i], 'click', function(e) {
                lightbox.show(Ext.get(this), e);
                e.stopEvent();
            }, els[i], { stopEvent: true });
        }
    }
});

Ext.namespace("Vpc.Basic");

Vpc.Basic.ImageEnlarge = function()
{
    this.lightbox = Ext.get(
        Ext.DomHelper.append(Ext.getBody(),
            { tag: 'div', cls: 'lightbox webLightbox webStandard' }
        )
    );
};

Vpc.Basic.ImageEnlarge.tpl = new Ext.XTemplate(
    '
{header}
',
    '
{body}</div',
    '
{footer}</div'
);

Vpc.Basic.ImageEnlarge.tplHeader = new Ext.XTemplate(
    '',
        ''+trlVps('close')+' X',
    '',
    '{fullSizeLink}'
);

Vpc.Basic.ImageEnlarge.tplBody = new Ext.XTemplate(
    '',
    '{nextImageBig}',
    '{previousImageBig}'
);
Vpc.Basic.ImageEnlarge.tplFooter = new Ext.XTemplate(
    '{nextImageButton}',
    '
{title}
',
    '{previousImageButton}'
);

Vpc.Basic.ImageEnlarge.tplSwitchBig = new Ext.XTemplate(
    '
',
        '
',
            '
<tpl if="type==\'previous\'">« </tpl>{text}<tpl if="type==\'next\'"> »</tpl>
',
            '',
            '
{[fm.ellipsis(values.title, 18)]}
',
        '
',
    '
'
);

Vpc.Basic.ImageEnlarge.tplSwitchButton = new Ext.XTemplate(
    '',
        '<tpl if="type==\'previous\'">« </tpl>{text}<tpl if="type==\'next\'"> »</tpl>',
    ''
);

Vpc.Basic.ImageEnlarge.prototype =
{

    hide: function(e)
    {
        if (e) e.stopEvent();
        this.lightbox.applyStyles('display: none;');
        this.unmask();
    },

    show: function(linkEl)
    {
        this.mask();

        this.lightbox.applyStyles('display: block;');
        this.lightbox.center();

        var m = linkEl.dom.rel.match(/enlarge_([0-9]+)_([0-9]+)_?([^ ]*)/);

        var data = {};
        if (m[3]) {
            data.fullSizeLink = ' ';
        } else {
            data.fullSizeLink = '';
        }
        data.title = linkEl.dom.title ? linkEl.dom.title : ' ';
        data.image = {
            src: linkEl.dom.href,
            width: parseInt(m[1]),
            height: parseInt(m[2])
        };
        if (linkEl.nextImage) {
            data.nextImage = {
                src: linkEl.nextImage.child('img').dom.src,
                title: linkEl.nextImage.dom.title,
                type: 'next',
                text: trlVps('next')
            };
        }
        if (linkEl.previousImage) {
            data.previousImage = {
                src: linkEl.previousImage.child('img').dom.src,
                title: linkEl.previousImage.dom.title,
                type: 'previous',
                text: trlVps('previous')
            };
        }

        var tpls = Vpc.Basic.ImageEnlarge;
        if (data.nextImage) {
            data.nextImageButton = tpls.tplSwitchButton.apply(data.nextImage);
            data.nextImageBig = tpls.tplSwitchBig.apply(data.nextImage);
        }
        if (data.previousImage) {
            data.previousImageButton = tpls.tplSwitchButton.apply(data.previousImage);
            data.previousImageBig = tpls.tplSwitchBig.apply(data.previousImage);
        }
        data.header = tpls.tplHeader.apply(data);
        data.footer = tpls.tplFooter.apply(data);
        data.body = tpls.tplBody.apply(data);

        tpls.tpl.overwrite(this.lightbox, data);

        var applyNexPreviousEvents = function(imageLink, type) {
            // preload next image
            var tmpNextImage = new Image();
            tmpNextImage.src = imageLink.dom.href;

            // overlay next button
            this.lightbox.query('.'+type+'SwitchBig').each(function(el) {
                el = Ext.get(el);
                el.on('click', function(e) {
                    this.lightbox.show(this.imageLink);
                }, {lightbox: this, imageLink: imageLink}, { stopEvent: true });
                el.on('mouseover', function(e) {
                    this.addClass('bigOver');
                }, el);
                el.on('mouseout', function(e) {
                    this.removeClass('bigOver');
                }, el);
            }, this);
            // next small button
            this.lightbox.query('.'+type+'SwitchButton').each(function(el) {
                el = Ext.fly(el);
                el.on('click', function(e) {
                    this.show(linkEl.nextImage);
                }, this, { stopEvent: true });
            }, this);
        };

        if (linkEl.nextImage) {
            applyNexPreviousEvents.call(this, linkEl.nextImage, 'next');
        }
        if (linkEl.previousImage) {
            applyNexPreviousEvents.call(this, linkEl.previousImage, 'previous');
        }

        this.lightbox.query('.closeButton').each(function(el) {
            el = Ext.fly(el);
            el.on('click', this.hide, this, { stopEvent: true });
        }, this);

        this.lightbox.query('.lightboxBody img.centerImage').each(function(img) {
            img = Ext.fly(img);
            var imageTopMargin = (img.parent('.lightboxBody').getHeight() - img.getHeight()) / 2;
            if (imageTopMargin < 0) imageTopMargin = 0;
            img.setStyle('margin-top', imageTopMargin+'px');
        }, this);
    },

    mask: function()
    {
        var maskEl = Ext.getBody().mask();
        Ext.getBody().removeClass('x-masked');
        maskEl.addClass('lightboxMask');
        maskEl.applyStyles('height:'+this.getPageSize()[1]+'px;');
        maskEl.on('click', this.hide, this);
    },

    unmask: function()
    {
        Ext.getBody().unmask();
        Ext.getBody().removeClass('lightboxShowOverflow');
    },

    getPageSize: function()
    {
        var xScroll, yScroll;

        if (window.innerHeight && window.scrollMaxY) {
            xScroll = window.innerWidth + window.scrollMaxX;
            yScroll = window.innerHeight + window.scrollMaxY;
        } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
            xScroll = document.body.scrollWidth;
            yScroll = document.body.scrollHeight;
        } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
            xScroll = document.body.offsetWidth;
            yScroll = document.body.offsetHeight;
        }

        var windowWidth, windowHeight;

        if (self.innerHeight) { // all except Explorer
            if(document.documentElement.clientWidth){
                windowWidth = document.documentElement.clientWidth;
            } else {
                windowWidth = self.innerWidth;
            }
            windowHeight = self.innerHeight;
        } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
            windowWidth = document.documentElement.clientWidth;
            windowHeight = document.documentElement.clientHeight;
        } else if (document.body) { // other Explorers
            windowWidth = document.body.clientWidth;
            windowHeight = document.body.clientHeight;
        }

        // for small pages with total height less then height of the viewport
        if(yScroll < windowHeight){
            pageHeight = windowHeight;
        } else {
            pageHeight = yScroll;
        }

        // for small pages with total width less then width of the viewport
        if(xScroll < windowWidth){
            pageWidth = xScroll;
        } else {
            pageWidth = windowWidth;
        }

        arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight)
        return arrayPageSize;
    }
};
<commit_msg>- lightbox styling bugfix @ IE<commit_after>
Vps.onContentReady(function() {

    var lightbox = new Vpc.Basic.ImageEnlarge();
    var els = document.getElementsByTagName('a');
    for (var i=0; i<els.length; i++) {
        if (els[i].rel.match(/enlarge_[0-9]+_[0-9]+/)) {
            Ext.EventManager.addListener(els[i], 'click', function(e) {
                lightbox.show(Ext.get(this), e);
                e.stopEvent();
            }, els[i], { stopEvent: true });
        }
    }
});

Ext.namespace("Vpc.Basic");

Vpc.Basic.ImageEnlarge = function()
{
    this.lightbox = Ext.get(
        Ext.DomHelper.append(Ext.getBody(),
            { tag: 'div', cls: 'lightbox webLightbox webStandard' }
        )
    );
};

Vpc.Basic.ImageEnlarge.tpl = new Ext.XTemplate(
    '
{header}
',
    '
{body}</div',
    '

',
    '
{footer}</div'
);

Vpc.Basic.ImageEnlarge.tplHeader = new Ext.XTemplate(
    '',
        ''+trlVps('close')+' X',
    '',
    '{fullSizeLink}'
);

Vpc.Basic.ImageEnlarge.tplBody = new Ext.XTemplate(
    '',
    '{nextImageBig}',
    '{previousImageBig}'
);
Vpc.Basic.ImageEnlarge.tplFooter = new Ext.XTemplate(
    '{nextImageButton}',
    '
{title}
',
    '{previousImageButton}'
);

Vpc.Basic.ImageEnlarge.tplSwitchBig = new Ext.XTemplate(
    '
',
        '
',
            '
<tpl if="type==\'previous\'">« </tpl>{text}<tpl if="type==\'next\'"> »</tpl>
',
            '',
            '
{[fm.ellipsis(values.title, 18)]}
',
        '
',
    '
'
);

Vpc.Basic.ImageEnlarge.tplSwitchButton = new Ext.XTemplate(
    '',
        '<tpl if="type==\'previous\'">« </tpl>{text}<tpl if="type==\'next\'"> »</tpl>',
    ''
);

Vpc.Basic.ImageEnlarge.prototype =
{

    hide: function(e)
    {
        if (e) e.stopEvent();
        this.lightbox.applyStyles('display: none;');
        this.unmask();
    },

    show: function(linkEl)
    {
        this.mask();

        this.lightbox.applyStyles('display: block;');
        this.lightbox.center();

        var m = linkEl.dom.rel.match(/enlarge_([0-9]+)_([0-9]+)_?([^ ]*)/);

        var data = {};
        if (m[3]) {
            data.fullSizeLink = ' ';
        } else {
            data.fullSizeLink = '';
        }
        data.title = linkEl.dom.title ? linkEl.dom.title : ' ';
        data.image = {
            src: linkEl.dom.href,
            width: parseInt(m[1]),
            height: parseInt(m[2])
        };
        if (linkEl.nextImage) {
            data.nextImage = {
                src: linkEl.nextImage.child('img').dom.src,
                title: linkEl.nextImage.dom.title,
                type: 'next',
                text: trlVps('next')
            };
        }
        if (linkEl.previousImage) {
            data.previousImage = {
                src: linkEl.previousImage.child('img').dom.src,
                title: linkEl.previousImage.dom.title,
                type: 'previous',
                text: trlVps('previous')
            };
        }

        var tpls = Vpc.Basic.ImageEnlarge;
        if (data.nextImage) {
            data.nextImageButton = tpls.tplSwitchButton.apply(data.nextImage);
            data.nextImageBig = tpls.tplSwitchBig.apply(data.nextImage);
        }
        if (data.previousImage) {
            data.previousImageButton = tpls.tplSwitchButton.apply(data.previousImage);
            data.previousImageBig = tpls.tplSwitchBig.apply(data.previousImage);
        }
        data.header = tpls.tplHeader.apply(data);
        data.footer = tpls.tplFooter.apply(data);
        data.body = tpls.tplBody.apply(data);

        tpls.tpl.overwrite(this.lightbox, data);

        var applyNexPreviousEvents = function(imageLink, type) {
            // preload next image
            var tmpNextImage = new Image();
            tmpNextImage.src = imageLink.dom.href;

            // overlay next button
            this.lightbox.query('.'+type+'SwitchBig').each(function(el) {
                el = Ext.get(el);
                el.on('click', function(e) {
                    this.lightbox.show(this.imageLink);
                }, {lightbox: this, imageLink: imageLink}, { stopEvent: true });
                el.on('mouseover', function(e) {
                    this.addClass('bigOver');
                }, el);
                el.on('mouseout', function(e) {
                    this.removeClass('bigOver');
                }, el);
            }, this);
            // next small button
            this.lightbox.query('.'+type+'SwitchButton').each(function(el) {
                el = Ext.fly(el);
                el.on('click', function(e) {
                    this.show(linkEl.nextImage);
                }, this, { stopEvent: true });
            }, this);
        };

        if (linkEl.nextImage) {
            applyNexPreviousEvents.call(this, linkEl.nextImage, 'next');
        }
        if (linkEl.previousImage) {
            applyNexPreviousEvents.call(this, linkEl.previousImage, 'previous');
        }

        this.lightbox.query('.closeButton').each(function(el) {
            el = Ext.fly(el);
            el.on('click', this.hide, this, { stopEvent: true });
        }, this);

        this.lightbox.query('.lightboxBody img.centerImage').each(function(img) {
            img = Ext.fly(img);
            var imageTopMargin = (img.parent('.lightboxBody').getHeight() - img.getHeight()) / 2;
            if (imageTopMargin < 0) imageTopMargin = 0;
            img.setStyle('margin-top', imageTopMargin+'px');
        }, this);
    },

    mask: function()
    {
        var maskEl = Ext.getBody().mask();
        Ext.getBody().removeClass('x-masked');
        maskEl.addClass('lightboxMask');
        maskEl.applyStyles('height:'+this.getPageSize()[1]+'px;');
        maskEl.on('click', this.hide, this);
    },

    unmask: function()
    {
        Ext.getBody().unmask();
        Ext.getBody().removeClass('lightboxShowOverflow');
    },

    getPageSize: function()
    {
        var xScroll, yScroll;

        if (window.innerHeight && window.scrollMaxY) {
            xScroll = window.innerWidth + window.scrollMaxX;
            yScroll = window.innerHeight + window.scrollMaxY;
        } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
            xScroll = document.body.scrollWidth;
            yScroll = document.body.scrollHeight;
        } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
            xScroll = document.body.offsetWidth;
            yScroll = document.body.offsetHeight;
        }

        var windowWidth, windowHeight;

        if (self.innerHeight) { // all except Explorer
            if(document.documentElement.clientWidth){
                windowWidth = document.documentElement.clientWidth;
            } else {
                windowWidth = self.innerWidth;
            }
            windowHeight = self.innerHeight;
        } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
            windowWidth = document.documentElement.clientWidth;
            windowHeight = document.documentElement.clientHeight;
        } else if (document.body) { // other Explorers
            windowWidth = document.body.clientWidth;
            windowHeight = document.body.clientHeight;
        }

        // for small pages with total height less then height of the viewport
        if(yScroll < windowHeight){
            pageHeight = windowHeight;
        } else {
            pageHeight = yScroll;
        }

        // for small pages with total width less then width of the viewport
        if(xScroll < windowWidth){
            pageWidth = xScroll;
        } else {
            pageWidth = windowWidth;
        }

        arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight)
        return arrayPageSize;
    }
};
<|endoftext|>


<commit_before>// @flow

import React, { Component } from 'react';
import StarRatingComponent from 'react-star-rating-component';
import styled from 'styled-components';

import {
	Card,
	CardActions,
	CardMedia,
	CardTitle,
	CardText
} from 'material-ui/Card';
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';
import RaisedButton from 'material-ui/RaisedButton';

import { update } from '../utils/BooksAPI';
import { getRating, setRating } from '../utils/RatingsAPI';
import type { BookType } from '../common/flowTypes';

const FlybraryBook = styled(Card)`
	flex-grow: 1;
	flex-shrink: 0;
	margin: 0 10px 12px;
	width: 90vw;
	min-width: 300px;
	max-width: 400px;
`;

const RatingWrapper = styled.div`
	margin-top: 20px;
	margin-bottom: 0px;
	padding-bottom: 0px;
	float: right;
`;

class Book extends Component {
	props: {
		book: BookType,
		handleShelfUpdate: (BookType, string) => void,
		findShelf: string => string
	};

	state = {
		shelf: '',
		rating: 0
	};

	handleChangeShelf = (event: SyntheticEvent, index: number, shelf: string) => {
		const { book, handleShelfUpdate } = this.props;
		update(book, shelf).then(() => {
			this.setState({ shelf });
			handleShelfUpdate(book, shelf);
		});
	};

	handleChangeRating = (rating: number) => {
		const { book: { id } } = this.props;
		setRating(id, rating);
		this.setState({ rating });
	};

	componentDidMount() {
		const { book, findShelf } = this.props;
		const rating = getRating(book.id);
		const shelf = book.shelf || findShelf(book.id);

		this.setState({ shelf, rating });
	}

	render() {
		const {
			book: {
				id,
				title,
				subtitle,
				description,
				authors,
				imageLinks: { thumbnail }
			}
		} = this.props;
		const { rating, shelf } = this.state;

		const shelfOptions = [
			{ text: 'Read', value: 'read' },
			{
				text: 'Currently Reading',
				value: 'currentlyReading'
			},
			{
				text: 'Want To Read',
				value: 'wantToRead'
			},
			{
				text: 'No Shelf',
				value: ''
			}
		];

		const shelfDropdownItems = shelfOptions.map(shelfOption => {
			return (
				<MenuItem
					key={shelfOption.value + '-opt'}
					value={shelfOption.value}
					primaryText={shelfOption.text}
				/>
			);
		});

		return (
			<FlybraryBook className="book">
				<CardMedia
					overlay={<CardTitle title={title} subtitle={subtitle} />}
					style={{ maxHeight: '400px', overflow: 'hidden' }}
				>

				</CardMedia>
				{authors && <CardTitle subtitle={authors.join(', ')} />}
				{description &&
					<CardText>
						{description.substring(0, 140) + '...'}
					</CardText>}
				<CardActions>
					Shelf:
					<DropDownMenu value={shelf} onChange={this.handleChangeShelf}>
						{shelfDropdownItems}
					</DropDownMenu>
					<RatingWrapper>
						<StarRatingComponent
							name={id + '-rating'}
							value={rating}
							onStarClick={newRating => this.handleChangeRating(newRating)}
						/>
					</RatingWrapper>
				</CardActions>
			</FlybraryBook>
		);
	}
}

export default Book;
<commit_msg>remove unneeded import<commit_after>// @flow

import React, { Component } from 'react';
import StarRatingComponent from 'react-star-rating-component';
import styled from 'styled-components';

import {
	Card,
	CardActions,
	CardMedia,
	CardTitle,
	CardText
} from 'material-ui/Card';
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';

import { update } from '../utils/BooksAPI';
import { getRating, setRating } from '../utils/RatingsAPI';
import type { BookType } from '../common/flowTypes';

const FlybraryBook = styled(Card)`
	flex-grow: 1;
	flex-shrink: 0;
	margin: 0 10px 12px;
	width: 90vw;
	min-width: 300px;
	max-width: 400px;
`;

const RatingWrapper = styled.div`
	margin-top: 20px;
	margin-bottom: 0px;
	padding-bottom: 0px;
	float: right;
`;

class Book extends Component {
	props: {
		book: BookType,
		handleShelfUpdate: (BookType, string) => void,
		findShelf: string => string
	};

	state = {
		shelf: '',
		rating: 0
	};

	handleChangeShelf = (event: SyntheticEvent, index: number, shelf: string) => {
		const { book, handleShelfUpdate } = this.props;
		update(book, shelf).then(() => {
			this.setState({ shelf });
			handleShelfUpdate(book, shelf);
		});
	};

	handleChangeRating = (rating: number) => {
		const { book: { id } } = this.props;
		setRating(id, rating);
		this.setState({ rating });
	};

	componentDidMount() {
		const { book, findShelf } = this.props;
		const rating = getRating(book.id);
		const shelf = book.shelf || findShelf(book.id);

		this.setState({ shelf, rating });
	}

	render() {
		const {
			book: {
				id,
				title,
				subtitle,
				description,
				authors,
				imageLinks: { thumbnail }
			}
		} = this.props;
		const { rating, shelf } = this.state;

		const shelfOptions = [
			{ text: 'Read', value: 'read' },
			{
				text: 'Currently Reading',
				value: 'currentlyReading'
			},
			{
				text: 'Want To Read',
				value: 'wantToRead'
			},
			{
				text: 'No Shelf',
				value: ''
			}
		];

		const shelfDropdownItems = shelfOptions.map(shelfOption => {
			return (
				<MenuItem
					key={shelfOption.value + '-opt'}
					value={shelfOption.value}
					primaryText={shelfOption.text}
				/>
			);
		});

		return (
			<FlybraryBook className="book">
				<CardMedia
					overlay={<CardTitle title={title} subtitle={subtitle} />}
					style={{ maxHeight: '400px', overflow: 'hidden' }}
				>

				</CardMedia>
				{authors && <CardTitle subtitle={authors.join(', ')} />}
				{description &&
					<CardText>
						{description.substring(0, 140) + '...'}
					</CardText>}
				<CardActions>
					Shelf:
					<DropDownMenu value={shelf} onChange={this.handleChangeShelf}>
						{shelfDropdownItems}
					</DropDownMenu>
					<RatingWrapper>
						<StarRatingComponent
							name={id + '-rating'}
							value={rating}
							onStarClick={newRating => this.handleChangeRating(newRating)}
						/>
					</RatingWrapper>
				</CardActions>
			</FlybraryBook>
		);
	}
}

export default Book;
<|endoftext|>