<commit_before>var _ = require('lodash'),
    squel = require('squel');

function Criteria(config, or) {
    this.or = or === true;
    this.config = config;
}

Criteria.prototype.apply = function (queryBuilder, values) {
    var config = this.config,
        expression = squel.expr(),
        where = this.or ? expression.or : expression.and;

    where = where.bind(expression);

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

    _.forEach(config, function (item) {
        var value = item.value,
            property = item.property,
            operator = item.operator,
            vl = values[item.name],
            path = queryBuilder.applyPath(property).property;

        if (value !== undefined) {
            if (_.isFunction(value)) {
                value = value();
            }
            operator(where, value, path);
        } else {
            operator(where, vl, path);
        }
    });

    queryBuilder.query.where(expression);

};

function equal(expression, value, property) {
    expression(property + ' = ?', value);
}

function notEqual(expression, value, property) {
    expression(property + ' <> ?', value);
}

function lessEqual(expression, value, property) {
    expression(property + ' <= ?', value);
}

function greaterEqual(expression, value, property) {
    expression(property + ' >= ?', value);
}

function lessThan(expression, value, property) {
    expression(property + ' < ?', value);
}

function greaterThan(expression, value, property) {
    expression(property + ' < ?', value);
}

function like(expression, value, property) {
    value = '%' + value.replace(/(%)|(_)|(\*)/g, '*$1$2$3').replace(/\*{2}/g, '%') + '%';
    expression(property + " LIKE ? ESCAPE '*'", value);
}

function ilike(expression, value, property) {
    value = '%' + value.toUpperCase().replace(/(%)|(_)|(\*)/g, '*$1$2$3').replace(/\*{2}/g, '%') + '%';
    expression("UPPER(" + property + ") LIKE ? ESCAPE '*'", value);
}

function ilikeStart(expression, value, property) {
    value = value.toUpperCase().replace(/(%)|(_)|(\*)/g, '*$1$2$3').replace(/\*{2}/g, '%') + '%';
    expression("UPPER(" + property + ") LIKE ? ESCAPE '*'", value);
}

function between(expression, values, property, queryBuilder) {
    // TODO there's a bug in squel that it's not possible to use more than one param on expr function
    // https://github.com/hiddentao/squel/issues/147
    // expression(property + ' BETWEEN ? AND ?', values[0], values[1]);
    queryBuilder.query.where(property + ' BETWEEN ? AND ?', values[0], values[1]);
}

function criteriaIn(expression, values, property) {
    expression(property + ' IN ?', values);
}

function notIn(expression, values, property) {
    if (values && values.length > 0) {
        expression(property + ' NOT IN ?', values);
    }
}

function has(expression, values, property) {
    // TODO
}

Criteria.prototype.OPERATOR = {
    NOT_EQUAL : notEqual,
    EQUAL : equal,
    LESS_EQUAL : lessEqual,
    GREATER_EQUAL : greaterEqual,
    LESS_THAN : lessThan,
    GREATER_THAN : greaterThan,
    LIKE : like,
    ILIKE : ilike,
    ILIKE_START : ilikeStart,
    BETWEEN : between,
    HAS : has,
    IN : criteriaIn,
    NOT_IN : notIn
};

module.exports = Criteria;<commit_msg>SPH-16 Adição do operador IS_NULL e IS_NOT_NULL<commit_after>var _ = require('lodash'),
    squel = require('squel');

function Criteria(config, or) {
    this.or = or === true;
    this.config = config;
}

Criteria.prototype.apply = function (queryBuilder, values) {
    var config = this.config,
        expression = squel.expr(),
        where = this.or ? expression.or : expression.and;

    where = where.bind(expression);

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

    _.forEach(config, function (item) {
        var value = item.value,
            property = item.property,
            operator = item.operator,
            vl = values[item.name],
            path = queryBuilder.applyPath(property).property;

        if (value !== undefined) {
            if (_.isFunction(value)) {
                value = value();
            }
            operator(where, path, value, queryBuilder);
        } else {
            operator(where, path, vl, queryBuilder);
        }
    });

    queryBuilder.query.where(expression);

};

function isNull (expression, property) {
    expression(property + ' IS NULL ');
}

function isNotNull (expression, property) {
    expression(property + ' IS NOT NULL ');
}

function equal(expression, property, value) {
    expression(property + ' = ?', value);
}

function notEqual(expression, property, value) {
    expression(property + ' <> ?', value);
}

function lessEqual(expression, property, value) {
    expression(property + ' <= ?', value);
}

function greaterEqual(expression, property, value) {
    expression(property + ' >= ?', value);
}

function lessThan(expression, property, value) {
    expression(property + ' < ?', value);
}

function greaterThan(expression, property, value) {
    expression(property + ' < ?', value);
}

function like(expression, property, value) {
    value = '%' + value.replace(/(%)|(_)|(\*)/g, '*$1$2$3').replace(/\*{2}/g, '%') + '%';
    expression(property + " LIKE ? ESCAPE '*'", value);
}

function ilike(expression, property, value) {
    value = '%' + value.toUpperCase().replace(/(%)|(_)|(\*)/g, '*$1$2$3').replace(/\*{2}/g, '%') + '%';
    expression("UPPER(" + property + ") LIKE ? ESCAPE '*'", value);
}

function ilikeStart(expression, property, value) {
    value = value.toUpperCase().replace(/(%)|(_)|(\*)/g, '*$1$2$3').replace(/\*{2}/g, '%') + '%';
    expression("UPPER(" + property + ") LIKE ? ESCAPE '*'", value);
}

function between(expression, property, values, queryBuilder) {
    // TODO there's a bug in squel that it's not possible to use more than one param on expr function
    // https://github.com/hiddentao/squel/issues/147
    // expression(property + ' BETWEEN ? AND ?', values[0], values[1]);
    queryBuilder.query.where(property + ' BETWEEN ? AND ?', values[0], values[1]);
}

function criteriaIn(expression, property, values) {
    expression(property + ' IN ?', values);
}

function notIn(expression, property, values) {
    if (values && values.length > 0) {
        expression(property + ' NOT IN ?', values);
    }
}

function has(expression, property, values) {
    // TODO
}

Criteria.prototype.OPERATOR = {
    NOT_EQUAL : notEqual,
    EQUAL : equal,
    LESS_EQUAL : lessEqual,
    GREATER_EQUAL : greaterEqual,
    LESS_THAN : lessThan,
    GREATER_THAN : greaterThan,
    LIKE : like,
    ILIKE : ilike,
    ILIKE_START : ilikeStart,
    BETWEEN : between,
    HAS : has,
    IN : criteriaIn,
    NOT_IN : notIn,
    IS_NULL : isNull,
    IS_NOT_NULL : isNotNull
};

module.exports = Criteria;<|endoftext|>


<commit_before>'use strict'

var fs = require('fs');
var path = require('path');
var bcrypt = require('bcrypt-nodejs');
var mongoosePaginate = require('mongoose-pagination');

var Artist = require('../models/artist');
var Album = require('../models/album');
var Song = require('../models/song');

var jwt = require('../services/jwt');

function getSong (req,res) {

    var songId = req.params.id;

    Song.findById(songId).populate({path: 'album'}).exec( (err,song) => {
        if(err){
            res.status(500).send({message: 'Error en el request de la cancion'});
        }  else{
            if(!song){
                res.status(404).send({message: 'No se ha encontrado la cancion'});
            } else{
                res.status(200).send({song: song});

            }

        }
    });

}

function getSongs (req,res) {

    var albumId = req.params.album;
    if(req.params.page){
        var page = req.params.page;
    }else{
        var page = 1;
    }

    var itemsPerPage = 5;

    if(!albumId){

        var find = Song.find().sort('name');
        find.populate({path: 'album'}).exec( (err, songs)=> {
            if (err) {
                res.status(500).send({message: 'Error al cargar las canciones !'});
            } else {
                if (!songs) {
                    res.status(404).send({message: 'No hay canciones !'});
                } else {
                    res.status(200).send({songs: songs});

                }

            }

        });

    }else {

        var find = Song.find({album: albumId}).sort('number');
        find.populate({path: 'album'}).exec( (err, songs)=> {

            if (err) {
                res.status(500).send({message: 'Error al cargar las canciones !'});
            } else {
                if (!songs) {
                    res.status(404).send({message: 'No hay canciones !'});
                } else {
                    res.status(200).send({songs: songs});

                }

            }

        });

    }

}

function saveSong (req,res) {

    var song = new Song();
    var params = req.body;

    //console.log(params);
    song.name = params.name;
    song.number = params.number;
    song.duration = params.duration;
    song.file = "null";
    song.album = params.album;

    song.save((err,songStored) => {
        if(err){
            res.status(500).send({message: 'Error al guardar la cancion'});
        }  else{
            if(!songStored){
                res.status(404).send({message: 'No se ha registrado la cancion'});
            } else{
                res.status(200).send({songStored: songStored});

            }

        }
    });

}

function updateSong (req,res) {

    var songId = req.params.id;
    var update = req.body;

    Song.findByIdAndUpdate(songId,update,(err,songUpdated) => {
        if(err){

            res.status(500).send({message: 'Error al actualizar la cancion'});

        }else{
            if(!songUpdated){

                res.status(404).send({message: 'No se ha podido actualizar la cancion'});

            }else {

                res.status(200).send({song: songUpdated});

            }

        }
    });

}

function deleteSong(req,res) {

    var songId = req.params.id;

    Song.findByIdAndRemove(songId,(err,songDeleted) => {
        if(err){

            res.status(500).send({message: 'Error al borrar la cancion'});

        }else{
            if(!songDeleted){

                res.status(404).send({message: 'No se ha podido borrar la cancion'});

            }else {
                res.status(200).send({songDeleted: songDeleted});

            }

        }
    });

}

function uploadSongFile(req,res){
    var albumId = req.params.id;
    var file_name = 'No ha subido ...';

    if(req.files){

        var file_path = req.files.image.path;

        var file_split = file_path.split("\/");

        var file_name = file_split[2];

        var ext_split = file_name.split('\.');

        var file_ext = ext_split[1];

        //console.log(ext_split);

        if(file_ext == 'png' || file_ext == 'jpg' || file_ext == 'jpeg' || file_ext == 'gif'){

            Album.findByIdAndUpdate(albumId,{image: file_name},(err,albumUpdated) =>{

                if(!albumUpdated){

                    res.status(404).send({message: 'No se ha podido actualizar el Album'});

                }else {

                    res.status(200).send({album: albumUpdated});

                }

            });
        }else{
            res.status(500).send({message: 'Extension del archivo no soportada'});

        }
    }else{
        res.status(500).send({message: 'No se ha subido una imagen'});
    }
}

function getSongFile(req,res){

    var imageFile = req.params.imageFile;
    var path_file = './uploads/albums/'+imageFile;
    fs.exists(path_file, function(exists){
        if(exists){
            res.sendFile(path.resolve(path_file));
        }else {
            res.status(404).send({message: 'No existe la imagen'});
        }
    });
}

module.exports = {
    getSong,
    getSongs,
    saveSong,
    updateSong,
    deleteSong,
    uploadSongFile,
    getSongFile

};<commit_msg>api song controlle<commit_after>'use strict'

var fs = require('fs');
var path = require('path');
var bcrypt = require('bcrypt-nodejs');
var mongoosePaginate = require('mongoose-pagination');

var Artist = require('../models/artist');
var Album = require('../models/album');
var Song = require('../models/song');

var jwt = require('../services/jwt');

function getSong (req,res) {

    var songId = req.params.id;

    Song.findById(songId).populate({path: 'album'}).exec( (err,song) => {
        if(err){
            res.status(500).send({message: 'Error en el request de la cancion'});
        }  else{
            if(!song){
                res.status(404).send({message: 'No se ha encontrado la cancion'});
            } else{
                res.status(200).send({song: song});

            }

        }
    });

}

function getSongs (req,res) {

    var albumId = req.params.album;
    if(req.params.page){
        var page = req.params.page;
    }else{
        var page = 1;
    }

    var itemsPerPage = 5;

    if(!albumId){

        var find = Song.find().sort('name');
        find.populate({path: 'album',
        populate: {
            path: 'artist',
            model: 'Artist'
        }

        }).exec( (err, songs)=> {
            if (err) {
                res.status(500).send({message: 'Error al cargar las canciones !'});
            } else {
                if (!songs) {
                    res.status(404).send({message: 'No hay canciones !'});
                } else {
                    res.status(200).send({songs: songs});

                }

            }

        });

    }else {

        var find = Song.find({album: albumId}).sort('number');
        find.populate({path: 'album',
            populate: {
                path: 'artist',
                model: 'Artist'
            }

        }).exec( (err, songs)=> {

            if (err) {
                res.status(500).send({message: 'Error al cargar las canciones !'});
            } else {
                if (!songs) {
                    res.status(404).send({message: 'No hay canciones !'});
                } else {
                    res.status(200).send({songs: songs});

                }

            }

        });

    }

}

function saveSong (req,res) {

    var song = new Song();
    var params = req.body;

    //console.log(params);
    song.name = params.name;
    song.number = params.number;
    song.duration = params.duration;
    song.file = "null";
    song.album = params.album;

    song.save((err,songStored) => {
        if(err){
            res.status(500).send({message: 'Error al guardar la cancion'});
        }  else{
            if(!songStored){
                res.status(404).send({message: 'No se ha registrado la cancion'});
            } else{
                res.status(200).send({songStored: songStored});

            }

        }
    });

}

function updateSong (req,res) {

    var songId = req.params.id;
    var update = req.body;

    Song.findByIdAndUpdate(songId,update,(err,songUpdated) => {
        if(err){

            res.status(500).send({message: 'Error al actualizar la cancion'});

        }else{
            if(!songUpdated){

                res.status(404).send({message: 'No se ha podido actualizar la cancion'});

            }else {

                res.status(200).send({song: songUpdated});

            }

        }
    });

}

function deleteSong(req,res) {

    var songId = req.params.id;

    Song.findByIdAndRemove(songId,(err,songDeleted) => {
        if(err){

            res.status(500).send({message: 'Error al borrar la cancion'});

        }else{
            if(!songDeleted){

                res.status(404).send({message: 'No se ha podido borrar la cancion'});

            }else {
                res.status(200).send({songDeleted: songDeleted});

            }

        }
    });

}

function uploadSongFile(req,res){
    var albumId = req.params.id;
    var file_name = 'No ha subido ...';

    if(req.files){

        var file_path = req.files.image.path;

        var file_split = file_path.split("\/");

        var file_name = file_split[2];

        var ext_split = file_name.split('\.');

        var file_ext = ext_split[1];

        //console.log(ext_split);

        if(file_ext == 'png' || file_ext == 'jpg' || file_ext == 'jpeg' || file_ext == 'gif'){

            Album.findByIdAndUpdate(albumId,{image: file_name},(err,albumUpdated) =>{

                if(!albumUpdated){

                    res.status(404).send({message: 'No se ha podido actualizar el Album'});

                }else {

                    res.status(200).send({album: albumUpdated});

                }

            });
        }else{
            res.status(500).send({message: 'Extension del archivo no soportada'});

        }
    }else{
        res.status(500).send({message: 'No se ha subido una imagen'});
    }
}

function getSongFile(req,res){

    var imageFile = req.params.imageFile;
    var path_file = './uploads/albums/'+imageFile;
    fs.exists(path_file, function(exists){
        if(exists){
            res.sendFile(path.resolve(path_file));
        }else {
            res.status(404).send({message: 'No existe la imagen'});
        }
    });
}

module.exports = {
    getSong,
    getSongs,
    saveSong,
    updateSong,
    deleteSong,
    uploadSongFile,
    getSongFile

};<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 *
 * Licensed 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.
 */

foam.CLASS({
  package: 'foam.box',
  name: 'Message',

  properties: [
    {
      class: 'Map',
      name: 'attributes'
    },
    {
      class: 'Object',
      name: 'object'
    },
    {
      class: 'Map',
      transient: true,
      name: 'localAttributes'
    }
  ]
});
<commit_msg>Add java factories for Message.attributes/localAttributes to improve usability.<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 *
 * Licensed 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.
 */

foam.CLASS({
  package: 'foam.box',
  name: 'Message',

  properties: [
    {
      class: 'Map',
      name: 'attributes',
      javaFactory: 'return new java.util.HashMap();'
    },
    {
      class: 'Object',
      name: 'object'
    },
    {
      class: 'Map',
      transient: true,
      name: 'localAttributes',
      javaFactory: 'return new java.util.HashMap();'
    }
  ]
});
<|endoftext|>


<commit_before>function contentController ($scope, $location,$http) {
	$scope.access_token= "";
	$scope.page_name = "";
	$scope.show = false;
	$scope.qdata = [];
	$scope.next = false;
	$scope.prev = false;
	$scope.count = 0;
	$scope.searching = false;
	$scope.countDirection = true; //true for positive (++)

	$scope.countEqualsZero = function () {
		if($scope.count==0)
			return true;
		return false;
	}
	//for clearfix class;
	$scope.indexDivByThree = function (index) {
		if((index+1) % 3 == 0 )
			return true;
		else return false;
	}

	$scope.lessPost = function () {
		if($scope.count<=25)
			return true;
		return false;
	}

	$scope.GetDate = function (date) {
		var d = new Date(date);
      return d;
	}
	window.fbAsyncInit = function() {
	FB.init({
		//facebook app id
	  appId      : '494795677343992',
	  cookie     : true,  // enable cookies to allow the server to access
	                      // the session
	  xfbml      : true,  // parse social plugins on this page
	  version    : 'v2.0', // use version 2.0
	  status     : true
	});

	FB.Event.subscribe('auth.authResponseChange', function(response) {
	     if (response.status === 'connected')
	     {
	     	console.log(response);
	        $scope.access_token = response.authResponse.accessToken;
	        $scope.show = true;
	        $scope.$apply();
	     }
	     else if (response.status === 'not_authorized')
	    {
	        console.log('logged In fail');
	    } else
	    {
	        //UNKNOWN ERROR. Logged Out
	        $scope.access_token = '';
	        $scope.show = false;
	        console.log('logged In failed');
	    }
	});
	FB.Event.subscribe('auth.login', function(response) {
	  console.log(response);
	});
	};
	$scope.findPage = function (type) {
		var l = Ladda.create(document.getElementById('mainBtn'));
		l1 = Ladda.create(document.getElementById('prevBtn'));
		l2 = Ladda.create(document.getElementById('nextBtn'));
		l.start();
		l1.start();
		l2.start();
		$scope.message = '';
		$scope.qdata=[];
		if(type=='fresh'){
			$scope.countDirection = true;
			$scope.searching = false;
			$scope.count = 0;
			url = "https://graph.facebook.com/"+$scope.page_name+"/posts/?access_token="+$scope.access_token;
		}
		if(type =='next'){
			$scope.countDirection = true;
			url = $scope.paging.next;
		}
		if(type =='prev'){
			$scope.countDirection = false;
			url = $scope.paging.previous;
		}
		$.ajax({
		url: url,
		type: "GET",
		success : function (data) {
			console.log(data);
			search = data.data;
			if(search.length==0){
				$scope.message = 'No posts available to search';
			}
			console.log($scope.search_string);
			if($scope.search_string == undefined ||$scope.search_string == ' '){
				$scope.message = 'wrong query';
				return;
			}
			$scope.searching = true;
			for (var i = 0; i < search.length; i++) {
				if($scope.countDirection)
					$scope.count++;
				else
					$scope.count--;
				console.log(search[i].message);
				if(search[i].message!==undefined){
					if(search[i].message.toLowerCase().search($scope.search_string.toLowerCase())!=-1){
						$scope.qdata.push(search[i]);
					}else if(search[i].name!==undefined){
						if(search[i].name.toLowerCase().search($scope.search_string.toLowerCase())!=-1){
							$scope.qdata.push(search[i]);
						}
					}
				}else if(search[i].description!==undefined){
					if(search[i].description.toLowerCase().search($scope.search_string.toLowerCase())!=-1){
						$scope.qdata.push(search[i]);
					}
				}
			};
			if(data.paging !==undefined){
				$scope.paging = data.paging;
				$scope.next = true;
				$scope.prev = true;
			}
			if($scope.qdata.length==0){
				$scope.findPage('next');
			}else{
				$scope.message = '';
			}
			l.stop();
			l1.stop();
			l2.stop();
			console.log($scope.qdata);
			// if(data.paging !==undefined){
			// 	$scope.paging = data.paging;
			// 	$scope.next = true;
			// 	$scope.prev = true;
			// }
			console.log($scope.paging);
			$scope.$apply();
		},
		error: function (data) {
			$scope.message = data.responseJSON.error.message;
			$scope.$apply();
		}
	});
	}
}<commit_msg>fixed some issues<commit_after>function contentController ($scope, $location,$http) {
	$scope.access_token= "";
	$scope.page_name = "";
	$scope.show = false;
	$scope.qdata = [];
	$scope.next = false;
	$scope.prev = false;
	$scope.count = 0;
	$scope.searching = false;
	$scope.countDirection = true; //true for positive (++)

	$scope.countEqualsZero = function () {
		if($scope.count==0)
			return true;
		return false;
	}
	//for clearfix class;
	$scope.indexDivByThree = function (index) {
		if((index+1) % 3 == 0 )
			return true;
		else return false;
	}

	$scope.lessPost = function () {
		if($scope.count<=25)
			return true;
		return false;
	}

	$scope.GetDate = function (date) {
		var d = new Date(date);
      return d;
	}
	window.fbAsyncInit = function() {
	FB.init({
		//facebook app id
	  appId      : '494795677343992',
	  cookie     : true,  // enable cookies to allow the server to access
	                      // the session
	  xfbml      : true,  // parse social plugins on this page
	  version    : 'v2.0', // use version 2.0
	  status     : true
	});

	FB.Event.subscribe('auth.authResponseChange', function(response) {
	     if (response.status === 'connected')
	     {
	     	console.log(response);
	        $scope.access_token = response.authResponse.accessToken;
	        $scope.show = true;
	        $scope.$apply();
	     }
	     else if (response.status === 'not_authorized')
	    {
	        console.log('logged In fail');
	    } else
	    {
	        //UNKNOWN ERROR. Logged Out
	        $scope.access_token = '';
	        $scope.show = false;
	        console.log('logged In failed');
	    }
	});
	FB.Event.subscribe('auth.login', function(response) {
	  console.log(response);
	});
	};
	$scope.findPage = function (type) {
		var l = Ladda.create(document.getElementById('mainBtn'));
		l1 = Ladda.create(document.getElementById('prevBtn'));
		l2 = Ladda.create(document.getElementById('nextBtn'));
		l.start();
		l1.start();
		l2.start();
		$scope.message = '';
		$scope.qdata=[];
		if(type=='fresh'){
			$scope.countDirection = true;
			$scope.searching = false;
			$scope.count = 0;
			url = "https://graph.facebook.com/"+$scope.page_name+"/posts/?access_token="+$scope.access_token;
		}
		if(type =='next'){
			$scope.countDirection = true;
			url = $scope.paging.next;
		}
		if(type =='prev'){
			$scope.countDirection = false;
			url = $scope.paging.previous;
		}
		$.ajax({
		url: url,
		type: "GET",
		success : function (data) {
			console.log(data);
			search = data.data;
			if(search.length==0){
				$scope.message = 'No posts available to search';
			}
			console.log($scope.search_string);
			if($scope.search_string == undefined ||$scope.search_string == ' '){
				$scope.message = 'wrong query';
				return;
			}
			$scope.searching = true;
			for (var i = 0; i < search.length; i++) {
				if($scope.countDirection)
					$scope.count++;
				else
					$scope.count--;
				console.log(search[i].message);
				if(search[i].message!==undefined){
					if(search[i].message.toLowerCase().search($scope.search_string.toLowerCase())!=-1){
						$scope.qdata.push(search[i]);
					}else if(search[i].name!==undefined){
						if(search[i].name.toLowerCase().search($scope.search_string.toLowerCase())!=-1){
							$scope.qdata.push(search[i]);
						}
					}
				}else if(search[i].description!==undefined){
					if(search[i].description.toLowerCase().search($scope.search_string.toLowerCase())!=-1){
						$scope.qdata.push(search[i]);
					}
				}
			};
			if(data.paging !==undefined){
				$scope.paging = data.paging;
				$scope.next = true;
				$scope.prev = true;
			}
			if($scope.qdata.length==0){
				$scope.findPage('next');
			}else{
				l.stop();
				l1.stop();
				l2.stop();
				$scope.message = '';
			}
			console.log($scope.qdata);
			// if(data.paging !==undefined){
			// 	$scope.paging = data.paging;
			// 	$scope.next = true;
			// 	$scope.prev = true;
			// }
			console.log($scope.paging);
			$scope.$apply();
		},
		error: function (data) {
			$scope.message = data.responseJSON.error.message;
			$scope.$apply();
		}
	});
	}
}<|endoftext|>


<commit_before>"use strict";

// What is Controller?
// ---

// Controller helps facilitate routing via express by providing configuring route handlers
//
// For example, a route to `/users/:id` would be handled by a `UsersController` with function `findOne`
//
// It provides a way for each controller to setup the routes and handlers it wants to respond to
//
// Also provides a mechanism to define pre, before, and after middleware per controller or per route
//
// Finally, it also provides response and error handling middleware
//
// Also parses query strings for filter, limit, and sort

// Dependencies
// ---
var _ = require('lodash');
var Backbone = require('backbone');
var Model = require('./model');
var Collection = require('./collection');

module.exports = Backbone.Model.extend({
  debug: false,

  path: "/",

  sortParam: "created",
  sortOrder: "desc",
  skip: 0,
  limit: 50,

  // Route specific middleware definitions
  // Object or Function
  middleware: function() {
    return {};
  },

  // Database query parameters/filters
  // Object or Function
  queryParams: function() {
    return {};
  },

  // Computes the base path for the controller
  // Object or Function
  basePath: function() {
    return this.path;
  },

  // Called after the constructor
  initialize: function() {
    // Routes
    this.routes = {
      get: {},
      post: {},
      put: {},
      delete: {}
    };

    // Middleware(s)
    this.pre = []; // run before route middleware
    this.before = []; // run after route middleware but before route handler
    this.after = []; // run after route handler

    // Setup middleware and route handlers
    this.setupPreMiddleware();
    this.setupBeforeMiddleware();
    this.setupRoutes();
    this.setupAfterMiddleware();

    // Response/error handler middleware
    this.after.push(this.successResponse);
    this.after.push(this.errorResponse);
    this.after.push(this.finalResponse);
  },

  // Setup routes that this controller should handle
  //
  // Example:
  // this.routes.get["/test"] = {
  //   action: this.testGet,
  //   middleware: []
  // };
  setupRoutes: function() {},

  // Setup middleware that should run before the route middleware
  // Example: `this.pre.push(this.fakePreMiddleware)`
  setupPreMiddleware: function() {},

  // Setup middleware that should run before the route handler
  // Example: `this.before.push(this.fakeBeforeMiddleware)`
  setupBeforeMiddleware: function() {},

  // Setup middleware that should run after the route handler
  // Example: `this.after.push(this.fakeAfterMiddleware)`
  setupAfterMiddleware: function() {},

  // Middleware
  // ---

  // Promise friendly next()
  // Used as a resolver for `then`
  nextThen: function(req, res, next) {
    return function(modelOrCollection) {
      this.prepareResponse(modelOrCollection, req, res, next);
    }.bind(this);
  },

  // Promise friendly next(err)
  // Used as a resolver for `catch`
  nextCatch: function(req, res, next) {
    return function(err) {
      next(err);
    }.bind(this);
  },

  // This method can be overridden to customize the response
  prepareResponse: function(modelOrCollection, req, res, next) {
    if (!modelOrCollection) {
      return next();
    }

    if (modelOrCollection instanceof Model) {
      // Data is a Model
      res.data = this.renderModel(modelOrCollection);
    } else if (modelOrCollection instanceof Collection) {
      // Data is a Collection
      res.data = this.renderCollection(modelOrCollection);
    } else {
      // Data is raw
      res.data = modelOrCollection;
    }

    return next();
  },

  // Default middleware for handling successful responses
  successResponse: function(req, res, next) {
    // Default to 200, but allow override (e.g. 201)
    res.code = res.code || 200;

    var data = res.data || {};
    var envelope = {
      meta: {
        code: res.code
      },
      data: data
    };

    // Optional paging meta
    if (res.paging) {
      envelope.meta.paging = res.paging;
    }

    if (res.code === 204) {
      res.data = null;
    } else {
      res.data = envelope;
    }
    next();
  },

  // Default middleware for handling error responses
  errorResponse: function(err, req, res, next) {
    // Default to 500, but allow override
    res.code = res.code || err.code || 500;

    var data = res.data || {};
    var envelope = {
      meta: {
        code: res.code,
        error: err.message
      },
      data: data
    };

    // TODO
    // We should log these errors somewhere remotely
    if (this.debug) {
      if (res.code >= 500) {
        if (err && err.stack && err.stack.error) {
          console.error(err.stack.error);
        }
      } else {
        console.error("Error (%d): %s".error, res.code, err.message);
      }
    }

    res.data = envelope;
    next();
  },

  // Final middleware for handling all responses
  // Server actually responds to the request here
  finalResponse: function(req, res, next) {
    // If we timed out before managing to respond, don't send the response
    if (res.headerSent) {
      return;
    }

    // Respond with correct format, defaulting to json
    res.fmt = res.fmt || 'json';
    if (res.fmt === 'json') {
      // json
      res.jsonp(res.code, res.data);
    } else if (res.fmt === 'xml') {
      // xml
      res.set('Content-Type', 'application/xml; charset=utf-8');
      res.send(res.code, res.data);
    } else {
      // text or html
      res.send(res.code, res.data);
    }
  },

  // Render
  // ---

  renderModel: function(model) {
    return model.render();
  },

  renderCollection: function(collection) {
    return collection.map(function(model) {
      return model.render();
    });
  },

  // Helpers
  // ---

  // Gets any route middleware that may have been defined
  getRouteMiddleware: function(action) {
    // Find route middleware definitions
    var middleware = _.result(this, 'middleware');
    if (_.has(middleware, action)) {
      return middleware[action];
    } else {
      return [];
    }
  },

  // Parses req.query (querystring) for since/until, sort/order, skip/limit
  // Also builds a query using allowed queryParams if applicable
  parseQueryString: function(req) {
    var query = {};
    var queries = [];
    var options = {};

    // Reserved Params
    var since = req.query.since || req.query.from; // validate timestamp (s or ms) [DO NOT USE]
    var until = req.query.until || req.query.to; // validate timestamp (s or ms) [ DO NOT USE]
    var sortBy = req.query.sort || this.sortParam; // validate sortableParams
    var orderBy = req.query.order || this.sortOrder; // validate [asc, desc]
    var skip = req.query.skip || req.query.offset || this.skip; // validate int
    var limit = req.query.limit || req.query.count || this.limit; // validate int

    // Hard limit at 100
    limit = Math.min(limit, 100);

    // Build created, updated objects into the query string if sent in as dot notation
    _.each(req.query, function(obj, key) {
      var match;
      if (match = key.match(/(created|updated).(gte|lte|gt|lt)/)) {
        req.query[match[1]] = req.query[match[1]] || {};
        req.query[match[1]][match[2]] = parseInt(obj);
      }
    });

    var created = req.query.created || {}; // accepts both s and ms
    var updated = req.query.updated || {}; // accepts both s and ms

    // Convert all timestamps into integers
    _.each(created, function(timestamp, key) {
      created[key] = _.parseInt(timestamp);
    });

    _.each(updated, function(timestamp, key) {
      updated[key] = _.parseInt(timestamp);
    });

    // Query
    // Create date
    if (!_.isEmpty(created)) {
      var createdQuery = {
        created: {}
      };

      if (created.gte) {
        created.gte = _.isUnixTime(created.gte) ? created.gte * 1000 : created.gte;
        createdQuery.created["$gte"] = new Date(created.gte).getTime();
      } else if (created.gt) {
        created.gt = _.isUnixTime(created.gt) ? created.gt * 1000 : created.gt;
        createdQuery.created["$gt"] = new Date(created.gt).getTime();
      }

      if (created.lte) {
        created.lte = _.isUnixTime(created.lte) ? created.lte * 1000 : created.lte;
        createdQuery.created["$lte"] = new Date(created.lte).getTime();
      } else if (created.lt) {
        created.lt = _.isUnixTime(created.lt) ? created.lt * 1000 : created.lt;
        createdQuery.created["$lt"] = new Date(created.lt).getTime();
      }

      if (_.isNumber(created)) {
        created = _.isUnixTime(created) ? created * 1000 : created;
        createdQuery.created = new Date(created).getTime();
      }
      queries.push(createdQuery);
    }

    // Updated/modified date
    if (!_.isEmpty(updated)) {
      var updatedQuery = {
        updated: {}
      };

      if (updated.gte) {
        updated.gte = _.isUnixTime(updated.gte) ? updated.gte * 1000 : updated.gte;
        updatedQuery.created["$gte"] = new Date(updated.gte).getTime();
      } else if (updated.gt) {
        updated.gt = _.isUnixTime(updated.gt) ? updated.gt * 1000 : updated.gt;
        updatedQuery.updated["$gt"] = new Date(updated.gt).getTime();
      }

      if (updated.lte) {
        updated.lte = _.isUnixTime(updated.lte) ? updated.lte * 1000 : updated.lte;
        updatedQuery.updated["$lte"] = new Date(updated.lte).getTime();
      } else if (updated.lt) {
        updated.lt = _.isUnixTime(updated.lt) ? updated.lt * 1000 : updated.lt;
        updatedQuery.created["$lt"] = new Date(updated.lt).getTime();
      }

      if (_.isNumber(updated)) {
        updated = _.isUnixTime(updated) ? updated * 1000 : updated;
        updatedQuery.updated = new Date(updated).getTime();
      }
      queries.push(updatedQuery);
    }

    // Since/Until Range
    if (since || until) {
      var sinceUntilQuery = {
        created: {}
      };

      if (since) {
        sinceUntilQuery.created["$gte"] = new Date(_.parseInt(since) * 1000).getTime();
      }

      if (until) {
        sinceUntilQuery.created["$lte"] = new Date(_.parseInt(until) * 1000).getTime();
      }

      queries.push(sinceUntilQuery);
    }

    // Filter Params
    var queryParams = _.extend(_.result(this, 'queryParams'), {
      "user_id": "string"
    });
    var filterParams = _.pick(req.query, _.keys(queryParams));

    _.each(filterParams, function(val, key) {
      // If value is all, ignore this param
      if (val === 'all') {
        return;
      }

      // Support `,` as `$or` for each param
      var vals = val.split(',');

      // No value, ignore this param
      if (vals.length === 0) {
        return;
      }

      // The built query filter
      var filter = {};

      // Get param type
      var type = queryParams[key];

      // Deal with different param types
      if (type === 'string') {
        // strings and objectid
        // no transformation
      } else if (type === 'regex') {
        // regex case insensitive and escaping special characters
        vals = _.map(vals, function(v) {
          return {
            // "$regex": '^' + _.escapeRegExp(v),
            "$regex": _.escapeRegExp(v),
            "$options": 'i'
          };
        });
        // filter[key] = {
        //   "$regex": '^' + _.escapeRegExp(val),
        //   "$options": 'i'
        // };
      } else if (type === 'integer') {
        // integers
        vals = _.map(vals, function(v) {
          return _.parseInt(v);
        });
        // val = _.parseInt(val);
      } else if (type === 'float') {
        // floats
        vals = _.map(vals, function(v) {
          return _.parseFloat(v);
        });
        // val = parseFloat(val);
      } else {
        // invalid or unknown type
        return;
      }

      // If there is only one val, no need to use `$or`
      if (vals.length === 1) {
        filter[key] = vals[0];
      } else {
        var orExpr = [];
        _.each(vals, function(orVal) {
          var orClause = {};
          orClause[key] = orVal;
          orExpr.push(orClause);
        });
        filter["$or"] = orExpr;
      }

      queries.push(filter);
    });

    // Combine the query
    if (queries.length > 0) {
      query['$and'] = queries;
    }

    // Options
    // Sort/Order/Limit/Skip
    var sortOptions = [
      [sortBy, orderBy]
    ];

    return {
      "query": query,
      "sort": sortOptions,
      "limit": parseInt(limit, 10),
      "skip": parseInt(skip, 10)
    };
  }

});<commit_msg>fixed updated[gte] filter<commit_after>"use strict";

// What is Controller?
// ---

// Controller helps facilitate routing via express by providing configuring route handlers
//
// For example, a route to `/users/:id` would be handled by a `UsersController` with function `findOne`
//
// It provides a way for each controller to setup the routes and handlers it wants to respond to
//
// Also provides a mechanism to define pre, before, and after middleware per controller or per route
//
// Finally, it also provides response and error handling middleware
//
// Also parses query strings for filter, limit, and sort

// Dependencies
// ---
var _ = require('lodash');
var Backbone = require('backbone');
var Model = require('./model');
var Collection = require('./collection');

module.exports = Backbone.Model.extend({
  debug: false,

  path: "/",

  sortParam: "created",
  sortOrder: "desc",
  skip: 0,
  limit: 50,

  // Route specific middleware definitions
  // Object or Function
  middleware: function() {
    return {};
  },

  // Database query parameters/filters
  // Object or Function
  queryParams: function() {
    return {};
  },

  // Computes the base path for the controller
  // Object or Function
  basePath: function() {
    return this.path;
  },

  // Called after the constructor
  initialize: function() {
    // Routes
    this.routes = {
      get: {},
      post: {},
      put: {},
      delete: {}
    };

    // Middleware(s)
    this.pre = []; // run before route middleware
    this.before = []; // run after route middleware but before route handler
    this.after = []; // run after route handler

    // Setup middleware and route handlers
    this.setupPreMiddleware();
    this.setupBeforeMiddleware();
    this.setupRoutes();
    this.setupAfterMiddleware();

    // Response/error handler middleware
    this.after.push(this.successResponse);
    this.after.push(this.errorResponse);
    this.after.push(this.finalResponse);
  },

  // Setup routes that this controller should handle
  //
  // Example:
  // this.routes.get["/test"] = {
  //   action: this.testGet,
  //   middleware: []
  // };
  setupRoutes: function() {},

  // Setup middleware that should run before the route middleware
  // Example: `this.pre.push(this.fakePreMiddleware)`
  setupPreMiddleware: function() {},

  // Setup middleware that should run before the route handler
  // Example: `this.before.push(this.fakeBeforeMiddleware)`
  setupBeforeMiddleware: function() {},

  // Setup middleware that should run after the route handler
  // Example: `this.after.push(this.fakeAfterMiddleware)`
  setupAfterMiddleware: function() {},

  // Middleware
  // ---

  // Promise friendly next()
  // Used as a resolver for `then`
  nextThen: function(req, res, next) {
    return function(modelOrCollection) {
      this.prepareResponse(modelOrCollection, req, res, next);
    }.bind(this);
  },

  // Promise friendly next(err)
  // Used as a resolver for `catch`
  nextCatch: function(req, res, next) {
    return function(err) {
      next(err);
    }.bind(this);
  },

  // This method can be overridden to customize the response
  prepareResponse: function(modelOrCollection, req, res, next) {
    if (!modelOrCollection) {
      return next();
    }

    if (modelOrCollection instanceof Model) {
      // Data is a Model
      res.data = this.renderModel(modelOrCollection);
    } else if (modelOrCollection instanceof Collection) {
      // Data is a Collection
      res.data = this.renderCollection(modelOrCollection);
    } else {
      // Data is raw
      res.data = modelOrCollection;
    }

    return next();
  },

  // Default middleware for handling successful responses
  successResponse: function(req, res, next) {
    // Default to 200, but allow override (e.g. 201)
    res.code = res.code || 200;

    var data = res.data || {};
    var envelope = {
      meta: {
        code: res.code
      },
      data: data
    };

    // Optional paging meta
    if (res.paging) {
      envelope.meta.paging = res.paging;
    }

    if (res.code === 204) {
      res.data = null;
    } else {
      res.data = envelope;
    }
    next();
  },

  // Default middleware for handling error responses
  errorResponse: function(err, req, res, next) {
    // Default to 500, but allow override
    res.code = res.code || err.code || 500;

    var data = res.data || {};
    var envelope = {
      meta: {
        code: res.code,
        error: err.message
      },
      data: data
    };

    // TODO
    // We should log these errors somewhere remotely
    if (this.debug) {
      if (res.code >= 500) {
        if (err && err.stack && err.stack.error) {
          console.error(err.stack.error);
        }
      } else {
        console.error("Error (%d): %s".error, res.code, err.message);
      }
    }

    res.data = envelope;
    next();
  },

  // Final middleware for handling all responses
  // Server actually responds to the request here
  finalResponse: function(req, res, next) {
    // If we timed out before managing to respond, don't send the response
    if (res.headerSent) {
      return;
    }

    // Respond with correct format, defaulting to json
    res.fmt = res.fmt || 'json';
    if (res.fmt === 'json') {
      // json
      res.jsonp(res.code, res.data);
    } else if (res.fmt === 'xml') {
      // xml
      res.set('Content-Type', 'application/xml; charset=utf-8');
      res.send(res.code, res.data);
    } else {
      // text or html
      res.send(res.code, res.data);
    }
  },

  // Render
  // ---

  renderModel: function(model) {
    return model.render();
  },

  renderCollection: function(collection) {
    return collection.map(function(model) {
      return model.render();
    });
  },

  // Helpers
  // ---

  // Gets any route middleware that may have been defined
  getRouteMiddleware: function(action) {
    // Find route middleware definitions
    var middleware = _.result(this, 'middleware');
    if (_.has(middleware, action)) {
      return middleware[action];
    } else {
      return [];
    }
  },

  // Parses req.query (querystring) for since/until, sort/order, skip/limit
  // Also builds a query using allowed queryParams if applicable
  parseQueryString: function(req) {
    var query = {};
    var queries = [];
    var options = {};

    // Reserved Params
    var since = req.query.since || req.query.from; // validate timestamp (s or ms) [DO NOT USE]
    var until = req.query.until || req.query.to; // validate timestamp (s or ms) [ DO NOT USE]
    var sortBy = req.query.sort || this.sortParam; // validate sortableParams
    var orderBy = req.query.order || this.sortOrder; // validate [asc, desc]
    var skip = req.query.skip || req.query.offset || this.skip; // validate int
    var limit = req.query.limit || req.query.count || this.limit; // validate int

    // Hard limit at 100
    limit = Math.min(limit, 100);

    // Build created, updated objects into the query string if sent in as dot notation
    _.each(req.query, function(obj, key) {
      var match;
      if (match = key.match(/(created|updated).(gte|lte|gt|lt)/)) {
        req.query[match[1]] = req.query[match[1]] || {};
        req.query[match[1]][match[2]] = parseInt(obj);
      }
    });

    var created = req.query.created || {}; // accepts both s and ms
    var updated = req.query.updated || {}; // accepts both s and ms

    // Convert all timestamps into integers
    _.each(created, function(timestamp, key) {
      created[key] = _.parseInt(timestamp);
    });

    _.each(updated, function(timestamp, key) {
      updated[key] = _.parseInt(timestamp);
    });

    // Query
    // Create date
    if (!_.isEmpty(created)) {
      var createdQuery = {
        created: {}
      };

      if (created.gte) {
        created.gte = _.isUnixTime(created.gte) ? created.gte * 1000 : created.gte;
        createdQuery.created["$gte"] = new Date(created.gte).getTime();
      } else if (created.gt) {
        created.gt = _.isUnixTime(created.gt) ? created.gt * 1000 : created.gt;
        createdQuery.created["$gt"] = new Date(created.gt).getTime();
      }

      if (created.lte) {
        created.lte = _.isUnixTime(created.lte) ? created.lte * 1000 : created.lte;
        createdQuery.created["$lte"] = new Date(created.lte).getTime();
      } else if (created.lt) {
        created.lt = _.isUnixTime(created.lt) ? created.lt * 1000 : created.lt;
        createdQuery.created["$lt"] = new Date(created.lt).getTime();
      }

      if (_.isNumber(created)) {
        created = _.isUnixTime(created) ? created * 1000 : created;
        createdQuery.created = new Date(created).getTime();
      }
      queries.push(createdQuery);
    }

    // Updated/modified date
    if (!_.isEmpty(updated)) {
      var updatedQuery = {
        updated: {}
      };

      if (updated.gte) {
        updated.gte = _.isUnixTime(updated.gte) ? updated.gte * 1000 : updated.gte;
        updatedQuery.updated["$gte"] = new Date(updated.gte).getTime();
      } else if (updated.gt) {
        updated.gt = _.isUnixTime(updated.gt) ? updated.gt * 1000 : updated.gt;
        updatedQuery.updated["$gt"] = new Date(updated.gt).getTime();
      }

      if (updated.lte) {
        updated.lte = _.isUnixTime(updated.lte) ? updated.lte * 1000 : updated.lte;
        updatedQuery.updated["$lte"] = new Date(updated.lte).getTime();
      } else if (updated.lt) {
        updated.lt = _.isUnixTime(updated.lt) ? updated.lt * 1000 : updated.lt;
        updatedQuery.created["$lt"] = new Date(updated.lt).getTime();
      }

      if (_.isNumber(updated)) {
        updated = _.isUnixTime(updated) ? updated * 1000 : updated;
        updatedQuery.updated = new Date(updated).getTime();
      }
      queries.push(updatedQuery);
    }

    // Since/Until Range
    if (since || until) {
      var sinceUntilQuery = {
        created: {}
      };

      if (since) {
        sinceUntilQuery.created["$gte"] = new Date(_.parseInt(since) * 1000).getTime();
      }

      if (until) {
        sinceUntilQuery.created["$lte"] = new Date(_.parseInt(until) * 1000).getTime();
      }

      queries.push(sinceUntilQuery);
    }

    // Filter Params
    var queryParams = _.extend(_.result(this, 'queryParams'), {
      "user_id": "string"
    });
    var filterParams = _.pick(req.query, _.keys(queryParams));

    _.each(filterParams, function(val, key) {
      // If value is all, ignore this param
      if (val === 'all') {
        return;
      }

      // Support `,` as `$or` for each param
      var vals = val.split(',');

      // No value, ignore this param
      if (vals.length === 0) {
        return;
      }

      // The built query filter
      var filter = {};

      // Get param type
      var type = queryParams[key];

      // Deal with different param types
      if (type === 'string') {
        // strings and objectid
        // no transformation
      } else if (type === 'regex') {
        // regex case insensitive and escaping special characters
        vals = _.map(vals, function(v) {
          return {
            // "$regex": '^' + _.escapeRegExp(v),
            "$regex": _.escapeRegExp(v),
            "$options": 'i'
          };
        });
        // filter[key] = {
        //   "$regex": '^' + _.escapeRegExp(val),
        //   "$options": 'i'
        // };
      } else if (type === 'integer') {
        // integers
        vals = _.map(vals, function(v) {
          return _.parseInt(v);
        });
        // val = _.parseInt(val);
      } else if (type === 'float') {
        // floats
        vals = _.map(vals, function(v) {
          return _.parseFloat(v);
        });
        // val = parseFloat(val);
      } else {
        // invalid or unknown type
        return;
      }

      // If there is only one val, no need to use `$or`
      if (vals.length === 1) {
        filter[key] = vals[0];
      } else {
        var orExpr = [];
        _.each(vals, function(orVal) {
          var orClause = {};
          orClause[key] = orVal;
          orExpr.push(orClause);
        });
        filter["$or"] = orExpr;
      }

      queries.push(filter);
    });

    // Combine the query
    if (queries.length > 0) {
      query['$and'] = queries;
    }

    // Options
    // Sort/Order/Limit/Skip
    var sortOptions = [
      [sortBy, orderBy]
    ];

    return {
      "query": query,
      "sort": sortOptions,
      "limit": parseInt(limit, 10),
      "skip": parseInt(skip, 10)
    };
  }

});<|endoftext|>


<commit_before>/* eslint-disable max-lines */
import uuid from 'uuid/v4';
import transmute from 'transmutation';
import whiteDeck from '../data/white-deck.json';

export default ({ db }) => {
    const entities = {
        player: ['player', ({ lead }) => db.get(`players/${lead.platform}/${lead.id}`)],
        queue: ['queue', () => db.get('queue')],
        game: ['game', ({ payload: { game } }) => db.get(`games/${game}`)],
        round: ['round', ({ game, payload: { round } }) => db.get(`rounds/${game.id}/${round}`)],
        hand: ['hand', ({ player, game }) => db.get(`hands/${game.id}/${player.id}`)],
        whiteDeck: ['whiteDeck', whiteDeck],
        pick: ['pick', ({ payload: { pick } }) => whiteDeck[pick]],
    };

    return {
        get: {
            login: transmute().extend(...entities.player),
            join: transmute()
                .extend(...entities.player)
                .extend(...entities.queue),
            hand: transmute()
                .extend(...entities.player)
                .extend(...entities.game)
                .extend(...entities.round)
                .extend(...entities.hand),
            pick: transmute()
                .extend(...entities.player)
                .extend(...entities.game)
                .extend(...entities.round)
                .extend(...entities.whiteDeck)
                .extend(...entities.pick),
        },
        save: {
            'welcome-message': transmute()
            .do(({ payload: lead }) =>
                db.set(`players/${lead.platform}/${lead.id}`, lead)),
            'welcome-back-message': transmute()
            .do(({ payload: { lead } }) =>
                db.set(`players/${lead.platform}/${lead.id}`, lead)),
            'queue-joined-message': transmute()
            .do(({ payload: { player } }) =>
                db.set(`queue/${player.id}`, player)),
            'game-started-message': transmute()
            .do(({ player, payload: { players } }) => {
                const id = uuid();
                db.set(`games/${id}`, {
                    id,
                    players,
                    notified_players: { [player.id]: player },
                });
                db.delete(Object.values(players).map(p => `queue/${p.id}`));
            }),
            'card-selected-message': transmute()
            .do(({ payload: { game, round, card }, player }) =>
                db.set(`rounds/${game.id}/${round.id}/candidates/${player.id}`, card))
            .do(({ payload: { game, card }, player }) =>
                db.delete([`hands/${game.id}/${player.id}/cards/${card.id}`])),
        },
    };
};
<commit_msg>Changed entities to get for readability.<commit_after>/* eslint-disable max-lines */
import uuid from 'uuid/v4';
import transmute from 'transmutation';
import whiteDeck from '../data/white-deck.json';

export default ({ db }) => {
    const get = {
        player: ['player', ({ lead }) => db.get(`players/${lead.platform}/${lead.id}`)],
        queue: ['queue', () => db.get('queue')],
        game: ['game', ({ payload: { game } }) => db.get(`games/${game}`)],
        round: ['round', ({ game, payload: { round } }) => db.get(`rounds/${game.id}/${round}`)],
        hand: ['hand', ({ player, game }) => db.get(`hands/${game.id}/${player.id}`)],
        whiteDeck: ['whiteDeck', whiteDeck],
        pick: ['pick', ({ payload: { pick } }) => whiteDeck[pick]],
    };

    return {
        get: {
            login: transmute().extend(...get.player),
            join: transmute()
                .extend(...get.player)
                .extend(...get.queue),
            hand: transmute()
                .extend(...get.player)
                .extend(...get.game)
                .extend(...get.round)
                .extend(...get.hand),
            pick: transmute()
                .extend(...get.player)
                .extend(...get.game)
                .extend(...get.round)
                .extend(...get.whiteDeck)
                .extend(...get.pick),
        },
        save: {
            'welcome-message': transmute()
            .do(({ payload: lead }) =>
                db.set(`players/${lead.platform}/${lead.id}`, lead)),
            'welcome-back-message': transmute()
            .do(({ payload: { lead } }) =>
                db.set(`players/${lead.platform}/${lead.id}`, lead)),
            'queue-joined-message': transmute()
            .do(({ payload: { player } }) =>
                db.set(`queue/${player.id}`, player)),
            'game-started-message': transmute()
            .do(({ player, payload: { players } }) => {
                const id = uuid();
                db.set(`games/${id}`, {
                    id,
                    players,
                    notified_players: { [player.id]: player },
                });
                db.delete(Object.values(players).map(p => `queue/${p.id}`));
            }),
            'card-selected-message': transmute()
            .do(({ payload: { game, round, card }, player }) =>
                db.set(`rounds/${game.id}/${round.id}/candidates/${player.id}`, card))
            .do(({ payload: { game, card }, player }) =>
                db.delete([`hands/${game.id}/${player.id}/cards/${card.id}`])),
        },
    };
};
<|endoftext|>


<commit_before>/**
 * @module ol/style/Icon
 */
import EventType from '../events/EventType.js';
import IconAnchorUnits from './IconAnchorUnits.js';
import IconOrigin from './IconOrigin.js';
import ImageState from '../ImageState.js';
import ImageStyle from './Image.js';
import {asArray} from '../color.js';
import {assert} from '../asserts.js';
import {get as getIconImage} from './IconImage.js';
import {getUid} from '../util.js';

/**
 * @typedef {Object} Options
 * @property {Array<number>} [anchor=[0.5, 0.5]] Anchor. Default value is the icon center.
 * @property {import("./IconOrigin.js").default} [anchorOrigin='top-left'] Origin of the anchor: `bottom-left`, `bottom-right`,
 * `top-left` or `top-right`.
 * @property {import("./IconAnchorUnits.js").default} [anchorXUnits='fraction'] Units in which the anchor x value is
 * specified. A value of `'fraction'` indicates the x value is a fraction of the icon. A value of `'pixels'` indicates
 * the x value in pixels.
 * @property {import("./IconAnchorUnits.js").default} [anchorYUnits='fraction'] Units in which the anchor y value is
 * specified. A value of `'fraction'` indicates the y value is a fraction of the icon. A value of `'pixels'` indicates
 * the y value in pixels.
 * @property {import("../color.js").Color|string} [color] Color to tint the icon. If not specified,
 * the icon will be left as is.
 * @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that you must provide a
 * `crossOrigin` value if you want to access pixel data with the Canvas renderer.
 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
 * @property {HTMLImageElement|HTMLCanvasElement} [img] Image object for the icon. If the `src` option is not provided then the
 * provided image must already be loaded. And in that case, it is required
 * to provide the size of the image, with the `imgSize` option.
 * @property {Array<number>} [offset=[0, 0]] Offset, which, together with the size and the offset origin, define the
 * sub-rectangle to use from the original icon image.
 * @property {Array<number>} [displacement=[0,0]] Displacement the icon
 * @property {import("./IconOrigin.js").default} [offsetOrigin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`,
 * `top-left` or `top-right`.
 * @property {number} [opacity=1] Opacity of the icon.
 * @property {number|import("../size.js").Size} [scale=1] Scale.
 * @property {boolean} [rotateWithView=false] Whether to rotate the icon with the view.
 * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
 * @property {import("../size.js").Size} [size] Icon size in pixel. Can be used together with `offset` to define the
 * sub-rectangle to use from the origin (sprite) icon image.
 * @property {import("../size.js").Size} [imgSize] Image size in pixels. Only required if `img` is set and `src` is not, and
 * for SVG images in Internet Explorer 11. The provided `imgSize` needs to match the actual size of the image.
 * @property {string} [src] Image source URI.
 */

/**
 * @classdesc
 * Set icon style for vector features.
 * @api
 */
class Icon extends ImageStyle {
  /**
   * @param {Options} [opt_options] Options.
   */
  constructor(opt_options) {
    const options = opt_options || {};

    /**
     * @type {number}
     */
    const opacity = options.opacity !== undefined ? options.opacity : 1;

    /**
     * @type {number}
     */
    const rotation = options.rotation !== undefined ? options.rotation : 0;

    /**
     * @type {number|import("../size.js").Size}
     */
    const scale = options.scale !== undefined ? options.scale : 1;

    /**
     * @type {boolean}
     */
    const rotateWithView =
      options.rotateWithView !== undefined ? options.rotateWithView : false;

    super({
      opacity: opacity,
      rotation: rotation,
      scale: scale,
      displacement:
        options.displacement !== undefined ? options.displacement : [0, 0],
      rotateWithView: rotateWithView,
    });

    /**
     * @private
     * @type {Array<number>}
     */
    this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5];

    /**
     * @private
     * @type {Array<number>}
     */
    this.normalizedAnchor_ = null;

    /**
     * @private
     * @type {import("./IconOrigin.js").default}
     */
    this.anchorOrigin_ =
      options.anchorOrigin !== undefined
        ? options.anchorOrigin
        : IconOrigin.TOP_LEFT;

    /**
     * @private
     * @type {import("./IconAnchorUnits.js").default}
     */
    this.anchorXUnits_ =
      options.anchorXUnits !== undefined
        ? options.anchorXUnits
        : IconAnchorUnits.FRACTION;

    /**
     * @private
     * @type {import("./IconAnchorUnits.js").default}
     */
    this.anchorYUnits_ =
      options.anchorYUnits !== undefined
        ? options.anchorYUnits
        : IconAnchorUnits.FRACTION;

    /**
     * @private
     * @type {?string}
     */
    this.crossOrigin_ =
      options.crossOrigin !== undefined ? options.crossOrigin : null;

    /**
     * @type {HTMLImageElement|HTMLCanvasElement}
     */
    const image = options.img !== undefined ? options.img : null;

    /**
     * @type {import("../size.js").Size}
     */
    const imgSize = options.imgSize !== undefined ? options.imgSize : null;

    /**
     * @type {string|undefined}
     */
    let src = options.src;

    assert(!(src !== undefined && image), 4); // `image` and `src` cannot be provided at the same time
    assert(!image || (image && imgSize), 5); // `imgSize` must be set when `image` is provided

    if ((src === undefined || src.length === 0) && image) {
      src = /** @type {HTMLImageElement} */ (image).src || getUid(image);
    }
    assert(src !== undefined && src.length > 0, 6); // A defined and non-empty `src` or `image` must be provided

    /**
     * @type {import("../ImageState.js").default}
     */
    const imageState =
      options.src !== undefined ? ImageState.IDLE : ImageState.LOADED;

    /**
     * @private
     * @type {import("../color.js").Color}
     */
    this.color_ = options.color !== undefined ? asArray(options.color) : null;

    /**
     * @private
     * @type {import("./IconImage.js").default}
     */
    this.iconImage_ = getIconImage(
      image,
      /** @type {string} */ (src),
      imgSize,
      this.crossOrigin_,
      imageState,
      this.color_
    );

    /**
     * @private
     * @type {Array<number>}
     */
    this.offset_ = options.offset !== undefined ? options.offset : [0, 0];
    /**
     * @private
     * @type {import("./IconOrigin.js").default}
     */
    this.offsetOrigin_ =
      options.offsetOrigin !== undefined
        ? options.offsetOrigin
        : IconOrigin.TOP_LEFT;

    /**
     * @private
     * @type {Array<number>}
     */
    this.origin_ = null;

    /**
     * @private
     * @type {import("../size.js").Size}
     */
    this.size_ = options.size !== undefined ? options.size : null;
  }

  /**
   * Clones the style. The underlying Image/HTMLCanvasElement is not cloned.
   * @return {Icon} The cloned style.
   * @api
   */
  clone() {
    const scale = this.getScale();
    return new Icon({
      anchor: this.anchor_.slice(),
      anchorOrigin: this.anchorOrigin_,
      anchorXUnits: this.anchorXUnits_,
      anchorYUnits: this.anchorYUnits_,
      crossOrigin: this.crossOrigin_,
      color:
        this.color_ && this.color_.slice
          ? this.color_.slice()
          : this.color_ || undefined,
      src: this.getSrc(),
      offset: this.offset_.slice(),
      offsetOrigin: this.offsetOrigin_,
      size: this.size_ !== null ? this.size_.slice() : undefined,
      opacity: this.getOpacity(),
      scale: Array.isArray(scale) ? scale.slice() : scale,
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
    });
  }

  /**
   * Get the anchor point in pixels. The anchor determines the center point for the
   * symbolizer.
   * @return {Array<number>} Anchor.
   * @api
   */
  getAnchor() {
    if (this.normalizedAnchor_) {
      return this.normalizedAnchor_;
    }
    let anchor = this.anchor_;
    const size = this.getSize();
    if (
      this.anchorXUnits_ == IconAnchorUnits.FRACTION ||
      this.anchorYUnits_ == IconAnchorUnits.FRACTION
    ) {
      if (!size) {
        return null;
      }
      anchor = this.anchor_.slice();
      if (this.anchorXUnits_ == IconAnchorUnits.FRACTION) {
        anchor[0] *= size[0];
      }
      if (this.anchorYUnits_ == IconAnchorUnits.FRACTION) {
        anchor[1] *= size[1];
      }
    }

    if (this.anchorOrigin_ != IconOrigin.TOP_LEFT) {
      if (!size) {
        return null;
      }
      if (anchor === this.anchor_) {
        anchor = this.anchor_.slice();
      }
      if (
        this.anchorOrigin_ == IconOrigin.TOP_RIGHT ||
        this.anchorOrigin_ == IconOrigin.BOTTOM_RIGHT
      ) {
        anchor[0] = -anchor[0] + size[0];
      }
      if (
        this.anchorOrigin_ == IconOrigin.BOTTOM_LEFT ||
        this.anchorOrigin_ == IconOrigin.BOTTOM_RIGHT
      ) {
        anchor[1] = -anchor[1] + size[1];
      }
    }
    const displacement = this.getDisplacement();
    anchor[0] -= displacement[0];
    anchor[1] += displacement[1];

    this.normalizedAnchor_ = anchor;
    return this.normalizedAnchor_;
  }

  /**
   * Set the anchor point. The anchor determines the center point for the
   * symbolizer.
   *
   * @param {Array<number>} anchor Anchor.
   * @api
   */
  setAnchor(anchor) {
    this.anchor_ = anchor;
    this.normalizedAnchor_ = null;
  }

  /**
   * Get the icon color.
   * @return {import("../color.js").Color} Color.
   * @api
   */
  getColor() {
    return this.color_;
  }

  /**
   * Get the image icon.
   * @param {number} pixelRatio Pixel ratio.
   * @return {HTMLImageElement|HTMLCanvasElement} Image or Canvas element.
   * @api
   */
  getImage(pixelRatio) {
    return this.iconImage_.getImage(pixelRatio);
  }

  /**
   * Get the pixel ratio.
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} The pixel ratio of the image.
   * @api
   */
  getPixelRatio(pixelRatio) {
    return this.iconImage_.getPixelRatio(pixelRatio);
  }

  /**
   * @return {import("../size.js").Size} Image size.
   */
  getImageSize() {
    return this.iconImage_.getSize();
  }

  /**
   * @return {import("../ImageState.js").default} Image state.
   */
  getImageState() {
    return this.iconImage_.getImageState();
  }

  /**
   * @return {HTMLImageElement|HTMLCanvasElement} Image element.
   */
  getHitDetectionImage() {
    return this.iconImage_.getHitDetectionImage();
  }

  /**
   * Get the origin of the symbolizer.
   * @return {Array<number>} Origin.
   * @api
   */
  getOrigin() {
    if (this.origin_) {
      return this.origin_;
    }
    let offset = this.offset_;

    if (this.offsetOrigin_ != IconOrigin.TOP_LEFT) {
      const size = this.getSize();
      const iconImageSize = this.iconImage_.getSize();
      if (!size || !iconImageSize) {
        return null;
      }
      offset = offset.slice();
      if (
        this.offsetOrigin_ == IconOrigin.TOP_RIGHT ||
        this.offsetOrigin_ == IconOrigin.BOTTOM_RIGHT
      ) {
        offset[0] = iconImageSize[0] - size[0] - offset[0];
      }
      if (
        this.offsetOrigin_ == IconOrigin.BOTTOM_LEFT ||
        this.offsetOrigin_ == IconOrigin.BOTTOM_RIGHT
      ) {
        offset[1] = iconImageSize[1] - size[1] - offset[1];
      }
    }
    this.origin_ = offset;
    return this.origin_;
  }

  /**
   * Get the image URL.
   * @return {string|undefined} Image src.
   * @api
   */
  getSrc() {
    return this.iconImage_.getSrc();
  }

  /**
   * Get the size of the icon (in pixels).
   * @return {import("../size.js").Size} Image size.
   * @api
   */
  getSize() {
    return !this.size_ ? this.iconImage_.getSize() : this.size_;
  }

  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   */
  listenImageChange(listener) {
    this.iconImage_.addEventListener(EventType.CHANGE, listener);
  }

  /**
   * Load not yet loaded URI.
   * When rendering a feature with an icon style, the vector renderer will
   * automatically call this method. However, you might want to call this
   * method yourself for preloading or other purposes.
   * @api
   */
  load() {
    this.iconImage_.load();
  }

  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   */
  unlistenImageChange(listener) {
    this.iconImage_.removeEventListener(EventType.CHANGE, listener);
  }
}

export default Icon;
<commit_msg>handle updateable displacement<commit_after>/**
 * @module ol/style/Icon
 */
import EventType from '../events/EventType.js';
import IconAnchorUnits from './IconAnchorUnits.js';
import IconOrigin from './IconOrigin.js';
import ImageState from '../ImageState.js';
import ImageStyle from './Image.js';
import {asArray} from '../color.js';
import {assert} from '../asserts.js';
import {get as getIconImage} from './IconImage.js';
import {getUid} from '../util.js';

/**
 * @typedef {Object} Options
 * @property {Array<number>} [anchor=[0.5, 0.5]] Anchor. Default value is the icon center.
 * @property {import("./IconOrigin.js").default} [anchorOrigin='top-left'] Origin of the anchor: `bottom-left`, `bottom-right`,
 * `top-left` or `top-right`.
 * @property {import("./IconAnchorUnits.js").default} [anchorXUnits='fraction'] Units in which the anchor x value is
 * specified. A value of `'fraction'` indicates the x value is a fraction of the icon. A value of `'pixels'` indicates
 * the x value in pixels.
 * @property {import("./IconAnchorUnits.js").default} [anchorYUnits='fraction'] Units in which the anchor y value is
 * specified. A value of `'fraction'` indicates the y value is a fraction of the icon. A value of `'pixels'` indicates
 * the y value in pixels.
 * @property {import("../color.js").Color|string} [color] Color to tint the icon. If not specified,
 * the icon will be left as is.
 * @property {null|string} [crossOrigin] The `crossOrigin` attribute for loaded images. Note that you must provide a
 * `crossOrigin` value if you want to access pixel data with the Canvas renderer.
 * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.
 * @property {HTMLImageElement|HTMLCanvasElement} [img] Image object for the icon. If the `src` option is not provided then the
 * provided image must already be loaded. And in that case, it is required
 * to provide the size of the image, with the `imgSize` option.
 * @property {Array<number>} [offset=[0, 0]] Offset, which, together with the size and the offset origin, define the
 * sub-rectangle to use from the original icon image.
 * @property {Array<number>} [displacement=[0,0]] Displacement of the icon.
 * @property {import("./IconOrigin.js").default} [offsetOrigin='top-left'] Origin of the offset: `bottom-left`, `bottom-right`,
 * `top-left` or `top-right`.
 * @property {number} [opacity=1] Opacity of the icon.
 * @property {number|import("../size.js").Size} [scale=1] Scale.
 * @property {boolean} [rotateWithView=false] Whether to rotate the icon with the view.
 * @property {number} [rotation=0] Rotation in radians (positive rotation clockwise).
 * @property {import("../size.js").Size} [size] Icon size in pixel. Can be used together with `offset` to define the
 * sub-rectangle to use from the origin (sprite) icon image.
 * @property {import("../size.js").Size} [imgSize] Image size in pixels. Only required if `img` is set and `src` is not, and
 * for SVG images in Internet Explorer 11. The provided `imgSize` needs to match the actual size of the image.
 * @property {string} [src] Image source URI.
 */

/**
 * @classdesc
 * Set icon style for vector features.
 * @api
 */
class Icon extends ImageStyle {
  /**
   * @param {Options} [opt_options] Options.
   */
  constructor(opt_options) {
    const options = opt_options || {};

    /**
     * @type {number}
     */
    const opacity = options.opacity !== undefined ? options.opacity : 1;

    /**
     * @type {number}
     */
    const rotation = options.rotation !== undefined ? options.rotation : 0;

    /**
     * @type {number|import("../size.js").Size}
     */
    const scale = options.scale !== undefined ? options.scale : 1;

    /**
     * @type {boolean}
     */
    const rotateWithView =
      options.rotateWithView !== undefined ? options.rotateWithView : false;

    super({
      opacity: opacity,
      rotation: rotation,
      scale: scale,
      displacement:
        options.displacement !== undefined ? options.displacement : [0, 0],
      rotateWithView: rotateWithView,
    });

    /**
     * @private
     * @type {Array<number>}
     */
    this.anchor_ = options.anchor !== undefined ? options.anchor : [0.5, 0.5];

    /**
     * @private
     * @type {Array<number>}
     */
    this.normalizedAnchor_ = null;

    /**
     * @private
     * @type {import("./IconOrigin.js").default}
     */
    this.anchorOrigin_ =
      options.anchorOrigin !== undefined
        ? options.anchorOrigin
        : IconOrigin.TOP_LEFT;

    /**
     * @private
     * @type {import("./IconAnchorUnits.js").default}
     */
    this.anchorXUnits_ =
      options.anchorXUnits !== undefined
        ? options.anchorXUnits
        : IconAnchorUnits.FRACTION;

    /**
     * @private
     * @type {import("./IconAnchorUnits.js").default}
     */
    this.anchorYUnits_ =
      options.anchorYUnits !== undefined
        ? options.anchorYUnits
        : IconAnchorUnits.FRACTION;

    /**
     * @private
     * @type {?string}
     */
    this.crossOrigin_ =
      options.crossOrigin !== undefined ? options.crossOrigin : null;

    /**
     * @type {HTMLImageElement|HTMLCanvasElement}
     */
    const image = options.img !== undefined ? options.img : null;

    /**
     * @type {import("../size.js").Size}
     */
    const imgSize = options.imgSize !== undefined ? options.imgSize : null;

    /**
     * @type {string|undefined}
     */
    let src = options.src;

    assert(!(src !== undefined && image), 4); // `image` and `src` cannot be provided at the same time
    assert(!image || (image && imgSize), 5); // `imgSize` must be set when `image` is provided

    if ((src === undefined || src.length === 0) && image) {
      src = /** @type {HTMLImageElement} */ (image).src || getUid(image);
    }
    assert(src !== undefined && src.length > 0, 6); // A defined and non-empty `src` or `image` must be provided

    /**
     * @type {import("../ImageState.js").default}
     */
    const imageState =
      options.src !== undefined ? ImageState.IDLE : ImageState.LOADED;

    /**
     * @private
     * @type {import("../color.js").Color}
     */
    this.color_ = options.color !== undefined ? asArray(options.color) : null;

    /**
     * @private
     * @type {import("./IconImage.js").default}
     */
    this.iconImage_ = getIconImage(
      image,
      /** @type {string} */ (src),
      imgSize,
      this.crossOrigin_,
      imageState,
      this.color_
    );

    /**
     * @private
     * @type {Array<number>}
     */
    this.offset_ = options.offset !== undefined ? options.offset : [0, 0];
    /**
     * @private
     * @type {import("./IconOrigin.js").default}
     */
    this.offsetOrigin_ =
      options.offsetOrigin !== undefined
        ? options.offsetOrigin
        : IconOrigin.TOP_LEFT;

    /**
     * @private
     * @type {Array<number>}
     */
    this.origin_ = null;

    /**
     * @private
     * @type {import("../size.js").Size}
     */
    this.size_ = options.size !== undefined ? options.size : null;
  }

  /**
   * Clones the style. The underlying Image/HTMLCanvasElement is not cloned.
   * @return {Icon} The cloned style.
   * @api
   */
  clone() {
    const scale = this.getScale();
    return new Icon({
      anchor: this.anchor_.slice(),
      anchorOrigin: this.anchorOrigin_,
      anchorXUnits: this.anchorXUnits_,
      anchorYUnits: this.anchorYUnits_,
      crossOrigin: this.crossOrigin_,
      color:
        this.color_ && this.color_.slice
          ? this.color_.slice()
          : this.color_ || undefined,
      src: this.getSrc(),
      offset: this.offset_.slice(),
      offsetOrigin: this.offsetOrigin_,
      size: this.size_ !== null ? this.size_.slice() : undefined,
      opacity: this.getOpacity(),
      scale: Array.isArray(scale) ? scale.slice() : scale,
      rotation: this.getRotation(),
      rotateWithView: this.getRotateWithView(),
    });
  }

  /**
   * Get the anchor point in pixels. The anchor determines the center point for the
   * symbolizer.
   * @return {Array<number>} Anchor.
   * @api
   */
  getAnchor() {
    let anchor = this.normalizedAnchor_;
    if (!anchor) {
      anchor = this.anchor_;
      const size = this.getSize();
      if (
        this.anchorXUnits_ == IconAnchorUnits.FRACTION ||
        this.anchorYUnits_ == IconAnchorUnits.FRACTION
      ) {
        if (!size) {
          return null;
        }
        anchor = this.anchor_.slice();
        if (this.anchorXUnits_ == IconAnchorUnits.FRACTION) {
          anchor[0] *= size[0];
        }
        if (this.anchorYUnits_ == IconAnchorUnits.FRACTION) {
          anchor[1] *= size[1];
        }
      }

      if (this.anchorOrigin_ != IconOrigin.TOP_LEFT) {
        if (!size) {
          return null;
        }
        if (anchor === this.anchor_) {
          anchor = this.anchor_.slice();
        }
        if (
          this.anchorOrigin_ == IconOrigin.TOP_RIGHT ||
          this.anchorOrigin_ == IconOrigin.BOTTOM_RIGHT
        ) {
          anchor[0] = -anchor[0] + size[0];
        }
        if (
          this.anchorOrigin_ == IconOrigin.BOTTOM_LEFT ||
          this.anchorOrigin_ == IconOrigin.BOTTOM_RIGHT
        ) {
          anchor[1] = -anchor[1] + size[1];
        }
      }
      this.normalizedAnchor_ = anchor;
    }
    const displacement = this.getDisplacement();
    return [anchor[0] - displacement[0], anchor[1] + displacement[1]];
  }

  /**
   * Set the anchor point. The anchor determines the center point for the
   * symbolizer.
   *
   * @param {Array<number>} anchor Anchor.
   * @api
   */
  setAnchor(anchor) {
    this.anchor_ = anchor;
    this.normalizedAnchor_ = null;
  }

  /**
   * Get the icon color.
   * @return {import("../color.js").Color} Color.
   * @api
   */
  getColor() {
    return this.color_;
  }

  /**
   * Get the image icon.
   * @param {number} pixelRatio Pixel ratio.
   * @return {HTMLImageElement|HTMLCanvasElement} Image or Canvas element.
   * @api
   */
  getImage(pixelRatio) {
    return this.iconImage_.getImage(pixelRatio);
  }

  /**
   * Get the pixel ratio.
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} The pixel ratio of the image.
   * @api
   */
  getPixelRatio(pixelRatio) {
    return this.iconImage_.getPixelRatio(pixelRatio);
  }

  /**
   * @return {import("../size.js").Size} Image size.
   */
  getImageSize() {
    return this.iconImage_.getSize();
  }

  /**
   * @return {import("../ImageState.js").default} Image state.
   */
  getImageState() {
    return this.iconImage_.getImageState();
  }

  /**
   * @return {HTMLImageElement|HTMLCanvasElement} Image element.
   */
  getHitDetectionImage() {
    return this.iconImage_.getHitDetectionImage();
  }

  /**
   * Get the origin of the symbolizer.
   * @return {Array<number>} Origin.
   * @api
   */
  getOrigin() {
    if (this.origin_) {
      return this.origin_;
    }
    let offset = this.offset_;

    if (this.offsetOrigin_ != IconOrigin.TOP_LEFT) {
      const size = this.getSize();
      const iconImageSize = this.iconImage_.getSize();
      if (!size || !iconImageSize) {
        return null;
      }
      offset = offset.slice();
      if (
        this.offsetOrigin_ == IconOrigin.TOP_RIGHT ||
        this.offsetOrigin_ == IconOrigin.BOTTOM_RIGHT
      ) {
        offset[0] = iconImageSize[0] - size[0] - offset[0];
      }
      if (
        this.offsetOrigin_ == IconOrigin.BOTTOM_LEFT ||
        this.offsetOrigin_ == IconOrigin.BOTTOM_RIGHT
      ) {
        offset[1] = iconImageSize[1] - size[1] - offset[1];
      }
    }
    this.origin_ = offset;
    return this.origin_;
  }

  /**
   * Get the image URL.
   * @return {string|undefined} Image src.
   * @api
   */
  getSrc() {
    return this.iconImage_.getSrc();
  }

  /**
   * Get the size of the icon (in pixels).
   * @return {import("../size.js").Size} Image size.
   * @api
   */
  getSize() {
    return !this.size_ ? this.iconImage_.getSize() : this.size_;
  }

  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   */
  listenImageChange(listener) {
    this.iconImage_.addEventListener(EventType.CHANGE, listener);
  }

  /**
   * Load not yet loaded URI.
   * When rendering a feature with an icon style, the vector renderer will
   * automatically call this method. However, you might want to call this
   * method yourself for preloading or other purposes.
   * @api
   */
  load() {
    this.iconImage_.load();
  }

  /**
   * @param {function(import("../events/Event.js").default): void} listener Listener function.
   */
  unlistenImageChange(listener) {
    this.iconImage_.removeEventListener(EventType.CHANGE, listener);
  }
}

export default Icon;
<|endoftext|>


<commit_before>import React, { Fragment } from 'react'
import {
  Container,
  Heading,
  Box,
  Text,
  Section,
  Flex,
  Card,
  cx
} from '@hackclub/design-system'
import Helmet from 'react-helmet'
import YouTubePlayer from 'react-player/lib/players/YouTube'
import Nav from 'components/Nav'
import Invert from 'components/Invert'
import Footer from 'components/Footer'
import { kebabCase } from 'lodash'

const Header = Section.withComponent('header')

const Calendar = Flex.extend`
  flex-direction: column;
  flex-shrink: 0;
  text-align: center;
  border-width: 4px;
  width: 96px;
  height: 96px;
  border-color: ${props => cx(props.color)};
  border-style: solid;
  border-radius: 12px;
  font-weight: ${props => props.theme.bold};
`
const Year = Text.extend.attrs({
  f: 3,
  py: 1,
  color: 'white'
})`
  line-height: 1;
`
const Month = Text.extend.attrs({ f: 4, mt: 1 })`
  line-height: 2;
`

const Updater = Container.withComponent(Flex).extend`
  flex-direction: column;
  align-items: center;
  ${props => props.theme.mediaQueries.md} {
    flex-direction: row;
    align-items: flex-start;
    justify-content: center;
  }
`
const Sheet = Card.extend`
  box-sizing: border-box;
  width: 100%;
  max-width: 48rem;
  max-height: 24rem;
  position: relative;
  padding-top: 55%;
  overflow: hidden;
  box-shadow: ${props => props.theme.boxShadows[1]};
  transition: 0.25s ease-out box-shadow;
  &:hover {
    box-shadow: ${props => props.theme.boxShadows[2]};
  }
  ${props => props.theme.mediaQueries.md} {
    padding-top: 41.25%; // NOTE(@lachlanjc): i just guessed until i found this
  }
`
const Player = Box.withComponent(YouTubePlayer).extend`
  position: absolute;
  top: 0;
  left: 0;
`

const Update = ({ month, year, color = 'primary', url, ...props }) => (
  <Updater
    mb={5}
    px={3}
    className="invert"
    id={kebabCase(`${month.replace('.', '')}-${year}`)}
  >
    <Calendar color={color} mb={3} mr={[null, 3, 4]}>
      <Year bg={color} children={year} />
      <Month color={color} children={month} />
    </Calendar>
    <Sheet>
      <Player
        url={url}
        width="100%"
        height="100%"
        controls
        config={{ youtube: { playerVars: { showinfo: 1 } } }}
      />
    </Sheet>
  </Updater>
)

const title = 'Monthly Updates – Hack Club'
const desc =
  'Watch all of Hack Club’s monthly update videos on what’s new in our community of high school coding clubs.'
const img = 'https://hackclub.com/updates.png'

export default () => (
  <Fragment>
    <Helmet
      title={title}
      meta={[
        { name: 'description', content: desc },
        { name: 'twitter:title', content: title },
        { name: 'twitter:description', content: desc },
        { name: 'twitter:image', content: img },
        { property: 'og:title', content: title },
        { property: 'og:description', content: desc },
        { property: 'og:image', content: img },
        { property: 'og:url', content: 'https://hackclub.com/updates' }
      ]}
    />
    <Nav invertFlag color="slate" style={{ position: 'absolute', top: 0 }} />
    <style children={`body{background:${cx('snow')};}`} />
    <Header py={4} align="center" justify="center">
      <Container mt={5} maxWidth={32}>
        <Heading.h1 color="black" f={6}>
          Updates
        </Heading.h1>
        <Text f={4} color="muted" style={{ lineHeight: '1.25' }}>
          Every month we produce a video update with what’s new at Hack Club.
          Here they all are!
        </Text>
      </Container>
      <Invert children="Theater mode" muted my={3} />
    </Header>
    <Container pb={4}>
      <Update
        color="lime.6"
        month="April"
        year={2018}
        url="https://youtu.be/q1BOuOhPvbg"
      />
      <Update
        color="teal.6"
        month="March"
        year={2018}
        url="https://youtu.be/Xj32LuE44bU"
      />
    </Container>
    <Footer />
  </Fragment>
)
<commit_msg>Add May update<commit_after>import React, { Fragment } from 'react'
import {
  Container,
  Heading,
  Box,
  Text,
  Section,
  Flex,
  Card,
  cx
} from '@hackclub/design-system'
import Helmet from 'react-helmet'
import YouTubePlayer from 'react-player/lib/players/YouTube'
import Nav from 'components/Nav'
import Invert from 'components/Invert'
import Footer from 'components/Footer'
import { kebabCase } from 'lodash'

const Header = Section.withComponent('header')

const Calendar = Flex.extend`
  flex-direction: column;
  flex-shrink: 0;
  text-align: center;
  border-width: 4px;
  width: 96px;
  height: 96px;
  border-color: ${props => cx(props.color)};
  border-style: solid;
  border-radius: 12px;
  font-weight: ${props => props.theme.bold};
`
const Year = Text.extend.attrs({
  f: 3,
  py: 1,
  color: 'white'
})`
  line-height: 1;
`
const Month = Text.extend.attrs({ f: 4, mt: 1 })`
  line-height: 2;
`

const Updater = Container.withComponent(Flex).extend`
  flex-direction: column;
  align-items: center;
  ${props => props.theme.mediaQueries.md} {
    flex-direction: row;
    align-items: flex-start;
    justify-content: center;
  }
`
const Sheet = Card.extend`
  box-sizing: border-box;
  width: 100%;
  max-width: 48rem;
  max-height: 24rem;
  position: relative;
  padding-top: 55%;
  overflow: hidden;
  box-shadow: ${props => props.theme.boxShadows[1]};
  transition: 0.25s ease-out box-shadow;
  &:hover {
    box-shadow: ${props => props.theme.boxShadows[2]};
  }
  ${props => props.theme.mediaQueries.md} {
    padding-top: 41.25%; // NOTE(@lachlanjc): i just guessed until i found this
  }
`
const Player = Box.withComponent(YouTubePlayer).extend`
  position: absolute;
  top: 0;
  left: 0;
`

const Update = ({ month, year, color = 'primary', url, ...props }) => (
  <Updater
    mb={5}
    px={3}
    className="invert"
    id={kebabCase(`${month.replace('.', '')}-${year}`)}
  >
    <Calendar color={color} mb={3} mr={[null, 3, 4]}>
      <Year bg={color} children={year} />
      <Month color={color} children={month} />
    </Calendar>
    <Sheet>
      <Player
        url={url}
        width="100%"
        height="100%"
        controls
        config={{ youtube: { playerVars: { showinfo: 1 } } }}
      />
    </Sheet>
  </Updater>
)

const title = 'Monthly Updates – Hack Club'
const desc =
  'Watch all of Hack Club’s monthly update videos on what’s new in our community of high school coding clubs.'
const img = 'https://hackclub.com/updates.png'

export default () => (
  <Fragment>
    <Helmet
      title={title}
      meta={[
        { name: 'description', content: desc },
        { name: 'twitter:title', content: title },
        { name: 'twitter:description', content: desc },
        { name: 'twitter:image', content: img },
        { property: 'og:title', content: title },
        { property: 'og:description', content: desc },
        { property: 'og:image', content: img },
        { property: 'og:url', content: 'https://hackclub.com/updates' }
      ]}
    />
    <Nav invertFlag color="slate" style={{ position: 'absolute', top: 0 }} />
    <style children={`body{background:${cx('snow')};}`} />
    <Header py={4} align="center" justify="center">
      <Container mt={5} maxWidth={32}>
        <Heading.h1 color="black" f={6}>
          Updates
        </Heading.h1>
        <Text f={4} color="muted" style={{ lineHeight: '1.25' }}>
          Every month we produce a video update with what’s new at Hack Club.
          Here they all are!
        </Text>
      </Container>
      <Invert children="Theater mode" muted my={3} />
    </Header>
    <Container pb={4}>
      <Update
        color="green.6"
        month="May"
        year={2018}
        url="https://youtu.be/_u8_U52ebao"
      />
      <Update
        color="teal.7"
        month="April"
        year={2018}
        url="https://youtu.be/q1BOuOhPvbg"
      />
      <Update
        color="cyan.8"
        month="March"
        year={2018}
        url="https://youtu.be/Xj32LuE44bU"
      />
    </Container>
    <Footer />
  </Fragment>
)
<|endoftext|>