diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 319eb0ca100b5aae62b669a5f375ec234aabe351..654ec9502b982d1052334b85fdd109a79850eda1 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -3,6 +3,7 @@
     <!-- Base application theme. -->
     <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
         <!-- Customize your theme here. -->
+        <item name="android:colorEdgeEffect">#aaaaaa</item>
     </style>
 
 </resources>
diff --git a/android/gradle.properties b/android/gradle.properties
index 1fd964e90b1c5ec50e26364318e2c872a9dd6154..732c56e3e4ea85b8250df9d758b957fcc428d466 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -18,3 +18,4 @@
 # org.gradle.parallel=true
 
 android.useDeprecatedNdk=true
+# VERSIONCODE=999999999
diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js
index b4123946b42b09d56bdbcd01c7f36860c9be4f5f..4e67c7478aa29454603fdd134db45dc0931b80f6 100644
--- a/app/actions/actionsTypes.js
+++ b/app/actions/actionsTypes.js
@@ -55,7 +55,8 @@ export const MESSAGES = createRequestTypes('MESSAGES', [
 	'TOGGLE_PIN_SUCCESS',
 	'TOGGLE_PIN_FAILURE',
 	'SET_INPUT',
-	'CLEAR_INPUT'
+	'CLEAR_INPUT',
+	'TOGGLE_REACTION_PICKER'
 ]);
 export const CREATE_CHANNEL = createRequestTypes('CREATE_CHANNEL', [
 	...defaultTypes,
diff --git a/app/actions/messages.js b/app/actions/messages.js
index 29c1b4ca9c1e94296fca4670a6752b124124e5ad..ed9bf4971e4ecb0596ff0e53cd70bf871a53d71c 100644
--- a/app/actions/messages.js
+++ b/app/actions/messages.js
@@ -176,3 +176,10 @@ export function clearInput() {
 		type: types.MESSAGES.CLEAR_INPUT
 	};
 }
+
+export function toggleReactionPicker(message) {
+	return {
+		type: types.MESSAGES.TOGGLE_REACTION_PICKER,
+		message
+	};
+}
diff --git a/app/containers/CustomEmoji.js b/app/containers/EmojiPicker/CustomEmoji.js
similarity index 77%
rename from app/containers/CustomEmoji.js
rename to app/containers/EmojiPicker/CustomEmoji.js
index 166e065abfa58199811234e9b9f9d6094cb7a935..5988296f3100272779735445c994244a5f9ddd39 100644
--- a/app/containers/CustomEmoji.js
+++ b/app/containers/EmojiPicker/CustomEmoji.js
@@ -6,19 +6,21 @@ import { connect } from 'react-redux';
 @connect(state => ({
 	baseUrl: state.settings.Site_Url
 }))
-export default class extends React.PureComponent {
+export default class extends React.Component {
 	static propTypes = {
 		baseUrl: PropTypes.string.isRequired,
 		emoji: PropTypes.object.isRequired,
 		style: PropTypes.object
 	}
-
+	shouldComponentUpdate() {
+		return false;
+	}
 	render() {
 		const { baseUrl, emoji, style } = this.props;
 		return (
 			<CachedImage
 				style={style}
-				source={{ uri: `${ baseUrl }/emoji-custom/${ encodeURIComponent(emoji.content) }.${ emoji.extension }` }}
+				source={{ uri: `${ baseUrl }/emoji-custom/${ encodeURIComponent(emoji.content || emoji.name) }.${ emoji.extension }` }}
 			/>
 		);
 	}
diff --git a/app/containers/EmojiPicker/EmojiCategory.js b/app/containers/EmojiPicker/EmojiCategory.js
new file mode 100644
index 0000000000000000000000000000000000000000..0fc3c65d76e4af4bb69adb689c0c5c920b5cee94
--- /dev/null
+++ b/app/containers/EmojiPicker/EmojiCategory.js
@@ -0,0 +1,80 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Text, View, TouchableOpacity, Platform } from 'react-native';
+import { emojify } from 'react-emojione';
+import { responsive } from 'react-native-responsive-ui';
+import styles from './styles';
+import CustomEmoji from './CustomEmoji';
+
+
+const emojisPerRow = Platform.OS === 'ios' ? 8 : 9;
+
+const renderEmoji = (emoji, size) => {
+	if (emoji.isCustom) {
+		return <CustomEmoji style={[styles.customCategoryEmoji, { height: size - 8, width: size - 8 }]} emoji={emoji} />;
+	}
+	return (
+		<Text style={[styles.categoryEmoji, { height: size, width: size, fontSize: size - 14 }]}>
+			{emojify(`:${ emoji }:`, { output: 'unicode' })}
+		</Text>
+	);
+};
+
+
+const nextFrame = () => new Promise(resolve => requestAnimationFrame(resolve));
+
+@responsive
+export default class EmojiCategory extends React.Component {
+	static propTypes = {
+		emojis: PropTypes.any,
+		window: PropTypes.any,
+		onEmojiSelected: PropTypes.func,
+		emojisPerRow: PropTypes.number,
+		width: PropTypes.number
+	};
+	constructor(props) {
+		super(props);
+		const { width, height } = this.props.window;
+
+		this.size = Math.min(this.props.width || width, height) / (this.props.emojisPerRow || emojisPerRow);
+		this.emojis = [];
+	}
+	componentWillMount() {
+		this.emojis = this.props.emojis.slice(0, emojisPerRow * 3).map(item => this.renderItem(item, this.size));
+	}
+	async componentDidMount() {
+		const array = this.props.emojis;
+		const temparray = [];
+		let i;
+		let j;
+		const chunk = emojisPerRow * 3;
+		for (i = chunk, j = array.length; i < j; i += chunk) {
+			temparray.push(array.slice(i, i + chunk));
+		}
+		temparray.forEach(async(items) => {
+			await nextFrame();
+			this.emojis = this.emojis.concat(items.map(item => this.renderItem(item, this.size)));
+			this.forceUpdate();
+			await nextFrame();
+		});
+	}
+
+	shouldComponentUpdate() {
+		return false;
+	}
+
+	renderItem(emoji, size) {
+		return (
+			<TouchableOpacity
+				activeOpacity={0.7}
+				key={emoji.isCustom ? emoji.content : emoji}
+				onPress={() => this.props.onEmojiSelected(emoji)}
+			>
+				{renderEmoji(emoji, size)}
+			</TouchableOpacity>);
+	}
+
+	render() {
+		return <View style={styles.categoryInner}>{this.emojis}</View>;
+	}
+}
diff --git a/app/containers/MessageBox/EmojiPicker/TabBar.js b/app/containers/EmojiPicker/TabBar.js
similarity index 66%
rename from app/containers/MessageBox/EmojiPicker/TabBar.js
rename to app/containers/EmojiPicker/TabBar.js
index 9bc131a46916c9664c2371eb2ab51597348255f2..fb23b30ea9bf7a5704fbed5cd498a9da8b8679d8 100644
--- a/app/containers/MessageBox/EmojiPicker/TabBar.js
+++ b/app/containers/EmojiPicker/TabBar.js
@@ -7,15 +7,21 @@ export default class extends React.PureComponent {
 	static propTypes = {
 		goToPage: PropTypes.func,
 		activeTab: PropTypes.number,
-		tabs: PropTypes.array
+		tabs: PropTypes.array,
+		tabEmojiStyle: PropTypes.object
 	}
 
 	render() {
 		return (
 			<View style={styles.tabsContainer}>
 				{this.props.tabs.map((tab, i) => (
-					<TouchableOpacity activeOpacity={0.7} key={tab} onPress={() => this.props.goToPage(i)} style={styles.tab}>
-						<Text style={styles.tabEmoji}>{tab}</Text>
+					<TouchableOpacity
+						activeOpacity={0.7}
+						key={tab}
+						onPress={() => this.props.goToPage(i)}
+						style={styles.tab}
+					>
+						<Text style={[styles.tabEmoji, this.props.tabEmojiStyle]}>{tab}</Text>
 						{this.props.activeTab === i ? <View style={styles.activeTabLine} /> : <View style={styles.tabLine} />}
 					</TouchableOpacity>
 				))}
diff --git a/app/containers/MessageBox/EmojiPicker/categories.js b/app/containers/EmojiPicker/categories.js
similarity index 75%
rename from app/containers/MessageBox/EmojiPicker/categories.js
rename to app/containers/EmojiPicker/categories.js
index 341c6a83e1d695bc340e25d0a7cbc52d913c979c..a95f67cf6945e7454e150097e6d513b11dc469e1 100644
--- a/app/containers/MessageBox/EmojiPicker/categories.js
+++ b/app/containers/EmojiPicker/categories.js
@@ -1,4 +1,4 @@
-const list = ['Frequently Used', 'Custom', 'Smileys & People', 'Animals & Nature', 'Food & Drink', 'Activities', 'Travel & Places', 'Objects', 'Symbols', 'Flags'];
+const list = ['frequentlyUsed', 'custom', 'people', 'nature', 'food', 'activity', 'travel', 'objects', 'symbols', 'flags'];
 const tabs = [
 	{
 		tabLabel: '🕒',
diff --git a/app/containers/MessageBox/EmojiPicker/index.js b/app/containers/EmojiPicker/index.js
similarity index 50%
rename from app/containers/MessageBox/EmojiPicker/index.js
rename to app/containers/EmojiPicker/index.js
index fbddf4c7885d8c40444c04e9e08637a7d32e2029..4209b5cc8463efb93ded4ab62ccba37fb3cf1046 100644
--- a/app/containers/MessageBox/EmojiPicker/index.js
+++ b/app/containers/EmojiPicker/index.js
@@ -1,35 +1,32 @@
-import 'string.fromcodepoint';
-import React, { PureComponent } from 'react';
+import React, { Component } from 'react';
 import PropTypes from 'prop-types';
-import { ScrollView, View } from 'react-native';
+import { ScrollView } from 'react-native';
 import ScrollableTabView from 'react-native-scrollable-tab-view';
-import emojiDatasource from 'emoji-datasource/emoji.json';
 import _ from 'lodash';
-import { groupBy, orderBy } from 'lodash/collection';
-import { mapValues } from 'lodash/object';
+import { emojify } from 'react-emojione';
 import TabBar from './TabBar';
 import EmojiCategory from './EmojiCategory';
 import styles from './styles';
 import categories from './categories';
-import scrollPersistTaps from '../../../utils/scrollPersistTaps';
-import database from '../../../lib/realm';
+import scrollPersistTaps from '../../utils/scrollPersistTaps';
+import database from '../../lib/realm';
+import { emojisByCategory } from '../../emojis';
 
-const charFromUtf16 = utf16 => String.fromCodePoint(...utf16.split('-').map(u => `0x${ u }`));
-const charFromEmojiObj = obj => charFromUtf16(obj.unified);
+const scrollProps = {
+	keyboardShouldPersistTaps: 'always'
+};
 
-const filteredEmojis = emojiDatasource.filter(e => parseFloat(e.added_in) < 10.0);
-const groupedAndSorted = groupBy(orderBy(filteredEmojis, 'sort_order'), 'category');
-const emojisByCategory = mapValues(groupedAndSorted, group => group.map(charFromEmojiObj));
-
-export default class extends PureComponent {
+export default class extends Component {
 	static propTypes = {
-		onEmojiSelected: PropTypes.func
+		onEmojiSelected: PropTypes.func,
+		tabEmojiStyle: PropTypes.object,
+		emojisPerRow: PropTypes.number,
+		width: PropTypes.number
 	};
 
 	constructor(props) {
 		super(props);
 		this.state = {
-			categories: categories.list.slice(0, 1),
 			frequentlyUsed: [],
 			customEmojis: []
 		};
@@ -38,16 +35,22 @@ export default class extends PureComponent {
 		this.updateFrequentlyUsed = this.updateFrequentlyUsed.bind(this);
 		this.updateCustomEmojis = this.updateCustomEmojis.bind(this);
 	}
+	//
+	// shouldComponentUpdate(nextProps) {
+	// 	return false;
+	// }
 
 	componentWillMount() {
 		this.frequentlyUsed.addListener(this.updateFrequentlyUsed);
 		this.customEmojis.addListener(this.updateCustomEmojis);
 		this.updateFrequentlyUsed();
 		this.updateCustomEmojis();
+		setTimeout(() => this.setState({ show: true }), 100);
 	}
 
 	componentWillUnmount() {
-		clearTimeout(this._timeout);
+		this.frequentlyUsed.removeAllListeners();
+		this.customEmojis.removeAllListeners();
 	}
 
 	onEmojiSelected(emoji) {
@@ -58,10 +61,11 @@ export default class extends PureComponent {
 			});
 			this.props.onEmojiSelected(`:${ emoji.content }:`);
 		} else {
-			const content = emoji.codePointAt(0).toString();
+			const content = emoji;
 			const count = this._getFrequentlyUsedCount(content);
 			this._addFrequentlyUsed({ content, count, isCustom: false });
-			this.props.onEmojiSelected(emoji);
+			const shortname = `:${ emoji }:`;
+			this.props.onEmojiSelected(emojify(shortname, { output: 'unicode' }), shortname);
 		}
 	}
 	_addFrequentlyUsed = (emoji) => {
@@ -78,22 +82,17 @@ export default class extends PureComponent {
 			if (item.isCustom) {
 				return item;
 			}
-			return String.fromCodePoint(item.content);
+			return emojify(`${ item.content }`, { output: 'unicode' });
 		});
 		this.setState({ frequentlyUsed });
 	}
 
 	updateCustomEmojis() {
-		const customEmojis = _.map(this.customEmojis.slice(), item => ({ content: item.name, extension: item.extension, isCustom: true }));
+		const customEmojis = _.map(this.customEmojis.slice(), item =>
+			({ content: item.name, extension: item.extension, isCustom: true }));
 		this.setState({ customEmojis });
 	}
 
-	loadNextCategory() {
-		if (this.state.categories.length < categories.list.length) {
-			this.setState({ categories: categories.list.slice(0, this.state.categories.length + 1) });
-		}
-	}
-
 	renderCategory(category, i) {
 		let emojis = [];
 		if (i === 0) {
@@ -104,40 +103,39 @@ export default class extends PureComponent {
 			emojis = emojisByCategory[category];
 		}
 		return (
-			<View style={styles.categoryContainer}>
-				<EmojiCategory
-					key={category}
-					emojis={emojis}
-					onEmojiSelected={emoji => this.onEmojiSelected(emoji)}
-					finishedLoading={() => { this._timeout = setTimeout(this.loadNextCategory.bind(this), 100); }}
-				/>
-			</View>
+			<EmojiCategory
+				emojis={emojis}
+				onEmojiSelected={emoji => this.onEmojiSelected(emoji)}
+				style={styles.categoryContainer}
+				size={this.props.emojisPerRow}
+				width={this.props.width}
+			/>
 		);
 	}
 
 	render() {
-		const scrollProps = {
-			keyboardShouldPersistTaps: 'always'
-		};
+		if (!this.state.show) {
+			return null;
+		}
 		return (
-			<View style={styles.container}>
-				<ScrollableTabView
-					renderTabBar={() => <TabBar />}
-					contentProps={scrollProps}
-				>
-					{
-						_.map(categories.tabs, (tab, i) => (
-							<ScrollView
-								key={i}
-								tabLabel={tab.tabLabel}
-								{...scrollPersistTaps}
-							>
-								{this.renderCategory(tab.category, i)}
-							</ScrollView>
-						))
-					}
-				</ScrollableTabView>
-			</View>
+			// <View style={styles.container}>
+			<ScrollableTabView
+				renderTabBar={() => <TabBar tabEmojiStyle={this.props.tabEmojiStyle} />}
+				contentProps={scrollProps}
+			>
+				{
+					categories.tabs.map((tab, i) => (
+						<ScrollView
+							key={tab.category}
+							tabLabel={tab.tabLabel}
+							{...scrollPersistTaps}
+						>
+							{this.renderCategory(tab.category, i)}
+						</ScrollView>
+					))
+				}
+			</ScrollableTabView>
+			// </View>
 		);
 	}
 }
diff --git a/app/containers/MessageBox/EmojiPicker/styles.js b/app/containers/EmojiPicker/styles.js
similarity index 70%
rename from app/containers/MessageBox/EmojiPicker/styles.js
rename to app/containers/EmojiPicker/styles.js
index a4ffdb598ade24e245f3b32e60b860fd14f597d4..038d11b20ceeab0c7fd48157364a003bc2880d69 100644
--- a/app/containers/MessageBox/EmojiPicker/styles.js
+++ b/app/containers/EmojiPicker/styles.js
@@ -1,7 +1,4 @@
-import { StyleSheet, Dimensions, Platform } from 'react-native';
-
-const { width } = Dimensions.get('window');
-const EMOJI_SIZE = width / (Platform.OS === 'ios' ? 8 : 9);
+import { StyleSheet } from 'react-native';
 
 export default StyleSheet.create({
 	container: {
@@ -45,18 +42,16 @@ export default StyleSheet.create({
 	categoryInner: {
 		flexWrap: 'wrap',
 		flexDirection: 'row',
-		alignItems: 'center'
+		alignItems: 'center',
+		justifyContent: 'flex-start',
+		flex: 1
 	},
 	categoryEmoji: {
-		fontSize: EMOJI_SIZE - 14,
 		color: 'black',
-		height: EMOJI_SIZE,
-		width: EMOJI_SIZE,
+		backgroundColor: 'transparent',
 		textAlign: 'center'
 	},
 	customCategoryEmoji: {
-		height: EMOJI_SIZE - 8,
-		width: EMOJI_SIZE - 8,
 		margin: 4
 	}
 });
diff --git a/app/containers/MessageActions.js b/app/containers/MessageActions.js
index 56b33fcd5314422f2f686eb5bdba6895ccad7029..c7ed5d2c4dffac6474e2d197a0b5018121156881 100644
--- a/app/containers/MessageActions.js
+++ b/app/containers/MessageActions.js
@@ -13,7 +13,8 @@ import {
 	permalinkClear,
 	togglePinRequest,
 	setInput,
-	actionsHide
+	actionsHide,
+	toggleReactionPicker
 } from '../actions/messages';
 import { showToast } from '../utils/info';
 
@@ -39,7 +40,8 @@ import { showToast } from '../utils/info';
 		permalinkRequest: message => dispatch(permalinkRequest(message)),
 		permalinkClear: () => dispatch(permalinkClear()),
 		togglePinRequest: message => dispatch(togglePinRequest(message)),
-		setInput: message => dispatch(setInput(message))
+		setInput: message => dispatch(setInput(message)),
+		toggleReactionPicker: message => dispatch(toggleReactionPicker(message))
 	})
 )
 export default class MessageActions extends React.Component {
@@ -58,6 +60,7 @@ export default class MessageActions extends React.Component {
 		togglePinRequest: PropTypes.func.isRequired,
 		setInput: PropTypes.func.isRequired,
 		permalink: PropTypes.string,
+		toggleReactionPicker: PropTypes.func.isRequired,
 		Message_AllowDeleting: PropTypes.bool,
 		Message_AllowDeleting_BlockDeleteInMinutes: PropTypes.number,
 		Message_AllowEditing: PropTypes.bool,
@@ -119,6 +122,11 @@ export default class MessageActions extends React.Component {
 				this.options.push(actionMessage.pinned ? 'Unpin' : 'Pin');
 				this.PIN_INDEX = this.options.length - 1;
 			}
+			// Reaction
+			if (!this.isRoomReadOnly()) {
+				this.options.push('Add Reaction');
+				this.REACTION_INDEX = this.options.length - 1;
+			}
 			// Delete
 			if (this.allowDelete(nextProps)) {
 				this.options.push('Delete');
@@ -275,6 +283,10 @@ export default class MessageActions extends React.Component {
 		this.props.permalinkRequest(this.props.actionMessage);
 	}
 
+	handleReaction() {
+		this.props.toggleReactionPicker(this.props.actionMessage);
+	}
+
 	handleActionPress = (actionIndex) => {
 		switch (actionIndex) {
 			case this.REPLY_INDEX:
@@ -298,6 +310,9 @@ export default class MessageActions extends React.Component {
 			case this.PIN_INDEX:
 				this.handlePin();
 				break;
+			case this.REACTION_INDEX:
+				this.handleReaction();
+				break;
 			case this.DELETE_INDEX:
 				this.handleDelete();
 				break;
diff --git a/app/containers/MessageBox/EmojiPicker/EmojiCategory.js b/app/containers/MessageBox/EmojiPicker/EmojiCategory.js
deleted file mode 100644
index e4c648b1b972c42c6e851e6e038080b722d2e778..0000000000000000000000000000000000000000
--- a/app/containers/MessageBox/EmojiPicker/EmojiCategory.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Text, View, TouchableOpacity, StyleSheet } from 'react-native';
-import styles from './styles';
-import CustomEmoji from '../../CustomEmoji';
-
-export default class extends React.PureComponent {
-	static propTypes = {
-		emojis: PropTypes.any,
-		finishedLoading: PropTypes.func,
-		onEmojiSelected: PropTypes.func
-	};
-
-	componentDidMount() {
-		this.props.finishedLoading();
-	}
-
-	renderEmoji = (emoji) => {
-		if (emoji.isCustom) {
-			const style = StyleSheet.flatten(styles.customCategoryEmoji);
-			return <CustomEmoji style={style} emoji={emoji} />;
-		}
-		return (
-			<Text style={styles.categoryEmoji}>
-				{emoji}
-			</Text>
-		);
-	}
-
-	render() {
-		const { emojis } = this.props;
-		return (
-			<View>
-				<View style={styles.categoryInner}>
-					{emojis.map(emoji =>
-						(
-							<TouchableOpacity
-								activeOpacity={0.7}
-								key={emoji.isCustom ? emoji.content : emoji}
-								onPress={() => this.props.onEmojiSelected(emoji)}
-							>
-								{this.renderEmoji(emoji)}
-							</TouchableOpacity>
-						))}
-				</View>
-			</View>
-		);
-	}
-}
diff --git a/app/containers/MessageBox/index.js b/app/containers/MessageBox/index.js
index 9fd862569e0a3ef8eb91dfec872dae1a532a6c18..b5f8aa3f23a49a67dcd1c7d4d189c91e5a42d002 100644
--- a/app/containers/MessageBox/index.js
+++ b/app/containers/MessageBox/index.js
@@ -1,9 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { View, TextInput, SafeAreaView, FlatList, Text, TouchableOpacity, Keyboard } from 'react-native';
+import { View, TextInput, SafeAreaView, FlatList, Text, TouchableOpacity, Keyboard, StyleSheet } from 'react-native';
 import Icon from 'react-native-vector-icons/MaterialIcons';
 import ImagePicker from 'react-native-image-picker';
 import { connect } from 'react-redux';
+import { emojify } from 'react-emojione';
 import { userTyping } from '../../actions/room';
 import RocketChat from '../../lib/rocketchat';
 import { editRequest, editCancel, clearInput } from '../../actions/messages';
@@ -11,11 +12,14 @@ import styles from './style';
 import MyIcon from '../icons';
 import database from '../../lib/realm';
 import Avatar from '../Avatar';
+import CustomEmoji from '../EmojiPicker/CustomEmoji';
 import AnimatedContainer from './AnimatedContainer';
-import EmojiPicker from './EmojiPicker';
+import EmojiPicker from '../EmojiPicker';
 import scrollPersistTaps from '../../utils/scrollPersistTaps';
+import { emojis } from '../../emojis';
 
 const MENTIONS_TRACKING_TYPE_USERS = '@';
+const MENTIONS_TRACKING_TYPE_EMOJIS = ':';
 
 const onlyUnique = function onlyUnique(value, index, self) {
 	return self.indexOf(({ _id }) => value._id === _id) === index;
@@ -54,10 +58,13 @@ export default class MessageBox extends React.PureComponent {
 			text: '',
 			mentions: [],
 			showMentionsContainer: false,
-			showEmojiContainer: false
+			showEmojiContainer: false,
+			trackingType: ''
 		};
 		this.users = [];
 		this.rooms = [];
+		this.emojis = [];
+		this.customEmojis = [];
 	}
 	componentWillReceiveProps(nextProps) {
 		if (this.props.message !== nextProps.message && nextProps.message.msg) {
@@ -80,7 +87,7 @@ export default class MessageBox extends React.PureComponent {
 
 			const lastNativeText = this.component._lastNativeText;
 
-			const regexp = /(#|@)([a-z._-]+)$/im;
+			const regexp = /(#|@|:)([a-z0-9._-]+)$/im;
 
 			const result = lastNativeText.substr(0, cursor).match(regexp);
 
@@ -176,7 +183,10 @@ export default class MessageBox extends React.PureComponent {
 		this.setState({ text: '' });
 	}
 	async openEmoji() {
-		await this.setState({ showEmojiContainer: !this.state.showEmojiContainer });
+		await this.setState({
+			showEmojiContainer: true,
+			showMentionsContainer: false
+		});
 		Keyboard.dismiss();
 	}
 	closeEmoji() {
@@ -292,25 +302,41 @@ export default class MessageBox extends React.PureComponent {
 		}
 	}
 
+	_getEmojis(keyword) {
+		if (keyword) {
+			this.customEmojis = database.objects('customEmojis').filtered('name CONTAINS[c] $0', keyword).slice(0, 4);
+			this.emojis = emojis.filter(emoji => emoji.indexOf(keyword) !== -1).slice(0, 4);
+			const mergedEmojis = [...this.customEmojis, ...this.emojis];
+			this.setState({ mentions: mergedEmojis });
+		}
+	}
+
 	stopTrackingMention() {
 		this.setState({
 			showMentionsContainer: false,
-			mentions: []
+			mentions: [],
+			trackingType: ''
 		});
 		this.users = [];
 		this.rooms = [];
+		this.customEmojis = [];
+		this.emojis = [];
 	}
 
 	identifyMentionKeyword(keyword, type) {
-		this.updateMentions(keyword, type);
 		this.setState({
-			showMentionsContainer: true
+			showMentionsContainer: true,
+			showEmojiContainer: false,
+			trackingType: type
 		});
+		this.updateMentions(keyword, type);
 	}
 
 	updateMentions = (keyword, type) => {
 		if (type === MENTIONS_TRACKING_TYPE_USERS) {
 			this._getUsers(keyword);
+		} else if (type === MENTIONS_TRACKING_TYPE_EMOJIS) {
+			this._getEmojis(keyword);
 		} else {
 			this._getRooms(keyword);
 		}
@@ -323,10 +349,12 @@ export default class MessageBox extends React.PureComponent {
 
 		const cursor = Math.max(start, end);
 
-		const regexp = /([a-z._-]+)$/im;
+		const regexp = /([a-z0-9._-]+)$/im;
 
 		const result = msg.substr(0, cursor).replace(regexp, '');
-		const text = `${ result }${ item.username || item.name } ${ msg.slice(cursor) }`;
+		const mentionName = this.state.trackingType === MENTIONS_TRACKING_TYPE_EMOJIS ?
+			`${ item.name || item }:` : (item.username || item.name);
+		const text = `${ result }${ mentionName } ${ msg.slice(cursor) }`;
 		this.component.setNativeProps({ text });
 		this.setState({ text });
 		this.component.focus();
@@ -357,6 +385,26 @@ export default class MessageBox extends React.PureComponent {
 			<Text>Notify {item.desc} in this room</Text>
 		</TouchableOpacity>
 	)
+	renderMentionEmoji = (item) => {
+		if (item.name) {
+			return (
+				<CustomEmoji
+					key='mention-item-avatar'
+					style={[styles.mentionItemCustomEmoji]}
+					emoji={item}
+					baseUrl={this.props.baseUrl}
+				/>
+			);
+		}
+		return (
+			<Text
+				key='mention-item-avatar'
+				style={[StyleSheet.flatten(styles.mentionItemEmoji)]}
+			>
+				{emojify(`:${ item }:`, { output: 'unicode' })}
+			</Text>
+		);
+	}
 	renderMentionItem = (item) => {
 		if (item.username === 'all' || item.username === 'here') {
 			return this.renderFixedMentionItem(item);
@@ -366,13 +414,22 @@ export default class MessageBox extends React.PureComponent {
 				style={styles.mentionItem}
 				onPress={() => this._onPressMention(item)}
 			>
-				<Avatar
-					style={{ margin: 8 }}
-					text={item.username || item.name}
-					size={30}
-					baseUrl={this.props.baseUrl}
-				/>
-				<Text>{item.username || item.name }</Text>
+				{this.state.trackingType === MENTIONS_TRACKING_TYPE_EMOJIS ?
+					[
+						this.renderMentionEmoji(item),
+						<Text key='mention-item-name'>:{ item.name || item }:</Text>
+					]
+					: [
+						<Avatar
+							key='mention-item-avatar'
+							style={{ margin: 8 }}
+							text={item.username || item.name}
+							size={30}
+							baseUrl={this.props.baseUrl}
+						/>,
+						<Text key='mention-item-name'>{ item.username || item.name }</Text>
+					]
+				}
 			</TouchableOpacity>
 		);
 	}
@@ -386,17 +443,17 @@ export default class MessageBox extends React.PureComponent {
 		return <AnimatedContainer visible={showEmojiContainer} subview={emojiContainer} messageboxHeight={messageboxHeight} />;
 	}
 	renderMentions() {
-		const usersList = (
+		const list = (
 			<FlatList
 				style={styles.mentionList}
 				data={this.state.mentions}
 				renderItem={({ item }) => this.renderMentionItem(item)}
-				keyExtractor={item => item._id}
+				keyExtractor={item => item._id || item}
 				{...scrollPersistTaps}
 			/>
 		);
 		const { showMentionsContainer, messageboxHeight } = this.state;
-		return <AnimatedContainer visible={showMentionsContainer} subview={usersList} messageboxHeight={messageboxHeight} />;
+		return <AnimatedContainer visible={showMentionsContainer} subview={list} messageboxHeight={messageboxHeight} />;
 	}
 	render() {
 		return (
diff --git a/app/containers/MessageBox/style.js b/app/containers/MessageBox/style.js
index 298a69ee6ec3e1afa0746826c9877b5e40029b04..98395ce4fddb6dcc71b23d3ef16a240049919ad5 100644
--- a/app/containers/MessageBox/style.js
+++ b/app/containers/MessageBox/style.js
@@ -1,4 +1,4 @@
-import { StyleSheet } from 'react-native';
+import { StyleSheet, Platform } from 'react-native';
 
 const MENTION_HEIGHT = 50;
 
@@ -83,6 +83,17 @@ export default StyleSheet.create({
 		borderTopWidth: 1,
 		backgroundColor: '#fff'
 	},
+	mentionItemCustomEmoji: {
+		margin: 8,
+		width: 30,
+		height: 30
+	},
+	mentionItemEmoji: {
+		width: 46,
+		height: 36,
+		fontSize: Platform.OS === 'ios' ? 30 : 25,
+		textAlign: 'center'
+	},
 	fixedMentionAvatar: {
 		fontWeight: 'bold',
 		textAlign: 'center',
diff --git a/app/containers/message/Emoji.js b/app/containers/message/Emoji.js
new file mode 100644
index 0000000000000000000000000000000000000000..95c0489a93900e4abce726aebf8adae029c78d3d
--- /dev/null
+++ b/app/containers/message/Emoji.js
@@ -0,0 +1,26 @@
+import React from 'react';
+import { Text } from 'react-native';
+import PropTypes from 'prop-types';
+import { emojify } from 'react-emojione';
+import CustomEmoji from '../EmojiPicker/CustomEmoji';
+
+export default class Emoji extends React.PureComponent {
+	static propTypes = {
+		content: PropTypes.string,
+		standardEmojiStyle: PropTypes.object,
+		customEmojiStyle: PropTypes.object,
+		customEmojis: PropTypes.object.isRequired
+	};
+	render() {
+		const {
+			content, standardEmojiStyle, customEmojiStyle, customEmojis
+		} = this.props;
+		const parsedContent = content.replace(/^:|:$/g, '');
+		const emojiExtension = customEmojis[parsedContent];
+		if (emojiExtension) {
+			const emoji = { extension: emojiExtension, content: parsedContent };
+			return <CustomEmoji key={content} style={customEmojiStyle} emoji={emoji} />;
+		}
+		return <Text style={standardEmojiStyle}>{ emojify(`${ content }`, { output: 'unicode' }) }</Text>;
+	}
+}
diff --git a/app/containers/message/Markdown.js b/app/containers/message/Markdown.js
index 3fab10a453dccf817086055c82ce5cb1bc92c45e..14b82f6d7cc50729e1e9c3a7785d70a798845a71 100644
--- a/app/containers/message/Markdown.js
+++ b/app/containers/message/Markdown.js
@@ -5,7 +5,7 @@ import EasyMarkdown from 'react-native-easy-markdown'; // eslint-disable-line
 import SimpleMarkdown from 'simple-markdown';
 import { emojify } from 'react-emojione';
 import styles from './styles';
-import CustomEmoji from '../CustomEmoji';
+import CustomEmoji from '../EmojiPicker/CustomEmoji';
 
 const BlockCode = ({ node, state }) => (
 	<Text
diff --git a/app/containers/message/ReactionsModal.js b/app/containers/message/ReactionsModal.js
new file mode 100644
index 0000000000000000000000000000000000000000..c62dab65cfecdae84c4819a02b47897053fc8f23
--- /dev/null
+++ b/app/containers/message/ReactionsModal.js
@@ -0,0 +1,124 @@
+import React from 'react';
+import { View, Text, TouchableWithoutFeedback, FlatList, StyleSheet } from 'react-native';
+import PropTypes from 'prop-types';
+import Modal from 'react-native-modal';
+import Icon from 'react-native-vector-icons/MaterialIcons';
+import Emoji from './Emoji';
+
+const styles = StyleSheet.create({
+	titleContainer: {
+		width: '100%',
+		alignItems: 'center',
+		paddingVertical: 10
+	},
+	title: {
+		color: '#ffffff',
+		textAlign: 'center',
+		fontSize: 16,
+		fontWeight: '600'
+	},
+	reactCount: {
+		color: '#dddddd',
+		fontSize: 10
+	},
+	peopleReacted: {
+		color: '#ffffff',
+		fontWeight: '500'
+	},
+	peopleItemContainer: {
+		flex: 1,
+		flexDirection: 'column',
+		justifyContent: 'center'
+	},
+	emojiContainer: {
+		width: 50,
+		height: 50,
+		alignItems: 'center',
+		justifyContent: 'center'
+	},
+	itemContainer: {
+		height: 50,
+		flexDirection: 'row'
+	},
+	listContainer: {
+		flex: 1
+	},
+	closeButton: {
+		position: 'absolute',
+		left: 0,
+		top: 10,
+		color: '#ffffff'
+	}
+});
+const standardEmojiStyle = { fontSize: 20 };
+const customEmojiStyle = { width: 20, height: 20 };
+export default class extends React.PureComponent {
+	static propTypes = {
+		isVisible: PropTypes.bool.isRequired,
+		onClose: PropTypes.func.isRequired,
+		reactions: PropTypes.object.isRequired,
+		user: PropTypes.object.isRequired,
+		customEmojis: PropTypes.object.isRequired
+	}
+	renderItem = (item) => {
+		const count = item.usernames.length;
+		let usernames = item.usernames.slice(0, 3)
+			.map(username => (username.value === this.props.user.username ? 'you' : username.value)).join(', ');
+		if (count > 3) {
+			usernames = `${ usernames } and more ${ count - 3 }`;
+		} else {
+			usernames = usernames.replace(/,(?=[^,]*$)/, ' and');
+		}
+		return (
+			<View style={styles.itemContainer}>
+				<View style={styles.emojiContainer}>
+					<Emoji
+						content={item.emoji}
+						standardEmojiStyle={standardEmojiStyle}
+						customEmojiStyle={customEmojiStyle}
+						customEmojis={this.props.customEmojis}
+					/>
+				</View>
+				<View style={styles.peopleItemContainer}>
+					<Text style={styles.reactCount}>
+						{count === 1 ? '1 person' : `${ count } people`} reacted
+					</Text>
+					<Text style={styles.peopleReacted}>{ usernames }</Text>
+				</View>
+			</View>
+		);
+	}
+
+	render() {
+		const {
+			isVisible, onClose, reactions
+		} = this.props;
+		return (
+			<Modal
+				isVisible={isVisible}
+				onBackdropPress={onClose}
+				onBackButtonPress={onClose}
+				backdropOpacity={0.9}
+			>
+				<TouchableWithoutFeedback onPress={onClose}>
+					<View style={styles.titleContainer}>
+						<Icon
+							style={styles.closeButton}
+							name='close'
+							size={20}
+							onPress={onClose}
+						/>
+						<Text style={styles.title}>Reactions</Text>
+					</View>
+				</TouchableWithoutFeedback>
+				<View style={styles.listContainer}>
+					<FlatList
+						data={reactions}
+						renderItem={({ item }) => this.renderItem(item)}
+						keyExtractor={item => item.emoji}
+					/>
+				</View>
+			</Modal>
+		);
+	}
+}
diff --git a/app/containers/message/Url.js b/app/containers/message/Url.js
index 6fe6cdddb2ccf471670d696ab0304a38b543c985..5ec48a9996a608d6c5a9f358bb6bfcf803561e6f 100644
--- a/app/containers/message/Url.js
+++ b/app/containers/message/Url.js
@@ -52,10 +52,13 @@ const Url = ({ url }) => {
 	return (
 		<TouchableOpacity onPress={() => onPress(url.url)} style={styles.button}>
 			<QuoteMark />
-			<Image
-				style={styles.image}
-				source={{ uri: encodeURI(url.image) }}
-			/>
+			{url.image ?
+				<Image
+					style={styles.image}
+					source={{ uri: encodeURI(url.image) }}
+				/>
+				: null
+			}
 			<View style={styles.textContainer}>
 				<Text style={styles.title}>{url.title}</Text>
 				<Text style={styles.description} numberOfLines={1}>{url.description}</Text>
diff --git a/app/containers/message/index.js b/app/containers/message/index.js
index f57bb5e1433459800b703cf99314dbe8b7278467..840cfa0b2a7ca0c48e85eca19eb00f04ac6409df 100644
--- a/app/containers/message/index.js
+++ b/app/containers/message/index.js
@@ -1,11 +1,12 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { View, TouchableHighlight, Text, TouchableOpacity, Animated, Keyboard } from 'react-native';
+import { View, TouchableHighlight, Text, TouchableOpacity, Animated, Keyboard, StyleSheet, Vibration } from 'react-native';
 import { connect } from 'react-redux';
 import Icon from 'react-native-vector-icons/MaterialIcons';
 import moment from 'moment';
+import equal from 'deep-equal';
 
-import { actionsShow, errorActionsShow } from '../../actions/messages';
+import { actionsShow, errorActionsShow, toggleReactionPicker } from '../../actions/messages';
 import Image from './Image';
 import User from './User';
 import Avatar from '../Avatar';
@@ -14,6 +15,8 @@ import Video from './Video';
 import Markdown from './Markdown';
 import Url from './Url';
 import Reply from './Reply';
+import ReactionsModal from './ReactionsModal';
+import Emoji from './Emoji';
 import messageStatus from '../../constants/messagesStatus';
 import styles from './styles';
 
@@ -26,11 +29,13 @@ const flex = { flexDirection: 'row', flex: 1 };
 	customEmojis: state.customEmojis
 }), dispatch => ({
 	actionsShow: actionMessage => dispatch(actionsShow(actionMessage)),
-	errorActionsShow: actionMessage => dispatch(errorActionsShow(actionMessage))
+	errorActionsShow: actionMessage => dispatch(errorActionsShow(actionMessage)),
+	toggleReactionPicker: message => dispatch(toggleReactionPicker(message))
 }))
 export default class Message extends React.Component {
 	static propTypes = {
 		item: PropTypes.object.isRequired,
+		reactions: PropTypes.object.isRequired,
 		baseUrl: PropTypes.string.isRequired,
 		Message_TimeFormat: PropTypes.string.isRequired,
 		message: PropTypes.object.isRequired,
@@ -39,7 +44,15 @@ export default class Message extends React.Component {
 		actionsShow: PropTypes.func,
 		errorActionsShow: PropTypes.func,
 		animate: PropTypes.bool,
-		customEmojis: PropTypes.object
+		customEmojis: PropTypes.object,
+		toggleReactionPicker: PropTypes.func,
+		onReactionPress: PropTypes.func
+	}
+
+	constructor(props) {
+		super(props);
+		this.state = { reactionsModal: false };
+		this.onClose = this.onClose.bind(this);
 	}
 
 	componentWillMount() {
@@ -60,7 +73,13 @@ export default class Message extends React.Component {
 		}
 	}
 
-	shouldComponentUpdate(nextProps) {
+	shouldComponentUpdate(nextProps, nextState) {
+		if (!equal(this.props.reactions, nextProps.reactions)) {
+			return true;
+		}
+		if (this.state.reactionsModal !== nextState.reactionsModal) {
+			return true;
+		}
 		return this.props.item._updatedAt.toGMTString() !== nextProps.item._updatedAt.toGMTString() || this.props.item.status !== nextProps.item.status;
 	}
 
@@ -69,13 +88,22 @@ export default class Message extends React.Component {
 	}
 
 	onLongPress() {
-		const { item } = this.props;
-		this.props.actionsShow(JSON.parse(JSON.stringify(item)));
+		this.props.actionsShow(this.parseMessage());
 	}
 
 	onErrorPress() {
-		const { item } = this.props;
-		this.props.errorActionsShow(JSON.parse(JSON.stringify(item)));
+		this.props.errorActionsShow(this.parseMessage());
+	}
+
+	onReactionPress(emoji) {
+		this.props.onReactionPress(emoji, this.props.item._id);
+	}
+	onClose() {
+		this.setState({ reactionsModal: false });
+	}
+	onReactionLongPress() {
+		this.setState({ reactionsModal: true });
+		Vibration.vibrate(50);
 	}
 
 	getInfoMessage() {
@@ -105,11 +133,12 @@ export default class Message extends React.Component {
 		return message;
 	}
 
+	parseMessage = () => JSON.parse(JSON.stringify(this.props.item));
+
 	isInfoMessage() {
 		return ['r', 'au', 'ru', 'ul', 'uj', 'rm', 'user-muted', 'user-unmuted', 'message_pinned'].includes(this.props.item.t);
 	}
 
-
 	isDeleted() {
 		return this.props.item.t === 'rm';
 	}
@@ -165,9 +194,50 @@ export default class Message extends React.Component {
 		);
 	}
 
+	renderReaction(reaction) {
+		const reacted = reaction.usernames.findIndex(item => item.value === this.props.user.username) !== -1;
+		const reactedContainerStyle = reacted ? { borderColor: '#bde1fe', backgroundColor: '#f3f9ff' } : {};
+		const reactedCount = reacted ? { color: '#4fb0fc' } : {};
+		return (
+			<TouchableOpacity
+				onPress={() => this.onReactionPress(reaction.emoji)}
+				onLongPress={() => this.onReactionLongPress()}
+				key={reaction.emoji}
+			>
+				<View style={[styles.reactionContainer, reactedContainerStyle]}>
+					<Emoji
+						content={reaction.emoji}
+						standardEmojiStyle={StyleSheet.flatten(styles.reactionEmoji)}
+						customEmojiStyle={StyleSheet.flatten(styles.reactionCustomEmoji)}
+						customEmojis={this.props.customEmojis}
+					/>
+					<Text style={[styles.reactionCount, reactedCount]}>{ reaction.usernames.length }</Text>
+				</View>
+			</TouchableOpacity>
+		);
+	}
+
+	renderReactions() {
+		if (this.props.item.reactions.length === 0) {
+			return null;
+		}
+		return (
+			<View style={styles.reactionsContainer}>
+				{this.props.item.reactions.map(reaction => this.renderReaction(reaction))}
+				<TouchableOpacity
+					onPress={() => this.props.toggleReactionPicker(this.parseMessage())}
+					key='add-reaction'
+					style={styles.reactionContainer}
+				>
+					<Icon name='insert-emoticon' color='#aaaaaa' size={15} />
+				</TouchableOpacity>
+			</View>
+		);
+	}
+
 	render() {
 		const {
-			item, message, editing, baseUrl
+			item, message, editing, baseUrl, customEmojis
 		} = this.props;
 
 		const marginLeft = this._visibility.interpolate({
@@ -181,7 +251,7 @@ export default class Message extends React.Component {
 		const username = item.alias || item.u.username;
 		const isEditing = message._id === item._id && editing;
 
-		const accessibilityLabel = `Message from ${ item.alias || item.u.username } at ${ moment(item.ts).format(this.props.Message_TimeFormat) }, ${ this.props.item.msg }`;
+		const accessibilityLabel = `Message from ${ username } at ${ moment(item.ts).format(this.props.Message_TimeFormat) }, ${ this.props.item.msg }`;
 
 		return (
 			<TouchableHighlight
@@ -213,8 +283,19 @@ export default class Message extends React.Component {
 							{this.renderMessageContent()}
 							{this.attachments()}
 							{this.renderUrl()}
+							{this.renderReactions()}
 						</View>
 					</View>
+					{this.state.reactionsModal ?
+						<ReactionsModal
+							isVisible={this.state.reactionsModal}
+							onClose={this.onClose}
+							reactions={item.reactions}
+							user={this.props.user}
+							customEmojis={customEmojis}
+						/>
+						: null
+					}
 				</Animated.View>
 			</TouchableHighlight>
 		);
diff --git a/app/containers/message/styles.js b/app/containers/message/styles.js
index 6236adf0681829e4f4ecaa1c46755079252f9416..7752dea76468e2b5314c2f913ca69bd0ac34065d 100644
--- a/app/containers/message/styles.js
+++ b/app/containers/message/styles.js
@@ -33,5 +33,35 @@ export default StyleSheet.create({
 		borderWidth: 1,
 		borderRadius: 5,
 		padding: 5
+	},
+	reactionsContainer: {
+		flexDirection: 'row',
+		flexWrap: 'wrap'
+	},
+	reactionContainer: {
+		flexDirection: 'row',
+		justifyContent: 'center',
+		alignItems: 'center',
+		padding: 3,
+		borderWidth: 1,
+		borderColor: '#cccccc',
+		borderRadius: 4,
+		marginRight: 5,
+		marginBottom: 5,
+		height: 23,
+		width: 35
+	},
+	reactionCount: {
+		fontSize: 12,
+		marginLeft: 2,
+		fontWeight: '600',
+		color: '#aaaaaa'
+	},
+	reactionEmoji: {
+		fontSize: 12
+	},
+	reactionCustomEmoji: {
+		width: 15,
+		height: 15
 	}
 });
diff --git a/app/emojis.js b/app/emojis.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7bff19571726105366fe0e9bbca7b3b78b44876
--- /dev/null
+++ b/app/emojis.js
@@ -0,0 +1,2833 @@
+export const emojisByCategory = {
+	people: [
+		'grinning',
+		'grimacing',
+		'grin',
+		'joy',
+		'smiley',
+		'smile',
+		'sweat_smile',
+		'laughing',
+		'innocent',
+		'wink',
+		'blush',
+		'slight_smile',
+		'upside_down',
+		'relaxed',
+		'yum',
+		'relieved',
+		'heart_eyes',
+		'kissing_heart',
+		'kissing',
+		'kissing_smiling_eyes',
+		'kissing_closed_eyes',
+		'stuck_out_tongue_winking_eye',
+		'stuck_out_tongue_closed_eyes',
+		'stuck_out_tongue',
+		'money_mouth',
+		'nerd',
+		'sunglasses',
+		'hugging',
+		'smirk',
+		'no_mouth',
+		'neutral_face',
+		'expressionless',
+		'unamused',
+		'rolling_eyes',
+		'thinking',
+		'flushed',
+		'disappointed',
+		'worried',
+		'angry',
+		'rage',
+		'pensive',
+		'confused',
+		'slight_frown',
+		'frowning2',
+		'persevere',
+		'confounded',
+		'tired_face',
+		'weary',
+		'triumph',
+		'open_mouth',
+		'scream',
+		'fearful',
+		'cold_sweat',
+		'hushed',
+		'frowning',
+		'anguished',
+		'cry',
+		'disappointed_relieved',
+		'sleepy',
+		'sweat',
+		'sob',
+		'dizzy_face',
+		'astonished',
+		'zipper_mouth',
+		'mask',
+		'thermometer_face',
+		'head_bandage',
+		'sleeping',
+		'zzz',
+		'poop',
+		'smiling_imp',
+		'imp',
+		'japanese_ogre',
+		'japanese_goblin',
+		'skull',
+		'ghost',
+		'alien',
+		'robot',
+		'smiley_cat',
+		'smile_cat',
+		'joy_cat',
+		'heart_eyes_cat',
+		'smirk_cat',
+		'kissing_cat',
+		'scream_cat',
+		'crying_cat_face',
+		'pouting_cat',
+		'raised_hands',
+		'clap',
+		'wave',
+		'thumbsup',
+		'thumbsdown',
+		'punch',
+		'fist',
+		'v',
+		'ok_hand',
+		'raised_hand',
+		'open_hands',
+		'muscle',
+		'pray',
+		'point_up',
+		'point_up_2',
+		'point_down',
+		'point_left',
+		'point_right',
+		'middle_finger',
+		'hand_splayed',
+		'metal',
+		'vulcan',
+		'writing_hand',
+		'nail_care',
+		'lips',
+		'tongue',
+		'ear',
+		'nose',
+		'eye',
+		'eyes',
+		'bust_in_silhouette',
+		'busts_in_silhouette',
+		'speaking_head',
+		'baby',
+		'boy',
+		'girl',
+		'man',
+		'woman',
+		'person_with_blond_hair',
+		'older_man',
+		'older_woman',
+		'man_with_gua_pi_mao',
+		'man_with_turban',
+		'cop',
+		'construction_worker',
+		'guardsman',
+		'spy',
+		'santa',
+		'angel',
+		'princess',
+		'bride_with_veil',
+		'walking',
+		'runner',
+		'dancer',
+		'dancers',
+		'couple',
+		'two_men_holding_hands',
+		'two_women_holding_hands',
+		'bow',
+		'information_desk_person',
+		'no_good',
+		'ok_woman',
+		'raising_hand',
+		'person_with_pouting_face',
+		'person_frowning',
+		'haircut',
+		'massage',
+		'couple_with_heart',
+		'couple_ww',
+		'couple_mm',
+		'couplekiss',
+		'kiss_ww',
+		'kiss_mm',
+		'family',
+		'family_mwg',
+		'family_mwgb',
+		'family_mwbb',
+		'family_mwgg',
+		'family_wwb',
+		'family_wwg',
+		'family_wwgb',
+		'family_wwbb',
+		'family_wwgg',
+		'family_mmb',
+		'family_mmg',
+		'family_mmgb',
+		'family_mmbb',
+		'family_mmgg',
+		'womans_clothes',
+		'shirt',
+		'jeans',
+		'necktie',
+		'dress',
+		'bikini',
+		'kimono',
+		'lipstick',
+		'kiss',
+		'footprints',
+		'high_heel',
+		'sandal',
+		'boot',
+		'mans_shoe',
+		'athletic_shoe',
+		'womans_hat',
+		'tophat',
+		'helmet_with_cross',
+		'mortar_board',
+		'crown',
+		'school_satchel',
+		'pouch',
+		'purse',
+		'handbag',
+		'briefcase',
+		'eyeglasses',
+		'dark_sunglasses',
+		'ring',
+		'closed_umbrella',
+		'cowboy',
+		'clown',
+		'nauseated_face',
+		'rofl',
+		'drooling_face',
+		'lying_face',
+		'sneezing_face',
+		'prince',
+		'man_in_tuxedo',
+		'mrs_claus',
+		'face_palm',
+		'shrug',
+		'selfie',
+		'man_dancing',
+		'call_me',
+		'raised_back_of_hand',
+		'left_facing_fist',
+		'right_facing_fist',
+		'handshake',
+		'fingers_crossed',
+		'pregnant_woman'
+	],
+	nature: [
+		'dog',
+		'cat',
+		'mouse',
+		'hamster',
+		'rabbit',
+		'bear',
+		'panda_face',
+		'koala',
+		'tiger',
+		'lion_face',
+		'cow',
+		'pig',
+		'pig_nose',
+		'frog',
+		'octopus',
+		'monkey_face',
+		'see_no_evil',
+		'hear_no_evil',
+		'speak_no_evil',
+		'monkey',
+		'chicken',
+		'penguin',
+		'bird',
+		'baby_chick',
+		'hatching_chick',
+		'hatched_chick',
+		'wolf',
+		'boar',
+		'horse',
+		'unicorn',
+		'bee',
+		'bug',
+		'snail',
+		'beetle',
+		'ant',
+		'spider',
+		'scorpion',
+		'crab',
+		'snake',
+		'turtle',
+		'tropical_fish',
+		'fish',
+		'blowfish',
+		'dolphin',
+		'whale',
+		'whale2',
+		'crocodile',
+		'leopard',
+		'tiger2',
+		'water_buffalo',
+		'ox',
+		'cow2',
+		'dromedary_camel',
+		'camel',
+		'elephant',
+		'goat',
+		'ram',
+		'sheep',
+		'racehorse',
+		'pig2',
+		'rat',
+		'mouse2',
+		'rooster',
+		'turkey',
+		'dove',
+		'dog2',
+		'poodle',
+		'cat2',
+		'rabbit2',
+		'chipmunk',
+		'feet',
+		'dragon',
+		'dragon_face',
+		'cactus',
+		'christmas_tree',
+		'evergreen_tree',
+		'deciduous_tree',
+		'palm_tree',
+		'seedling',
+		'herb',
+		'shamrock',
+		'four_leaf_clover',
+		'bamboo',
+		'tanabata_tree',
+		'leaves',
+		'fallen_leaf',
+		'maple_leaf',
+		'ear_of_rice',
+		'hibiscus',
+		'sunflower',
+		'rose',
+		'tulip',
+		'blossom',
+		'cherry_blossom',
+		'bouquet',
+		'mushroom',
+		'chestnut',
+		'jack_o_lantern',
+		'shell',
+		'spider_web',
+		'earth_americas',
+		'earth_africa',
+		'earth_asia',
+		'full_moon',
+		'waning_gibbous_moon',
+		'last_quarter_moon',
+		'waning_crescent_moon',
+		'new_moon',
+		'waxing_crescent_moon',
+		'first_quarter_moon',
+		'waxing_gibbous_moon',
+		'new_moon_with_face',
+		'full_moon_with_face',
+		'first_quarter_moon_with_face',
+		'last_quarter_moon_with_face',
+		'sun_with_face',
+		'crescent_moon',
+		'star',
+		'star2',
+		'dizzy',
+		'sparkles',
+		'comet',
+		'sunny',
+		'white_sun_small_cloud',
+		'partly_sunny',
+		'white_sun_cloud',
+		'white_sun_rain_cloud',
+		'cloud',
+		'cloud_rain',
+		'thunder_cloud_rain',
+		'cloud_lightning',
+		'zap',
+		'fire',
+		'boom',
+		'snowflake',
+		'cloud_snow',
+		'snowman2',
+		'snowman',
+		'wind_blowing_face',
+		'dash',
+		'cloud_tornado',
+		'fog',
+		'umbrella2',
+		'umbrella',
+		'droplet',
+		'sweat_drops',
+		'ocean',
+		'eagle',
+		'duck',
+		'bat',
+		'shark',
+		'owl',
+		'fox',
+		'butterfly',
+		'deer',
+		'gorilla',
+		'lizard',
+		'rhino',
+		'wilted_rose',
+		'shrimp',
+		'squid'
+	],
+	food: [
+		'green_apple',
+		'apple',
+		'pear',
+		'tangerine',
+		'lemon',
+		'banana',
+		'watermelon',
+		'grapes',
+		'strawberry',
+		'melon',
+		'cherries',
+		'peach',
+		'pineapple',
+		'tomato',
+		'eggplant',
+		'hot_pepper',
+		'corn',
+		'sweet_potato',
+		'honey_pot',
+		'bread',
+		'cheese',
+		'poultry_leg',
+		'meat_on_bone',
+		'fried_shrimp',
+		'cooking',
+		'hamburger',
+		'fries',
+		'hotdog',
+		'pizza',
+		'spaghetti',
+		'taco',
+		'burrito',
+		'ramen',
+		'stew',
+		'fish_cake',
+		'sushi',
+		'bento',
+		'curry',
+		'rice_ball',
+		'rice',
+		'rice_cracker',
+		'oden',
+		'dango',
+		'shaved_ice',
+		'ice_cream',
+		'icecream',
+		'cake',
+		'birthday',
+		'custard',
+		'candy',
+		'lollipop',
+		'chocolate_bar',
+		'popcorn',
+		'doughnut',
+		'cookie',
+		'beer',
+		'beers',
+		'wine_glass',
+		'cocktail',
+		'tropical_drink',
+		'champagne',
+		'sake',
+		'tea',
+		'coffee',
+		'baby_bottle',
+		'fork_and_knife',
+		'fork_knife_plate',
+		'croissant',
+		'avocado',
+		'cucumber',
+		'bacon',
+		'potato',
+		'carrot',
+		'french_bread',
+		'salad',
+		'shallow_pan_of_food',
+		'stuffed_flatbread',
+		'champagne_glass',
+		'tumbler_glass',
+		'spoon',
+		'egg',
+		'milk',
+		'peanuts',
+		'kiwi',
+		'pancakes'
+	],
+	activity: [
+		'soccer',
+		'basketball',
+		'football',
+		'baseball',
+		'tennis',
+		'volleyball',
+		'rugby_football',
+		'8ball',
+		'golf',
+		'golfer',
+		'ping_pong',
+		'badminton',
+		'hockey',
+		'field_hockey',
+		'cricket',
+		'ski',
+		'skier',
+		'snowboarder',
+		'ice_skate',
+		'bow_and_arrow',
+		'fishing_pole_and_fish',
+		'rowboat',
+		'swimmer',
+		'surfer',
+		'bath',
+		'basketball_player',
+		'lifter',
+		'bicyclist',
+		'mountain_bicyclist',
+		'horse_racing',
+		'levitate',
+		'trophy',
+		'running_shirt_with_sash',
+		'medal',
+		'military_medal',
+		'reminder_ribbon',
+		'rosette',
+		'ticket',
+		'tickets',
+		'performing_arts',
+		'art',
+		'circus_tent',
+		'microphone',
+		'headphones',
+		'musical_score',
+		'musical_keyboard',
+		'saxophone',
+		'trumpet',
+		'guitar',
+		'violin',
+		'clapper',
+		'video_game',
+		'space_invader',
+		'dart',
+		'game_die',
+		'slot_machine',
+		'bowling',
+		'cartwheel',
+		'juggling',
+		'wrestlers',
+		'boxing_glove',
+		'martial_arts_uniform',
+		'water_polo',
+		'handball',
+		'goal',
+		'fencer',
+		'first_place',
+		'second_place',
+		'third_place',
+		'drum'
+	],
+	travel: [
+		'red_car',
+		'taxi',
+		'blue_car',
+		'bus',
+		'trolleybus',
+		'race_car',
+		'police_car',
+		'ambulance',
+		'fire_engine',
+		'minibus',
+		'truck',
+		'articulated_lorry',
+		'tractor',
+		'motorcycle',
+		'bike',
+		'rotating_light',
+		'oncoming_police_car',
+		'oncoming_bus',
+		'oncoming_automobile',
+		'oncoming_taxi',
+		'aerial_tramway',
+		'mountain_cableway',
+		'suspension_railway',
+		'railway_car',
+		'train',
+		'monorail',
+		'bullettrain_side',
+		'bullettrain_front',
+		'light_rail',
+		'mountain_railway',
+		'steam_locomotive',
+		'train2',
+		'metro',
+		'tram',
+		'station',
+		'helicopter',
+		'airplane_small',
+		'airplane',
+		'airplane_departure',
+		'airplane_arriving',
+		'sailboat',
+		'motorboat',
+		'speedboat',
+		'ferry',
+		'cruise_ship',
+		'rocket',
+		'satellite_orbital',
+		'seat',
+		'anchor',
+		'construction',
+		'fuelpump',
+		'busstop',
+		'vertical_traffic_light',
+		'traffic_light',
+		'checkered_flag',
+		'ship',
+		'ferris_wheel',
+		'roller_coaster',
+		'carousel_horse',
+		'construction_site',
+		'foggy',
+		'tokyo_tower',
+		'factory',
+		'fountain',
+		'rice_scene',
+		'mountain',
+		'mountain_snow',
+		'mount_fuji',
+		'volcano',
+		'japan',
+		'camping',
+		'tent',
+		'park',
+		'motorway',
+		'railway_track',
+		'sunrise',
+		'sunrise_over_mountains',
+		'desert',
+		'beach',
+		'island',
+		'city_sunset',
+		'city_dusk',
+		'cityscape',
+		'night_with_stars',
+		'bridge_at_night',
+		'milky_way',
+		'stars',
+		'sparkler',
+		'fireworks',
+		'rainbow',
+		'homes',
+		'european_castle',
+		'japanese_castle',
+		'stadium',
+		'statue_of_liberty',
+		'house',
+		'house_with_garden',
+		'house_abandoned',
+		'office',
+		'department_store',
+		'post_office',
+		'european_post_office',
+		'hospital',
+		'bank',
+		'hotel',
+		'convenience_store',
+		'school',
+		'love_hotel',
+		'wedding',
+		'classical_building',
+		'church',
+		'mosque',
+		'synagogue',
+		'kaaba',
+		'shinto_shrine',
+		'shopping_cart',
+		'scooter',
+		'motor_scooter',
+		'canoe'
+	],
+	objects: [
+		'watch',
+		'iphone',
+		'calling',
+		'computer',
+		'keyboard',
+		'desktop',
+		'printer',
+		'mouse_three_button',
+		'trackball',
+		'joystick',
+		'compression',
+		'minidisc',
+		'floppy_disk',
+		'cd',
+		'dvd',
+		'vhs',
+		'camera',
+		'camera_with_flash',
+		'video_camera',
+		'movie_camera',
+		'projector',
+		'film_frames',
+		'telephone_receiver',
+		'telephone',
+		'pager',
+		'fax',
+		'tv',
+		'radio',
+		'microphone2',
+		'level_slider',
+		'control_knobs',
+		'stopwatch',
+		'timer',
+		'alarm_clock',
+		'clock',
+		'hourglass_flowing_sand',
+		'hourglass',
+		'satellite',
+		'battery',
+		'electric_plug',
+		'bulb',
+		'flashlight',
+		'candle',
+		'wastebasket',
+		'oil',
+		'money_with_wings',
+		'dollar',
+		'yen',
+		'euro',
+		'pound',
+		'moneybag',
+		'credit_card',
+		'gem',
+		'scales',
+		'wrench',
+		'hammer',
+		'hammer_pick',
+		'tools',
+		'pick',
+		'nut_and_bolt',
+		'gear',
+		'chains',
+		'gun',
+		'bomb',
+		'knife',
+		'dagger',
+		'crossed_swords',
+		'shield',
+		'smoking',
+		'skull_crossbones',
+		'coffin',
+		'urn',
+		'amphora',
+		'crystal_ball',
+		'prayer_beads',
+		'barber',
+		'alembic',
+		'telescope',
+		'microscope',
+		'hole',
+		'pill',
+		'syringe',
+		'thermometer',
+		'label',
+		'bookmark',
+		'toilet',
+		'shower',
+		'bathtub',
+		'key',
+		'key2',
+		'couch',
+		'sleeping_accommodation',
+		'bed',
+		'door',
+		'bellhop',
+		'frame_photo',
+		'map',
+		'beach_umbrella',
+		'moyai',
+		'shopping_bags',
+		'balloon',
+		'flags',
+		'ribbon',
+		'gift',
+		'confetti_ball',
+		'tada',
+		'dolls',
+		'wind_chime',
+		'crossed_flags',
+		'izakaya_lantern',
+		'envelope',
+		'envelope_with_arrow',
+		'incoming_envelope',
+		'e-mail',
+		'love_letter',
+		'postbox',
+		'mailbox_closed',
+		'mailbox',
+		'mailbox_with_mail',
+		'mailbox_with_no_mail',
+		'package',
+		'postal_horn',
+		'inbox_tray',
+		'outbox_tray',
+		'scroll',
+		'page_with_curl',
+		'bookmark_tabs',
+		'bar_chart',
+		'chart_with_upwards_trend',
+		'chart_with_downwards_trend',
+		'page_facing_up',
+		'date',
+		'calendar',
+		'calendar_spiral',
+		'card_index',
+		'card_box',
+		'ballot_box',
+		'file_cabinet',
+		'clipboard',
+		'notepad_spiral',
+		'file_folder',
+		'open_file_folder',
+		'dividers',
+		'newspaper2',
+		'newspaper',
+		'notebook',
+		'closed_book',
+		'green_book',
+		'blue_book',
+		'orange_book',
+		'notebook_with_decorative_cover',
+		'ledger',
+		'books',
+		'book',
+		'link',
+		'paperclip',
+		'paperclips',
+		'scissors',
+		'triangular_ruler',
+		'straight_ruler',
+		'pushpin',
+		'round_pushpin',
+		'triangular_flag_on_post',
+		'flag_white',
+		'flag_black',
+		'closed_lock_with_key',
+		'lock',
+		'unlock',
+		'lock_with_ink_pen',
+		'pen_ballpoint',
+		'pen_fountain',
+		'black_nib',
+		'pencil',
+		'pencil2',
+		'crayon',
+		'paintbrush',
+		'mag',
+		'mag_right'
+	],
+	symbols: [
+		'100',
+		'1234',
+		'heart',
+		'yellow_heart',
+		'green_heart',
+		'blue_heart',
+		'purple_heart',
+		'broken_heart',
+		'heart_exclamation',
+		'two_hearts',
+		'revolving_hearts',
+		'heartbeat',
+		'heartpulse',
+		'sparkling_heart',
+		'cupid',
+		'gift_heart',
+		'heart_decoration',
+		'peace',
+		'cross',
+		'star_and_crescent',
+		'om_symbol',
+		'wheel_of_dharma',
+		'star_of_david',
+		'six_pointed_star',
+		'menorah',
+		'yin_yang',
+		'orthodox_cross',
+		'place_of_worship',
+		'ophiuchus',
+		'aries',
+		'taurus',
+		'gemini',
+		'cancer',
+		'leo',
+		'virgo',
+		'libra',
+		'scorpius',
+		'sagittarius',
+		'capricorn',
+		'aquarius',
+		'pisces',
+		'id',
+		'atom',
+		'u7a7a',
+		'u5272',
+		'radioactive',
+		'biohazard',
+		'mobile_phone_off',
+		'vibration_mode',
+		'u6709',
+		'u7121',
+		'u7533',
+		'u55b6',
+		'u6708',
+		'eight_pointed_black_star',
+		'vs',
+		'accept',
+		'white_flower',
+		'ideograph_advantage',
+		'secret',
+		'congratulations',
+		'u5408',
+		'u6e80',
+		'u7981',
+		'a',
+		'b',
+		'ab',
+		'cl',
+		'o2',
+		'sos',
+		'no_entry',
+		'name_badge',
+		'no_entry_sign',
+		'x',
+		'o',
+		'anger',
+		'hotsprings',
+		'no_pedestrians',
+		'do_not_litter',
+		'no_bicycles',
+		'non-potable_water',
+		'underage',
+		'no_mobile_phones',
+		'exclamation',
+		'grey_exclamation',
+		'question',
+		'grey_question',
+		'bangbang',
+		'interrobang',
+		'low_brightness',
+		'high_brightness',
+		'trident',
+		'fleur-de-lis',
+		'part_alternation_mark',
+		'warning',
+		'children_crossing',
+		'beginner',
+		'recycle',
+		'u6307',
+		'chart',
+		'sparkle',
+		'eight_spoked_asterisk',
+		'negative_squared_cross_mark',
+		'white_check_mark',
+		'diamond_shape_with_a_dot_inside',
+		'cyclone',
+		'loop',
+		'globe_with_meridians',
+		'm',
+		'atm',
+		'sa',
+		'passport_control',
+		'customs',
+		'baggage_claim',
+		'left_luggage',
+		'wheelchair',
+		'no_smoking',
+		'wc',
+		'parking',
+		'potable_water',
+		'mens',
+		'womens',
+		'baby_symbol',
+		'restroom',
+		'put_litter_in_its_place',
+		'cinema',
+		'signal_strength',
+		'koko',
+		'ng',
+		'ok',
+		'up',
+		'cool',
+		'new',
+		'free',
+		'zero',
+		'one',
+		'two',
+		'three',
+		'four',
+		'five',
+		'six',
+		'seven',
+		'eight',
+		'nine',
+		'keycap_ten',
+		'arrow_forward',
+		'pause_button',
+		'play_pause',
+		'stop_button',
+		'record_button',
+		'track_next',
+		'track_previous',
+		'fast_forward',
+		'rewind',
+		'twisted_rightwards_arrows',
+		'repeat',
+		'repeat_one',
+		'arrow_backward',
+		'arrow_up_small',
+		'arrow_down_small',
+		'arrow_double_up',
+		'arrow_double_down',
+		'arrow_right',
+		'arrow_left',
+		'arrow_up',
+		'arrow_down',
+		'arrow_upper_right',
+		'arrow_lower_right',
+		'arrow_lower_left',
+		'arrow_upper_left',
+		'arrow_up_down',
+		'left_right_arrow',
+		'arrows_counterclockwise',
+		'arrow_right_hook',
+		'leftwards_arrow_with_hook',
+		'arrow_heading_up',
+		'arrow_heading_down',
+		'hash',
+		'asterisk',
+		'information_source',
+		'abc',
+		'abcd',
+		'capital_abcd',
+		'symbols',
+		'musical_note',
+		'notes',
+		'wavy_dash',
+		'curly_loop',
+		'heavy_check_mark',
+		'arrows_clockwise',
+		'heavy_plus_sign',
+		'heavy_minus_sign',
+		'heavy_division_sign',
+		'heavy_multiplication_x',
+		'heavy_dollar_sign',
+		'currency_exchange',
+		'copyright',
+		'registered',
+		'tm',
+		'end',
+		'back',
+		'on',
+		'top',
+		'soon',
+		'ballot_box_with_check',
+		'radio_button',
+		'white_circle',
+		'black_circle',
+		'red_circle',
+		'large_blue_circle',
+		'small_orange_diamond',
+		'small_blue_diamond',
+		'large_orange_diamond',
+		'large_blue_diamond',
+		'small_red_triangle',
+		'black_small_square',
+		'white_small_square',
+		'black_large_square',
+		'white_large_square',
+		'small_red_triangle_down',
+		'black_medium_square',
+		'white_medium_square',
+		'black_medium_small_square',
+		'white_medium_small_square',
+		'black_square_button',
+		'white_square_button',
+		'speaker',
+		'sound',
+		'loud_sound',
+		'mute',
+		'mega',
+		'loudspeaker',
+		'bell',
+		'no_bell',
+		'black_joker',
+		'mahjong',
+		'spades',
+		'clubs',
+		'hearts',
+		'diamonds',
+		'flower_playing_cards',
+		'thought_balloon',
+		'anger_right',
+		'speech_balloon',
+		'clock1',
+		'clock2',
+		'clock3',
+		'clock4',
+		'clock5',
+		'clock6',
+		'clock7',
+		'clock8',
+		'clock9',
+		'clock10',
+		'clock11',
+		'clock12',
+		'clock130',
+		'clock230',
+		'clock330',
+		'clock430',
+		'clock530',
+		'clock630',
+		'clock730',
+		'clock830',
+		'clock930',
+		'clock1030',
+		'clock1130',
+		'clock1230',
+		'eye_in_speech_bubble',
+		'speech_left',
+		'eject',
+		'black_heart',
+		'octagonal_sign',
+		'asterisk_symbol',
+		'pound_symbol',
+		'digit_nine',
+		'digit_eight',
+		'digit_seven',
+		'digit_six',
+		'digit_five',
+		'digit_four',
+		'digit_three',
+		'digit_two',
+		'digit_one',
+		'digit_zero',
+		'regional_indicator_z',
+		'regional_indicator_y',
+		'regional_indicator_x',
+		'regional_indicator_w',
+		'regional_indicator_v',
+		'regional_indicator_u',
+		'regional_indicator_t',
+		'regional_indicator_s',
+		'regional_indicator_r',
+		'regional_indicator_q',
+		'regional_indicator_p',
+		'regional_indicator_o',
+		'regional_indicator_n',
+		'regional_indicator_m',
+		'regional_indicator_l',
+		'regional_indicator_k',
+		'regional_indicator_j',
+		'regional_indicator_i',
+		'regional_indicator_h',
+		'regional_indicator_g',
+		'regional_indicator_f',
+		'regional_indicator_e',
+		'regional_indicator_d',
+		'regional_indicator_c',
+		'regional_indicator_b',
+		'regional_indicator_a'
+	],
+	flags: [
+		'flag_ac',
+		'flag_af',
+		'flag_al',
+		'flag_dz',
+		'flag_ad',
+		'flag_ao',
+		'flag_ai',
+		'flag_ag',
+		'flag_ar',
+		'flag_am',
+		'flag_aw',
+		'flag_au',
+		'flag_at',
+		'flag_az',
+		'flag_bs',
+		'flag_bh',
+		'flag_bd',
+		'flag_bb',
+		'flag_by',
+		'flag_be',
+		'flag_bz',
+		'flag_bj',
+		'flag_bm',
+		'flag_bt',
+		'flag_bo',
+		'flag_ba',
+		'flag_bw',
+		'flag_br',
+		'flag_bn',
+		'flag_bg',
+		'flag_bf',
+		'flag_bi',
+		'flag_cv',
+		'flag_kh',
+		'flag_cm',
+		'flag_ca',
+		'flag_ky',
+		'flag_cf',
+		'flag_td',
+		'flag_cl',
+		'flag_cn',
+		'flag_co',
+		'flag_km',
+		'flag_cg',
+		'flag_cd',
+		'flag_cr',
+		'flag_hr',
+		'flag_cu',
+		'flag_cy',
+		'flag_cz',
+		'flag_dk',
+		'flag_dj',
+		'flag_dm',
+		'flag_do',
+		'flag_ec',
+		'flag_eg',
+		'flag_sv',
+		'flag_gq',
+		'flag_er',
+		'flag_ee',
+		'flag_et',
+		'flag_fk',
+		'flag_fo',
+		'flag_fj',
+		'flag_fi',
+		'flag_fr',
+		'flag_pf',
+		'flag_ga',
+		'flag_gm',
+		'flag_ge',
+		'flag_de',
+		'flag_gh',
+		'flag_gi',
+		'flag_gr',
+		'flag_gl',
+		'flag_gd',
+		'flag_gu',
+		'flag_gt',
+		'flag_gn',
+		'flag_gw',
+		'flag_gy',
+		'flag_ht',
+		'flag_hn',
+		'flag_hk',
+		'flag_hu',
+		'flag_is',
+		'flag_in',
+		'flag_id',
+		'flag_ir',
+		'flag_iq',
+		'flag_ie',
+		'flag_il',
+		'flag_it',
+		'flag_ci',
+		'flag_jm',
+		'flag_jp',
+		'flag_je',
+		'flag_jo',
+		'flag_kz',
+		'flag_ke',
+		'flag_ki',
+		'flag_xk',
+		'flag_kw',
+		'flag_kg',
+		'flag_la',
+		'flag_lv',
+		'flag_lb',
+		'flag_ls',
+		'flag_lr',
+		'flag_ly',
+		'flag_li',
+		'flag_lt',
+		'flag_lu',
+		'flag_mo',
+		'flag_mk',
+		'flag_mg',
+		'flag_mw',
+		'flag_my',
+		'flag_mv',
+		'flag_ml',
+		'flag_mt',
+		'flag_mh',
+		'flag_mr',
+		'flag_mu',
+		'flag_mx',
+		'flag_fm',
+		'flag_md',
+		'flag_mc',
+		'flag_mn',
+		'flag_me',
+		'flag_ms',
+		'flag_ma',
+		'flag_mz',
+		'flag_mm',
+		'flag_na',
+		'flag_nr',
+		'flag_np',
+		'flag_nl',
+		'flag_nc',
+		'flag_nz',
+		'flag_ni',
+		'flag_ne',
+		'flag_ng',
+		'flag_nu',
+		'flag_kp',
+		'flag_no',
+		'flag_om',
+		'flag_pk',
+		'flag_pw',
+		'flag_ps',
+		'flag_pa',
+		'flag_pg',
+		'flag_py',
+		'flag_pe',
+		'flag_ph',
+		'flag_pl',
+		'flag_pt',
+		'flag_pr',
+		'flag_qa',
+		'flag_ro',
+		'flag_ru',
+		'flag_rw',
+		'flag_sh',
+		'flag_kn',
+		'flag_lc',
+		'flag_vc',
+		'flag_ws',
+		'flag_sm',
+		'flag_st',
+		'flag_sa',
+		'flag_sn',
+		'flag_rs',
+		'flag_sc',
+		'flag_sl',
+		'flag_sg',
+		'flag_sk',
+		'flag_si',
+		'flag_sb',
+		'flag_so',
+		'flag_za',
+		'flag_kr',
+		'flag_es',
+		'flag_lk',
+		'flag_sd',
+		'flag_sr',
+		'flag_sz',
+		'flag_se',
+		'flag_ch',
+		'flag_sy',
+		'flag_tw',
+		'flag_tj',
+		'flag_tz',
+		'flag_th',
+		'flag_tl',
+		'flag_tg',
+		'flag_to',
+		'flag_tt',
+		'flag_tn',
+		'flag_tr',
+		'flag_tm',
+		'flag_tv',
+		'flag_ug',
+		'flag_ua',
+		'flag_ae',
+		'flag_gb',
+		'flag_us',
+		'flag_vi',
+		'flag_uy',
+		'flag_uz',
+		'flag_vu',
+		'flag_va',
+		'flag_ve',
+		'flag_vn',
+		'flag_wf',
+		'flag_eh',
+		'flag_ye',
+		'flag_zm',
+		'flag_zw',
+		'flag_re',
+		'flag_ax',
+		'flag_ta',
+		'flag_io',
+		'flag_bq',
+		'flag_cx',
+		'flag_cc',
+		'flag_gg',
+		'flag_im',
+		'flag_yt',
+		'flag_nf',
+		'flag_pn',
+		'flag_bl',
+		'flag_pm',
+		'flag_gs',
+		'flag_tk',
+		'flag_bv',
+		'flag_hm',
+		'flag_sj',
+		'flag_um',
+		'flag_ic',
+		'flag_ea',
+		'flag_cp',
+		'flag_dg',
+		'flag_as',
+		'flag_aq',
+		'flag_vg',
+		'flag_ck',
+		'flag_cw',
+		'flag_eu',
+		'flag_gf',
+		'flag_tf',
+		'flag_gp',
+		'flag_mq',
+		'flag_mp',
+		'flag_sx',
+		'flag_ss',
+		'flag_tc',
+		'flag_mf'
+	]
+};
+
+export const emojis = [
+	'grinning',
+	'grimacing',
+	'grin',
+	'joy',
+	'smiley',
+	'smile',
+	'sweat_smile',
+	'laughing',
+	'innocent',
+	'wink',
+	'blush',
+	'slight_smile',
+	'upside_down',
+	'relaxed',
+	'yum',
+	'relieved',
+	'heart_eyes',
+	'kissing_heart',
+	'kissing',
+	'kissing_smiling_eyes',
+	'kissing_closed_eyes',
+	'stuck_out_tongue_winking_eye',
+	'stuck_out_tongue_closed_eyes',
+	'stuck_out_tongue',
+	'money_mouth',
+	'nerd',
+	'sunglasses',
+	'hugging',
+	'smirk',
+	'no_mouth',
+	'neutral_face',
+	'expressionless',
+	'unamused',
+	'rolling_eyes',
+	'thinking',
+	'flushed',
+	'disappointed',
+	'worried',
+	'angry',
+	'rage',
+	'pensive',
+	'confused',
+	'slight_frown',
+	'frowning2',
+	'persevere',
+	'confounded',
+	'tired_face',
+	'weary',
+	'triumph',
+	'open_mouth',
+	'scream',
+	'fearful',
+	'cold_sweat',
+	'hushed',
+	'frowning',
+	'anguished',
+	'cry',
+	'disappointed_relieved',
+	'sleepy',
+	'sweat',
+	'sob',
+	'dizzy_face',
+	'astonished',
+	'zipper_mouth',
+	'mask',
+	'thermometer_face',
+	'head_bandage',
+	'sleeping',
+	'zzz',
+	'poop',
+	'smiling_imp',
+	'imp',
+	'japanese_ogre',
+	'japanese_goblin',
+	'skull',
+	'ghost',
+	'alien',
+	'robot',
+	'smiley_cat',
+	'smile_cat',
+	'joy_cat',
+	'heart_eyes_cat',
+	'smirk_cat',
+	'kissing_cat',
+	'scream_cat',
+	'crying_cat_face',
+	'pouting_cat',
+	'raised_hands',
+	'clap',
+	'wave',
+	'thumbsup',
+	'thumbsdown',
+	'punch',
+	'fist',
+	'v',
+	'ok_hand',
+	'raised_hand',
+	'open_hands',
+	'muscle',
+	'pray',
+	'point_up',
+	'point_up_2',
+	'point_down',
+	'point_left',
+	'point_right',
+	'middle_finger',
+	'hand_splayed',
+	'metal',
+	'vulcan',
+	'writing_hand',
+	'nail_care',
+	'lips',
+	'tongue',
+	'ear',
+	'nose',
+	'eye',
+	'eyes',
+	'bust_in_silhouette',
+	'busts_in_silhouette',
+	'speaking_head',
+	'baby',
+	'boy',
+	'girl',
+	'man',
+	'woman',
+	'person_with_blond_hair',
+	'older_man',
+	'older_woman',
+	'man_with_gua_pi_mao',
+	'man_with_turban',
+	'cop',
+	'construction_worker',
+	'guardsman',
+	'spy',
+	'santa',
+	'angel',
+	'princess',
+	'bride_with_veil',
+	'walking',
+	'runner',
+	'dancer',
+	'dancers',
+	'couple',
+	'two_men_holding_hands',
+	'two_women_holding_hands',
+	'bow',
+	'information_desk_person',
+	'no_good',
+	'ok_woman',
+	'raising_hand',
+	'person_with_pouting_face',
+	'person_frowning',
+	'haircut',
+	'massage',
+	'couple_with_heart',
+	'couple_ww',
+	'couple_mm',
+	'couplekiss',
+	'kiss_ww',
+	'kiss_mm',
+	'family',
+	'family_mwg',
+	'family_mwgb',
+	'family_mwbb',
+	'family_mwgg',
+	'family_wwb',
+	'family_wwg',
+	'family_wwgb',
+	'family_wwbb',
+	'family_wwgg',
+	'family_mmb',
+	'family_mmg',
+	'family_mmgb',
+	'family_mmbb',
+	'family_mmgg',
+	'womans_clothes',
+	'shirt',
+	'jeans',
+	'necktie',
+	'dress',
+	'bikini',
+	'kimono',
+	'lipstick',
+	'kiss',
+	'footprints',
+	'high_heel',
+	'sandal',
+	'boot',
+	'mans_shoe',
+	'athletic_shoe',
+	'womans_hat',
+	'tophat',
+	'helmet_with_cross',
+	'mortar_board',
+	'crown',
+	'school_satchel',
+	'pouch',
+	'purse',
+	'handbag',
+	'briefcase',
+	'eyeglasses',
+	'dark_sunglasses',
+	'ring',
+	'closed_umbrella',
+	'cowboy',
+	'clown',
+	'nauseated_face',
+	'rofl',
+	'drooling_face',
+	'lying_face',
+	'sneezing_face',
+	'prince',
+	'man_in_tuxedo',
+	'mrs_claus',
+	'face_palm',
+	'shrug',
+	'selfie',
+	'man_dancing',
+	'call_me',
+	'raised_back_of_hand',
+	'left_facing_fist',
+	'right_facing_fist',
+	'handshake',
+	'fingers_crossed',
+	'pregnant_woman',
+	'dog',
+	'cat',
+	'mouse',
+	'hamster',
+	'rabbit',
+	'bear',
+	'panda_face',
+	'koala',
+	'tiger',
+	'lion_face',
+	'cow',
+	'pig',
+	'pig_nose',
+	'frog',
+	'octopus',
+	'monkey_face',
+	'see_no_evil',
+	'hear_no_evil',
+	'speak_no_evil',
+	'monkey',
+	'chicken',
+	'penguin',
+	'bird',
+	'baby_chick',
+	'hatching_chick',
+	'hatched_chick',
+	'wolf',
+	'boar',
+	'horse',
+	'unicorn',
+	'bee',
+	'bug',
+	'snail',
+	'beetle',
+	'ant',
+	'spider',
+	'scorpion',
+	'crab',
+	'snake',
+	'turtle',
+	'tropical_fish',
+	'fish',
+	'blowfish',
+	'dolphin',
+	'whale',
+	'whale2',
+	'crocodile',
+	'leopard',
+	'tiger2',
+	'water_buffalo',
+	'ox',
+	'cow2',
+	'dromedary_camel',
+	'camel',
+	'elephant',
+	'goat',
+	'ram',
+	'sheep',
+	'racehorse',
+	'pig2',
+	'rat',
+	'mouse2',
+	'rooster',
+	'turkey',
+	'dove',
+	'dog2',
+	'poodle',
+	'cat2',
+	'rabbit2',
+	'chipmunk',
+	'feet',
+	'dragon',
+	'dragon_face',
+	'cactus',
+	'christmas_tree',
+	'evergreen_tree',
+	'deciduous_tree',
+	'palm_tree',
+	'seedling',
+	'herb',
+	'shamrock',
+	'four_leaf_clover',
+	'bamboo',
+	'tanabata_tree',
+	'leaves',
+	'fallen_leaf',
+	'maple_leaf',
+	'ear_of_rice',
+	'hibiscus',
+	'sunflower',
+	'rose',
+	'tulip',
+	'blossom',
+	'cherry_blossom',
+	'bouquet',
+	'mushroom',
+	'chestnut',
+	'jack_o_lantern',
+	'shell',
+	'spider_web',
+	'earth_americas',
+	'earth_africa',
+	'earth_asia',
+	'full_moon',
+	'waning_gibbous_moon',
+	'last_quarter_moon',
+	'waning_crescent_moon',
+	'new_moon',
+	'waxing_crescent_moon',
+	'first_quarter_moon',
+	'waxing_gibbous_moon',
+	'new_moon_with_face',
+	'full_moon_with_face',
+	'first_quarter_moon_with_face',
+	'last_quarter_moon_with_face',
+	'sun_with_face',
+	'crescent_moon',
+	'star',
+	'star2',
+	'dizzy',
+	'sparkles',
+	'comet',
+	'sunny',
+	'white_sun_small_cloud',
+	'partly_sunny',
+	'white_sun_cloud',
+	'white_sun_rain_cloud',
+	'cloud',
+	'cloud_rain',
+	'thunder_cloud_rain',
+	'cloud_lightning',
+	'zap',
+	'fire',
+	'boom',
+	'snowflake',
+	'cloud_snow',
+	'snowman2',
+	'snowman',
+	'wind_blowing_face',
+	'dash',
+	'cloud_tornado',
+	'fog',
+	'umbrella2',
+	'umbrella',
+	'droplet',
+	'sweat_drops',
+	'ocean',
+	'eagle',
+	'duck',
+	'bat',
+	'shark',
+	'owl',
+	'fox',
+	'butterfly',
+	'deer',
+	'gorilla',
+	'lizard',
+	'rhino',
+	'wilted_rose',
+	'shrimp',
+	'squid',
+	'green_apple',
+	'apple',
+	'pear',
+	'tangerine',
+	'lemon',
+	'banana',
+	'watermelon',
+	'grapes',
+	'strawberry',
+	'melon',
+	'cherries',
+	'peach',
+	'pineapple',
+	'tomato',
+	'eggplant',
+	'hot_pepper',
+	'corn',
+	'sweet_potato',
+	'honey_pot',
+	'bread',
+	'cheese',
+	'poultry_leg',
+	'meat_on_bone',
+	'fried_shrimp',
+	'cooking',
+	'hamburger',
+	'fries',
+	'hotdog',
+	'pizza',
+	'spaghetti',
+	'taco',
+	'burrito',
+	'ramen',
+	'stew',
+	'fish_cake',
+	'sushi',
+	'bento',
+	'curry',
+	'rice_ball',
+	'rice',
+	'rice_cracker',
+	'oden',
+	'dango',
+	'shaved_ice',
+	'ice_cream',
+	'icecream',
+	'cake',
+	'birthday',
+	'custard',
+	'candy',
+	'lollipop',
+	'chocolate_bar',
+	'popcorn',
+	'doughnut',
+	'cookie',
+	'beer',
+	'beers',
+	'wine_glass',
+	'cocktail',
+	'tropical_drink',
+	'champagne',
+	'sake',
+	'tea',
+	'coffee',
+	'baby_bottle',
+	'fork_and_knife',
+	'fork_knife_plate',
+	'croissant',
+	'avocado',
+	'cucumber',
+	'bacon',
+	'potato',
+	'carrot',
+	'french_bread',
+	'salad',
+	'shallow_pan_of_food',
+	'stuffed_flatbread',
+	'champagne_glass',
+	'tumbler_glass',
+	'spoon',
+	'egg',
+	'milk',
+	'peanuts',
+	'kiwi',
+	'pancakes',
+	'soccer',
+	'basketball',
+	'football',
+	'baseball',
+	'tennis',
+	'volleyball',
+	'rugby_football',
+	'8ball',
+	'golf',
+	'golfer',
+	'ping_pong',
+	'badminton',
+	'hockey',
+	'field_hockey',
+	'cricket',
+	'ski',
+	'skier',
+	'snowboarder',
+	'ice_skate',
+	'bow_and_arrow',
+	'fishing_pole_and_fish',
+	'rowboat',
+	'swimmer',
+	'surfer',
+	'bath',
+	'basketball_player',
+	'lifter',
+	'bicyclist',
+	'mountain_bicyclist',
+	'horse_racing',
+	'levitate',
+	'trophy',
+	'running_shirt_with_sash',
+	'medal',
+	'military_medal',
+	'reminder_ribbon',
+	'rosette',
+	'ticket',
+	'tickets',
+	'performing_arts',
+	'art',
+	'circus_tent',
+	'microphone',
+	'headphones',
+	'musical_score',
+	'musical_keyboard',
+	'saxophone',
+	'trumpet',
+	'guitar',
+	'violin',
+	'clapper',
+	'video_game',
+	'space_invader',
+	'dart',
+	'game_die',
+	'slot_machine',
+	'bowling',
+	'cartwheel',
+	'juggling',
+	'wrestlers',
+	'boxing_glove',
+	'martial_arts_uniform',
+	'water_polo',
+	'handball',
+	'goal',
+	'fencer',
+	'first_place',
+	'second_place',
+	'third_place',
+	'drum',
+	'red_car',
+	'taxi',
+	'blue_car',
+	'bus',
+	'trolleybus',
+	'race_car',
+	'police_car',
+	'ambulance',
+	'fire_engine',
+	'minibus',
+	'truck',
+	'articulated_lorry',
+	'tractor',
+	'motorcycle',
+	'bike',
+	'rotating_light',
+	'oncoming_police_car',
+	'oncoming_bus',
+	'oncoming_automobile',
+	'oncoming_taxi',
+	'aerial_tramway',
+	'mountain_cableway',
+	'suspension_railway',
+	'railway_car',
+	'train',
+	'monorail',
+	'bullettrain_side',
+	'bullettrain_front',
+	'light_rail',
+	'mountain_railway',
+	'steam_locomotive',
+	'train2',
+	'metro',
+	'tram',
+	'station',
+	'helicopter',
+	'airplane_small',
+	'airplane',
+	'airplane_departure',
+	'airplane_arriving',
+	'sailboat',
+	'motorboat',
+	'speedboat',
+	'ferry',
+	'cruise_ship',
+	'rocket',
+	'satellite_orbital',
+	'seat',
+	'anchor',
+	'construction',
+	'fuelpump',
+	'busstop',
+	'vertical_traffic_light',
+	'traffic_light',
+	'checkered_flag',
+	'ship',
+	'ferris_wheel',
+	'roller_coaster',
+	'carousel_horse',
+	'construction_site',
+	'foggy',
+	'tokyo_tower',
+	'factory',
+	'fountain',
+	'rice_scene',
+	'mountain',
+	'mountain_snow',
+	'mount_fuji',
+	'volcano',
+	'japan',
+	'camping',
+	'tent',
+	'park',
+	'motorway',
+	'railway_track',
+	'sunrise',
+	'sunrise_over_mountains',
+	'desert',
+	'beach',
+	'island',
+	'city_sunset',
+	'city_dusk',
+	'cityscape',
+	'night_with_stars',
+	'bridge_at_night',
+	'milky_way',
+	'stars',
+	'sparkler',
+	'fireworks',
+	'rainbow',
+	'homes',
+	'european_castle',
+	'japanese_castle',
+	'stadium',
+	'statue_of_liberty',
+	'house',
+	'house_with_garden',
+	'house_abandoned',
+	'office',
+	'department_store',
+	'post_office',
+	'european_post_office',
+	'hospital',
+	'bank',
+	'hotel',
+	'convenience_store',
+	'school',
+	'love_hotel',
+	'wedding',
+	'classical_building',
+	'church',
+	'mosque',
+	'synagogue',
+	'kaaba',
+	'shinto_shrine',
+	'shopping_cart',
+	'scooter',
+	'motor_scooter',
+	'canoe',
+	'watch',
+	'iphone',
+	'calling',
+	'computer',
+	'keyboard',
+	'desktop',
+	'printer',
+	'mouse_three_button',
+	'trackball',
+	'joystick',
+	'compression',
+	'minidisc',
+	'floppy_disk',
+	'cd',
+	'dvd',
+	'vhs',
+	'camera',
+	'camera_with_flash',
+	'video_camera',
+	'movie_camera',
+	'projector',
+	'film_frames',
+	'telephone_receiver',
+	'telephone',
+	'pager',
+	'fax',
+	'tv',
+	'radio',
+	'microphone2',
+	'level_slider',
+	'control_knobs',
+	'stopwatch',
+	'timer',
+	'alarm_clock',
+	'clock',
+	'hourglass_flowing_sand',
+	'hourglass',
+	'satellite',
+	'battery',
+	'electric_plug',
+	'bulb',
+	'flashlight',
+	'candle',
+	'wastebasket',
+	'oil',
+	'money_with_wings',
+	'dollar',
+	'yen',
+	'euro',
+	'pound',
+	'moneybag',
+	'credit_card',
+	'gem',
+	'scales',
+	'wrench',
+	'hammer',
+	'hammer_pick',
+	'tools',
+	'pick',
+	'nut_and_bolt',
+	'gear',
+	'chains',
+	'gun',
+	'bomb',
+	'knife',
+	'dagger',
+	'crossed_swords',
+	'shield',
+	'smoking',
+	'skull_crossbones',
+	'coffin',
+	'urn',
+	'amphora',
+	'crystal_ball',
+	'prayer_beads',
+	'barber',
+	'alembic',
+	'telescope',
+	'microscope',
+	'hole',
+	'pill',
+	'syringe',
+	'thermometer',
+	'label',
+	'bookmark',
+	'toilet',
+	'shower',
+	'bathtub',
+	'key',
+	'key2',
+	'couch',
+	'sleeping_accommodation',
+	'bed',
+	'door',
+	'bellhop',
+	'frame_photo',
+	'map',
+	'beach_umbrella',
+	'moyai',
+	'shopping_bags',
+	'balloon',
+	'flags',
+	'ribbon',
+	'gift',
+	'confetti_ball',
+	'tada',
+	'dolls',
+	'wind_chime',
+	'crossed_flags',
+	'izakaya_lantern',
+	'envelope',
+	'envelope_with_arrow',
+	'incoming_envelope',
+	'e-mail',
+	'love_letter',
+	'postbox',
+	'mailbox_closed',
+	'mailbox',
+	'mailbox_with_mail',
+	'mailbox_with_no_mail',
+	'package',
+	'postal_horn',
+	'inbox_tray',
+	'outbox_tray',
+	'scroll',
+	'page_with_curl',
+	'bookmark_tabs',
+	'bar_chart',
+	'chart_with_upwards_trend',
+	'chart_with_downwards_trend',
+	'page_facing_up',
+	'date',
+	'calendar',
+	'calendar_spiral',
+	'card_index',
+	'card_box',
+	'ballot_box',
+	'file_cabinet',
+	'clipboard',
+	'notepad_spiral',
+	'file_folder',
+	'open_file_folder',
+	'dividers',
+	'newspaper2',
+	'newspaper',
+	'notebook',
+	'closed_book',
+	'green_book',
+	'blue_book',
+	'orange_book',
+	'notebook_with_decorative_cover',
+	'ledger',
+	'books',
+	'book',
+	'link',
+	'paperclip',
+	'paperclips',
+	'scissors',
+	'triangular_ruler',
+	'straight_ruler',
+	'pushpin',
+	'round_pushpin',
+	'triangular_flag_on_post',
+	'flag_white',
+	'flag_black',
+	'closed_lock_with_key',
+	'lock',
+	'unlock',
+	'lock_with_ink_pen',
+	'pen_ballpoint',
+	'pen_fountain',
+	'black_nib',
+	'pencil',
+	'pencil2',
+	'crayon',
+	'paintbrush',
+	'mag',
+	'mag_right',
+	'100',
+	'1234',
+	'heart',
+	'yellow_heart',
+	'green_heart',
+	'blue_heart',
+	'purple_heart',
+	'broken_heart',
+	'heart_exclamation',
+	'two_hearts',
+	'revolving_hearts',
+	'heartbeat',
+	'heartpulse',
+	'sparkling_heart',
+	'cupid',
+	'gift_heart',
+	'heart_decoration',
+	'peace',
+	'cross',
+	'star_and_crescent',
+	'om_symbol',
+	'wheel_of_dharma',
+	'star_of_david',
+	'six_pointed_star',
+	'menorah',
+	'yin_yang',
+	'orthodox_cross',
+	'place_of_worship',
+	'ophiuchus',
+	'aries',
+	'taurus',
+	'gemini',
+	'cancer',
+	'leo',
+	'virgo',
+	'libra',
+	'scorpius',
+	'sagittarius',
+	'capricorn',
+	'aquarius',
+	'pisces',
+	'id',
+	'atom',
+	'u7a7a',
+	'u5272',
+	'radioactive',
+	'biohazard',
+	'mobile_phone_off',
+	'vibration_mode',
+	'u6709',
+	'u7121',
+	'u7533',
+	'u55b6',
+	'u6708',
+	'eight_pointed_black_star',
+	'vs',
+	'accept',
+	'white_flower',
+	'ideograph_advantage',
+	'secret',
+	'congratulations',
+	'u5408',
+	'u6e80',
+	'u7981',
+	'a',
+	'b',
+	'ab',
+	'cl',
+	'o2',
+	'sos',
+	'no_entry',
+	'name_badge',
+	'no_entry_sign',
+	'x',
+	'o',
+	'anger',
+	'hotsprings',
+	'no_pedestrians',
+	'do_not_litter',
+	'no_bicycles',
+	'non-potable_water',
+	'underage',
+	'no_mobile_phones',
+	'exclamation',
+	'grey_exclamation',
+	'question',
+	'grey_question',
+	'bangbang',
+	'interrobang',
+	'low_brightness',
+	'high_brightness',
+	'trident',
+	'fleur-de-lis',
+	'part_alternation_mark',
+	'warning',
+	'children_crossing',
+	'beginner',
+	'recycle',
+	'u6307',
+	'chart',
+	'sparkle',
+	'eight_spoked_asterisk',
+	'negative_squared_cross_mark',
+	'white_check_mark',
+	'diamond_shape_with_a_dot_inside',
+	'cyclone',
+	'loop',
+	'globe_with_meridians',
+	'm',
+	'atm',
+	'sa',
+	'passport_control',
+	'customs',
+	'baggage_claim',
+	'left_luggage',
+	'wheelchair',
+	'no_smoking',
+	'wc',
+	'parking',
+	'potable_water',
+	'mens',
+	'womens',
+	'baby_symbol',
+	'restroom',
+	'put_litter_in_its_place',
+	'cinema',
+	'signal_strength',
+	'koko',
+	'ng',
+	'ok',
+	'up',
+	'cool',
+	'new',
+	'free',
+	'zero',
+	'one',
+	'two',
+	'three',
+	'four',
+	'five',
+	'six',
+	'seven',
+	'eight',
+	'nine',
+	'keycap_ten',
+	'arrow_forward',
+	'pause_button',
+	'play_pause',
+	'stop_button',
+	'record_button',
+	'track_next',
+	'track_previous',
+	'fast_forward',
+	'rewind',
+	'twisted_rightwards_arrows',
+	'repeat',
+	'repeat_one',
+	'arrow_backward',
+	'arrow_up_small',
+	'arrow_down_small',
+	'arrow_double_up',
+	'arrow_double_down',
+	'arrow_right',
+	'arrow_left',
+	'arrow_up',
+	'arrow_down',
+	'arrow_upper_right',
+	'arrow_lower_right',
+	'arrow_lower_left',
+	'arrow_upper_left',
+	'arrow_up_down',
+	'left_right_arrow',
+	'arrows_counterclockwise',
+	'arrow_right_hook',
+	'leftwards_arrow_with_hook',
+	'arrow_heading_up',
+	'arrow_heading_down',
+	'hash',
+	'asterisk',
+	'information_source',
+	'abc',
+	'abcd',
+	'capital_abcd',
+	'symbols',
+	'musical_note',
+	'notes',
+	'wavy_dash',
+	'curly_loop',
+	'heavy_check_mark',
+	'arrows_clockwise',
+	'heavy_plus_sign',
+	'heavy_minus_sign',
+	'heavy_division_sign',
+	'heavy_multiplication_x',
+	'heavy_dollar_sign',
+	'currency_exchange',
+	'copyright',
+	'registered',
+	'tm',
+	'end',
+	'back',
+	'on',
+	'top',
+	'soon',
+	'ballot_box_with_check',
+	'radio_button',
+	'white_circle',
+	'black_circle',
+	'red_circle',
+	'large_blue_circle',
+	'small_orange_diamond',
+	'small_blue_diamond',
+	'large_orange_diamond',
+	'large_blue_diamond',
+	'small_red_triangle',
+	'black_small_square',
+	'white_small_square',
+	'black_large_square',
+	'white_large_square',
+	'small_red_triangle_down',
+	'black_medium_square',
+	'white_medium_square',
+	'black_medium_small_square',
+	'white_medium_small_square',
+	'black_square_button',
+	'white_square_button',
+	'speaker',
+	'sound',
+	'loud_sound',
+	'mute',
+	'mega',
+	'loudspeaker',
+	'bell',
+	'no_bell',
+	'black_joker',
+	'mahjong',
+	'spades',
+	'clubs',
+	'hearts',
+	'diamonds',
+	'flower_playing_cards',
+	'thought_balloon',
+	'anger_right',
+	'speech_balloon',
+	'clock1',
+	'clock2',
+	'clock3',
+	'clock4',
+	'clock5',
+	'clock6',
+	'clock7',
+	'clock8',
+	'clock9',
+	'clock10',
+	'clock11',
+	'clock12',
+	'clock130',
+	'clock230',
+	'clock330',
+	'clock430',
+	'clock530',
+	'clock630',
+	'clock730',
+	'clock830',
+	'clock930',
+	'clock1030',
+	'clock1130',
+	'clock1230',
+	'eye_in_speech_bubble',
+	'speech_left',
+	'eject',
+	'black_heart',
+	'octagonal_sign',
+	'asterisk_symbol',
+	'pound_symbol',
+	'digit_nine',
+	'digit_eight',
+	'digit_seven',
+	'digit_six',
+	'digit_five',
+	'digit_four',
+	'digit_three',
+	'digit_two',
+	'digit_one',
+	'digit_zero',
+	'regional_indicator_z',
+	'regional_indicator_y',
+	'regional_indicator_x',
+	'regional_indicator_w',
+	'regional_indicator_v',
+	'regional_indicator_u',
+	'regional_indicator_t',
+	'regional_indicator_s',
+	'regional_indicator_r',
+	'regional_indicator_q',
+	'regional_indicator_p',
+	'regional_indicator_o',
+	'regional_indicator_n',
+	'regional_indicator_m',
+	'regional_indicator_l',
+	'regional_indicator_k',
+	'regional_indicator_j',
+	'regional_indicator_i',
+	'regional_indicator_h',
+	'regional_indicator_g',
+	'regional_indicator_f',
+	'regional_indicator_e',
+	'regional_indicator_d',
+	'regional_indicator_c',
+	'regional_indicator_b',
+	'regional_indicator_a',
+	'flag_ac',
+	'flag_af',
+	'flag_al',
+	'flag_dz',
+	'flag_ad',
+	'flag_ao',
+	'flag_ai',
+	'flag_ag',
+	'flag_ar',
+	'flag_am',
+	'flag_aw',
+	'flag_au',
+	'flag_at',
+	'flag_az',
+	'flag_bs',
+	'flag_bh',
+	'flag_bd',
+	'flag_bb',
+	'flag_by',
+	'flag_be',
+	'flag_bz',
+	'flag_bj',
+	'flag_bm',
+	'flag_bt',
+	'flag_bo',
+	'flag_ba',
+	'flag_bw',
+	'flag_br',
+	'flag_bn',
+	'flag_bg',
+	'flag_bf',
+	'flag_bi',
+	'flag_cv',
+	'flag_kh',
+	'flag_cm',
+	'flag_ca',
+	'flag_ky',
+	'flag_cf',
+	'flag_td',
+	'flag_cl',
+	'flag_cn',
+	'flag_co',
+	'flag_km',
+	'flag_cg',
+	'flag_cd',
+	'flag_cr',
+	'flag_hr',
+	'flag_cu',
+	'flag_cy',
+	'flag_cz',
+	'flag_dk',
+	'flag_dj',
+	'flag_dm',
+	'flag_do',
+	'flag_ec',
+	'flag_eg',
+	'flag_sv',
+	'flag_gq',
+	'flag_er',
+	'flag_ee',
+	'flag_et',
+	'flag_fk',
+	'flag_fo',
+	'flag_fj',
+	'flag_fi',
+	'flag_fr',
+	'flag_pf',
+	'flag_ga',
+	'flag_gm',
+	'flag_ge',
+	'flag_de',
+	'flag_gh',
+	'flag_gi',
+	'flag_gr',
+	'flag_gl',
+	'flag_gd',
+	'flag_gu',
+	'flag_gt',
+	'flag_gn',
+	'flag_gw',
+	'flag_gy',
+	'flag_ht',
+	'flag_hn',
+	'flag_hk',
+	'flag_hu',
+	'flag_is',
+	'flag_in',
+	'flag_id',
+	'flag_ir',
+	'flag_iq',
+	'flag_ie',
+	'flag_il',
+	'flag_it',
+	'flag_ci',
+	'flag_jm',
+	'flag_jp',
+	'flag_je',
+	'flag_jo',
+	'flag_kz',
+	'flag_ke',
+	'flag_ki',
+	'flag_xk',
+	'flag_kw',
+	'flag_kg',
+	'flag_la',
+	'flag_lv',
+	'flag_lb',
+	'flag_ls',
+	'flag_lr',
+	'flag_ly',
+	'flag_li',
+	'flag_lt',
+	'flag_lu',
+	'flag_mo',
+	'flag_mk',
+	'flag_mg',
+	'flag_mw',
+	'flag_my',
+	'flag_mv',
+	'flag_ml',
+	'flag_mt',
+	'flag_mh',
+	'flag_mr',
+	'flag_mu',
+	'flag_mx',
+	'flag_fm',
+	'flag_md',
+	'flag_mc',
+	'flag_mn',
+	'flag_me',
+	'flag_ms',
+	'flag_ma',
+	'flag_mz',
+	'flag_mm',
+	'flag_na',
+	'flag_nr',
+	'flag_np',
+	'flag_nl',
+	'flag_nc',
+	'flag_nz',
+	'flag_ni',
+	'flag_ne',
+	'flag_ng',
+	'flag_nu',
+	'flag_kp',
+	'flag_no',
+	'flag_om',
+	'flag_pk',
+	'flag_pw',
+	'flag_ps',
+	'flag_pa',
+	'flag_pg',
+	'flag_py',
+	'flag_pe',
+	'flag_ph',
+	'flag_pl',
+	'flag_pt',
+	'flag_pr',
+	'flag_qa',
+	'flag_ro',
+	'flag_ru',
+	'flag_rw',
+	'flag_sh',
+	'flag_kn',
+	'flag_lc',
+	'flag_vc',
+	'flag_ws',
+	'flag_sm',
+	'flag_st',
+	'flag_sa',
+	'flag_sn',
+	'flag_rs',
+	'flag_sc',
+	'flag_sl',
+	'flag_sg',
+	'flag_sk',
+	'flag_si',
+	'flag_sb',
+	'flag_so',
+	'flag_za',
+	'flag_kr',
+	'flag_es',
+	'flag_lk',
+	'flag_sd',
+	'flag_sr',
+	'flag_sz',
+	'flag_se',
+	'flag_ch',
+	'flag_sy',
+	'flag_tw',
+	'flag_tj',
+	'flag_tz',
+	'flag_th',
+	'flag_tl',
+	'flag_tg',
+	'flag_to',
+	'flag_tt',
+	'flag_tn',
+	'flag_tr',
+	'flag_tm',
+	'flag_tv',
+	'flag_ug',
+	'flag_ua',
+	'flag_ae',
+	'flag_gb',
+	'flag_us',
+	'flag_vi',
+	'flag_uy',
+	'flag_uz',
+	'flag_vu',
+	'flag_va',
+	'flag_ve',
+	'flag_vn',
+	'flag_wf',
+	'flag_eh',
+	'flag_ye',
+	'flag_zm',
+	'flag_zw',
+	'flag_re',
+	'flag_ax',
+	'flag_ta',
+	'flag_io',
+	'flag_bq',
+	'flag_cx',
+	'flag_cc',
+	'flag_gg',
+	'flag_im',
+	'flag_yt',
+	'flag_nf',
+	'flag_pn',
+	'flag_bl',
+	'flag_pm',
+	'flag_gs',
+	'flag_tk',
+	'flag_bv',
+	'flag_hm',
+	'flag_sj',
+	'flag_um',
+	'flag_ic',
+	'flag_ea',
+	'flag_cp',
+	'flag_dg',
+	'flag_as',
+	'flag_aq',
+	'flag_vg',
+	'flag_ck',
+	'flag_cw',
+	'flag_eu',
+	'flag_gf',
+	'flag_tf',
+	'flag_gp',
+	'flag_mq',
+	'flag_mp',
+	'flag_sx',
+	'flag_ss',
+	'flag_tc',
+	'flag_mf'
+];
diff --git a/app/lib/realm.js b/app/lib/realm.js
index 17d30e26a72a48a3200b77b194cb4fb7ccf49854..147660455e529617d47046dda72f6b6f6232103e 100644
--- a/app/lib/realm.js
+++ b/app/lib/realm.js
@@ -142,6 +142,21 @@ const url = {
 	}
 };
 
+const messagesReactionsUsernamesSchema = {
+	name: 'messagesReactionsUsernames',
+	properties: {
+		value: 'string'
+	}
+};
+
+const messagesReactionsSchema = {
+	name: 'messagesReactions',
+	primaryKey: 'emoji',
+	properties: {
+		emoji: 'string',
+		usernames: { type: 'list', objectType: 'messagesReactionsUsernames' }
+	}
+};
 
 const messagesEditedBySchema = {
 	name: 'messagesEditedBy',
@@ -173,7 +188,8 @@ const messagesSchema = {
 		status: { type: 'int', optional: true },
 		pinned: { type: 'bool', optional: true },
 		starred: { type: 'bool', optional: true },
-		editedBy: 'messagesEditedBy'
+		editedBy: 'messagesEditedBy',
+		reactions: { type: 'list', objectType: 'messagesReactions' }
 	}
 };
 
@@ -222,7 +238,9 @@ const schema = [
 	url,
 	frequentlyUsedEmojiSchema,
 	customEmojiAliasesSchema,
-	customEmojisSchema
+	customEmojisSchema,
+	messagesReactionsSchema,
+	messagesReactionsUsernamesSchema
 ];
 class DB {
 	databases = {
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index dc0bf1bd64cefd74bc3c24a74e4e53dd711641ff..f56eb1c90e4bba216a17354ff15198c13417b991 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -1,6 +1,7 @@
 import Random from 'react-native-meteor/lib/Random';
 import { AsyncStorage, Platform } from 'react-native';
 import { hashPassword } from 'react-native-meteor/lib/utils';
+import _ from 'lodash';
 
 import RNFetchBlob from 'react-native-fetch-blob';
 import reduxStore from './createStore';
@@ -264,6 +265,8 @@ const RocketChat = {
 		// loadHistory returns message.starred as object
 		// stream-room-messages returns message.starred as an array
 		message.starred = message.starred && (Array.isArray(message.starred) ? message.starred.length > 0 : !!message.starred);
+		message.reactions = _.map(message.reactions, (value, key) =>
+			({ emoji: key, usernames: value.usernames.map(username => ({ value: username })) }));
 		return message;
 	},
 	loadMessagesForRoom(rid, end, cb) {
@@ -586,6 +589,9 @@ const RocketChat = {
 	},
 	setUserPresenceDefaultStatus(status) {
 		return call('UserPresence:setDefaultStatus', status);
+	},
+	setReaction(emoji, messageId) {
+		return call('setReaction', emoji, messageId);
 	}
 };
 
diff --git a/app/reducers/messages.js b/app/reducers/messages.js
index 7c4022375c66a33291b243f3bd30ca7ab7e888bd..ae17f395e042ccd14a03fdc2512620f41c396343 100644
--- a/app/reducers/messages.js
+++ b/app/reducers/messages.js
@@ -8,7 +8,8 @@ const initialState = {
 	editing: false,
 	permalink: '',
 	showActions: false,
-	showErrorActions: false
+	showErrorActions: false,
+	showReactionPicker: false
 };
 
 export default function messages(state = initialState, action) {
@@ -96,6 +97,12 @@ export default function messages(state = initialState, action) {
 				...state,
 				message: {}
 			};
+		case types.MESSAGES.TOGGLE_REACTION_PICKER:
+			return {
+				...state,
+				showReactionPicker: !state.showReactionPicker,
+				actionMessage: action.message
+			};
 		default:
 			return state;
 	}
diff --git a/app/views/RoomView/ListView.js b/app/views/RoomView/ListView.js
index 3eacad9cbb77707b7e99f74ecd703d8a3afd174f..9c89b46f5f13c667ecae2ad8df5f377c17a65234 100644
--- a/app/views/RoomView/ListView.js
+++ b/app/views/RoomView/ListView.js
@@ -4,10 +4,16 @@ import cloneReferencedElement from 'react-clone-referenced-element';
 import { ScrollView, ListView as OldList2 } from 'react-native';
 import moment from 'moment';
 import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+
 import DateSeparator from './DateSeparator';
 import UnreadSeparator from './UnreadSeparator';
+import styles from './styles';
+import debounce from '../../utils/debounce';
+import Typing from '../../containers/Typing';
+import database from '../../lib/realm';
 
-const DEFAULT_SCROLL_CALLBACK_THROTTLE = 50;
+const DEFAULT_SCROLL_CALLBACK_THROTTLE = 100;
 
 export class DataSource extends OldList.DataSource {
 	getRowData(sectionIndex: number, rowIndex: number): any {
@@ -20,9 +26,58 @@ export class DataSource extends OldList.DataSource {
 	}
 }
 
+const ds = new DataSource({ rowHasChanged: (r1, r2) => r1._id !== r2._id });
+
 @connect(state => ({
 	lastOpen: state.room.lastOpen
 }))
+
+export class List extends React.Component {
+	static propTypes = {
+		onEndReached: PropTypes.func,
+		renderFooter: PropTypes.func,
+		renderRow: PropTypes.func,
+		room: PropTypes.string,
+		end: PropTypes.bool
+	};
+	constructor(props) {
+		super(props);
+		this.data = database
+			.objects('messages')
+			.filtered('rid = $0', props.room)
+			.sorted('ts', true);
+		this.dataSource = ds.cloneWithRows(this.data);
+	}
+	componentDidMount() {
+		this.data.addListener(this.updateState);
+	}
+	shouldComponentUpdate(nextProps) {
+		return this.props.end !== nextProps.end;
+	}
+	updateState = debounce(() => {
+		// this.setState({
+		this.dataSource = this.dataSource.cloneWithRows(this.data);
+		this.forceUpdate();
+		// });
+	}, 100);
+
+	render() {
+		return (<ListView
+			enableEmptySections
+			style={styles.list}
+			onEndReachedThreshold={0.5}
+			renderFooter={this.props.renderFooter}
+			renderHeader={() => <Typing />}
+			onEndReached={() => this.props.onEndReached(this.data)}
+			dataSource={this.dataSource}
+			renderRow={item => this.props.renderRow(item)}
+			initialListSize={10}
+			keyboardShouldPersistTaps='always'
+			keyboardDismissMode='none'
+		/>);
+	}
+}
+
 export class ListView extends OldList2 {
 	constructor(props) {
 		super(props);
diff --git a/app/views/RoomView/ReactionPicker.js b/app/views/RoomView/ReactionPicker.js
new file mode 100644
index 0000000000000000000000000000000000000000..96ff5fd2d21458d62cdac62485abdf9f26b38951
--- /dev/null
+++ b/app/views/RoomView/ReactionPicker.js
@@ -0,0 +1,60 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { View, Platform } from 'react-native';
+import { connect } from 'react-redux';
+import Modal from 'react-native-modal';
+import { responsive } from 'react-native-responsive-ui';
+import EmojiPicker from '../../containers/EmojiPicker';
+import { toggleReactionPicker } from '../../actions/messages';
+import styles from './styles';
+
+const margin = Platform.OS === 'android' ? 40 : 20;
+const tabEmojiStyle = { fontSize: 15 };
+
+@connect(state => ({
+	showReactionPicker: state.messages.showReactionPicker
+}), dispatch => ({
+	toggleReactionPicker: message => dispatch(toggleReactionPicker(message))
+}))
+@responsive
+export default class extends React.Component {
+	static propTypes = {
+		window: PropTypes.any,
+		showReactionPicker: PropTypes.bool,
+		toggleReactionPicker: PropTypes.func,
+		onEmojiSelected: PropTypes.func
+	};
+
+	shouldComponentUpdate(nextProps) {
+		return nextProps.showReactionPicker !== this.props.showReactionPicker || this.props.window.width !== nextProps.window.width;
+	}
+
+	onEmojiSelected(emoji, shortname) {
+		// standard emojis: `emoji` is unicode and `shortname` is :joy:
+		// custom emojis: only `emoji` is returned with shortname type (:joy:)
+		// to set reactions, we need shortname type
+		this.props.onEmojiSelected(shortname || emoji);
+	}
+
+	render() {
+		const { width, height } = this.props.window;
+		return (
+			<Modal
+				isVisible={this.props.showReactionPicker}
+				style={{ alignItems: 'center' }}
+				onBackdropPress={() => this.props.toggleReactionPicker()}
+				onBackButtonPress={() => this.props.toggleReactionPicker()}
+				animationIn='fadeIn'
+				animationOut='fadeOut'
+			>
+				<View style={[styles.reactionPickerContainer, { width: width - margin, height: Math.min(width, height) - (margin * 2) }]}>
+					<EmojiPicker
+						tabEmojiStyle={tabEmojiStyle}
+						width={Math.min(width, height) - margin}
+						onEmojiSelected={(emoji, shortname) => this.onEmojiSelected(emoji, shortname)}
+					/>
+				</View>
+			</Modal>
+		);
+	}
+}
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index 94bbd4f1268bd7653e272789e33ba1bed52493ae..dd76d5d43cceb6537a613d1466d056c92ed2aa92 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -1,44 +1,45 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { Text, View, Button, SafeAreaView, Platform } from 'react-native';
+import { Text, View, Button, SafeAreaView, Platform, Keyboard } from 'react-native';
 import { connect } from 'react-redux';
 import { bindActionCreators } from 'redux';
 import equal from 'deep-equal';
 import KeyboardSpacer from 'react-native-keyboard-spacer';
 
-import { ListView } from './ListView';
+import { List } from './ListView';
 import * as actions from '../../actions';
 import { openRoom, setLastOpen } from '../../actions/room';
-import { editCancel } from '../../actions/messages';
+import { editCancel, toggleReactionPicker } from '../../actions/messages';
+import { setKeyboardOpen, setKeyboardClosed } from '../../actions/keyboard';
 import database from '../../lib/realm';
 import RocketChat from '../../lib/rocketchat';
 import Message from '../../containers/message';
 import MessageActions from '../../containers/MessageActions';
 import MessageErrorActions from '../../containers/MessageErrorActions';
 import MessageBox from '../../containers/MessageBox';
-import Typing from '../../containers/Typing';
+
 import Header from '../../containers/Header';
 import RoomsHeader from './Header';
+import ReactionPicker from './ReactionPicker';
 import Banner from './banner';
 import styles from './styles';
 
-import debounce from '../../utils/debounce';
-
-const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1._id !== r2._id });
-
-const typing = () => <Typing />;
 @connect(
 	state => ({
 		Site_Url: state.settings.Site_Url || state.server ? state.server.server : '',
 		Message_TimeFormat: state.settings.Message_TimeFormat,
 		loading: state.messages.isFetching,
-		user: state.login.user
+		user: state.login.user,
+		actionMessage: state.messages.actionMessage
 	}),
 	dispatch => ({
 		actions: bindActionCreators(actions, dispatch),
 		openRoom: room => dispatch(openRoom(room)),
 		editCancel: () => dispatch(editCancel()),
-		setLastOpen: date => dispatch(setLastOpen(date))
+		setLastOpen: date => dispatch(setLastOpen(date)),
+		toggleReactionPicker: message => dispatch(toggleReactionPicker(message)),
+		setKeyboardOpen: () => dispatch(setKeyboardOpen()),
+		setKeyboardClosed: () => dispatch(setKeyboardClosed())
 	})
 )
 export default class RoomView extends React.Component {
@@ -51,7 +52,12 @@ export default class RoomView extends React.Component {
 		rid: PropTypes.string,
 		name: PropTypes.string,
 		Site_Url: PropTypes.string,
-		Message_TimeFormat: PropTypes.string
+		Message_TimeFormat: PropTypes.string,
+		loading: PropTypes.bool,
+		actionMessage: PropTypes.object,
+		toggleReactionPicker: PropTypes.func.isRequired,
+		setKeyboardOpen: PropTypes.func,
+		setKeyboardClosed: PropTypes.func
 	};
 
 	static navigationOptions = ({ navigation }) => ({
@@ -63,22 +69,17 @@ export default class RoomView extends React.Component {
 		this.rid =
 			props.rid ||
 			props.navigation.state.params.room.rid;
-		this.name = this.props.name ||
-		this.props.navigation.state.params.name ||
-		this.props.navigation.state.params.room.name;
+		this.name = props.name ||
+			props.navigation.state.params.name ||
+			props.navigation.state.params.room.name;
 		this.opened = new Date();
-		this.data = database
-			.objects('messages')
-			.filtered('rid = $0', this.rid)
-			.sorted('ts', true);
-		const rowIds = this.data.map((row, index) => index);
 		this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
 		this.state = {
-			dataSource: ds.cloneWithRows(this.data, rowIds),
 			loaded: true,
 			joined: typeof props.rid === 'undefined',
-			readOnly: false
+			room: {}
 		};
+		this.onReactionPress = this.onReactionPress.bind(this);
 	}
 
 	componentWillMount() {
@@ -86,59 +87,58 @@ export default class RoomView extends React.Component {
 			title: this.name
 		});
 		this.updateRoom();
-		this.props.openRoom({ rid: this.rid, name: this.name, ls: this.room.ls });
-		if (this.room.alert || this.room.unread || this.room.userMentions) {
-			this.props.setLastOpen(this.room.ls);
+		this.props.openRoom({ rid: this.rid, name: this.name, ls: this.state.room.ls });
+		if (this.state.room.alert || this.state.room.unread || this.state.room.userMentions) {
+			this.props.setLastOpen(this.state.room.ls);
 		} else {
 			this.props.setLastOpen(null);
 		}
-		this.data.addListener(this.updateState);
+
 		this.rooms.addListener(this.updateRoom);
+		this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => this.props.setKeyboardOpen());
+		this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => this.props.setKeyboardClosed());
 	}
 	shouldComponentUpdate(nextProps, nextState) {
 		return !(equal(this.props, nextProps) && equal(this.state, nextState));
 	}
 	componentWillUnmount() {
 		clearTimeout(this.timer);
-		this.data.removeAllListeners();
+		this.rooms.removeAllListeners();
+		this.keyboardDidShowListener.remove();
+		this.keyboardDidHideListener.remove();
 		this.props.editCancel();
 	}
 
-	onEndReached = () => {
-		if (
-			// rowCount &&
-			this.state.loaded &&
-			this.state.loadingMore !== true &&
-			this.state.end !== true
-		) {
-			this.setState({
-				loadingMore: true
-			});
-			requestAnimationFrame(() => {
-				const lastRowData = this.data[this.data.length - 1];
-				if (!lastRowData) {
-					return;
-				}
-				RocketChat.loadMessagesForRoom(this.rid, lastRowData.ts, ({ end }) => {
-					this.setState({
-						loadingMore: false,
-						end
-					});
-				});
-			});
+	onEndReached = (data) => {
+		if (this.props.loading || this.state.end) {
+			return;
+		}
+		if (!this.state.loaded) {
+			alert(2);
+			return;
 		}
-	}
 
-	updateState = debounce(() => {
-		const rowIds = this.data.map((row, index) => index);
-		this.setState({
-			dataSource: this.state.dataSource.cloneWithRows(this.data, rowIds)
+		requestAnimationFrame(() => {
+			const lastRowData = data[data.length - 1];
+			if (!lastRowData) {
+				return;
+			}
+			RocketChat.loadMessagesForRoom(this.rid, lastRowData.ts, ({ end }) => end && this.setState({
+				end
+			}));
 		});
-	}, 50);
+	}
+
+	onReactionPress = (shortname, messageId) => {
+		if (!messageId) {
+			RocketChat.setReaction(shortname, this.props.actionMessage._id);
+			return this.props.toggleReactionPicker();
+		}
+		RocketChat.setReaction(shortname, messageId);
+	};
 
 	updateRoom = () => {
-		[this.room] = this.rooms;
-		this.setState({ readOnly: this.room.ro });
+		this.setState({ room: this.rooms[0] });
 	}
 
 	sendMessage = message => RocketChat.sendMessage(this.rid, message).then(() => {
@@ -156,10 +156,12 @@ export default class RoomView extends React.Component {
 		<Message
 			key={item._id}
 			item={item}
+			reactions={JSON.parse(JSON.stringify(item.reactions))}
 			animate={this.opened.toISOString() < item.ts.toISOString()}
 			baseUrl={this.props.Site_Url}
 			Message_TimeFormat={this.props.Message_TimeFormat}
 			user={this.props.user}
+			onReactionPress={this.onReactionPress}
 		/>
 	);
 
@@ -174,7 +176,7 @@ export default class RoomView extends React.Component {
 				</View>
 			);
 		}
-		if (this.state.readOnly) {
+		if (this.state.room.ro) {
 			return (
 				<View style={styles.readOnly}>
 					<Text>This room is read only</Text>
@@ -185,36 +187,28 @@ export default class RoomView extends React.Component {
 	};
 
 	renderHeader = () => {
-		if (this.state.loadingMore) {
-			return <Text style={styles.loadingMore}>Loading more messages...</Text>;
-		}
-
 		if (this.state.end) {
 			return <Text style={styles.loadingMore}>Start of conversation</Text>;
 		}
+		return <Text style={styles.loadingMore}>Loading more messages...</Text>;
 	}
 	render() {
 		return (
 			<View style={styles.container}>
 				<Banner />
 				<SafeAreaView style={styles.safeAreaView}>
-					<ListView
-						enableEmptySections
-						style={styles.list}
-						onEndReachedThreshold={500}
+					<List
+						end={this.state.end}
+						room={this.rid}
 						renderFooter={this.renderHeader}
-						renderHeader={typing}
 						onEndReached={this.onEndReached}
-						dataSource={this.state.dataSource}
 						renderRow={item => this.renderItem(item)}
-						initialListSize={10}
-						keyboardShouldPersistTaps='always'
-						keyboardDismissMode='none'
 					/>
 				</SafeAreaView>
 				{this.renderFooter()}
-				<MessageActions room={this.room} />
+				{this.state.room._id ? <MessageActions room={this.state.room} /> : null}
 				<MessageErrorActions />
+				<ReactionPicker onEmojiSelected={this.onReactionPress} />
 				{Platform.OS === 'ios' ? <KeyboardSpacer /> : null}
 			</View>
 		);
diff --git a/app/views/RoomView/styles.js b/app/views/RoomView/styles.js
index 2e2713d05ec1da75427eb6af3e8e7dfc3de6f9c3..6b68d2333f79004b48893e1de487bbc1af09418f 100644
--- a/app/views/RoomView/styles.js
+++ b/app/views/RoomView/styles.js
@@ -1,4 +1,4 @@
-import { StyleSheet } from 'react-native';
+import { StyleSheet, Platform } from 'react-native';
 
 export default StyleSheet.create({
 	typing: { fontWeight: 'bold', paddingHorizontal: 15, height: 25 },
@@ -33,5 +33,13 @@ export default StyleSheet.create({
 	},
 	readOnly: {
 		padding: 10
+	},
+	reactionPickerContainer: {
+		// width: width - 20,
+		// height: width - 20,
+		paddingHorizontal: Platform.OS === 'android' ? 11 : 10,
+		backgroundColor: '#F7F7F7',
+		borderRadius: 4,
+		flexDirection: 'column'
 	}
 });
diff --git a/package-lock.json b/package-lock.json
index df02c28ade2f7b6dc3607f26de87e586907f6e38..fb9a3f7ab24d55141a8977a3f36fe23df03d341f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1481,6 +1481,16 @@
         "babel-helper-is-void-0": "0.2.0"
       }
     },
+    "babel-plugin-module-resolver": {
+      "version": "2.7.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-2.7.1.tgz",
+      "integrity": "sha1-GL48Qt31n3pFbJ4FEs2ROU9uS+E=",
+      "requires": {
+        "find-babel-config": "1.1.0",
+        "glob": "7.1.2",
+        "resolve": "1.5.0"
+      }
+    },
     "babel-plugin-react-transform": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/babel-plugin-react-transform/-/babel-plugin-react-transform-3.0.0.tgz",
@@ -2172,6 +2182,18 @@
         "semver": "5.4.1"
       }
     },
+    "babel-preset-expo": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-4.0.0.tgz",
+      "integrity": "sha512-EWFC6WJzZX5t2zZfLNdJXUkNMusUkxP5V+GrXaSk8pKbWGjE3TD2i33ncpF/4aQM9QGDm+SH6pImZJOqIDlRUw==",
+      "requires": {
+        "babel-plugin-module-resolver": "2.7.1",
+        "babel-plugin-transform-decorators-legacy": "1.3.4",
+        "babel-plugin-transform-exponentiation-operator": "6.24.1",
+        "babel-plugin-transform-export-extensions": "6.22.0",
+        "babel-preset-react-native": "4.0.0"
+      }
+    },
     "babel-preset-fbjs": {
       "version": "2.1.4",
       "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.1.4.tgz",
@@ -4610,11 +4632,6 @@
       "resolved": "https://registry.npmjs.org/email-validator/-/email-validator-1.1.1.tgz",
       "integrity": "sha512-vkcJJZEb7JXDY883Nx1Lkmb6noM3j1SfSt8L9tVFhZPnPQiFq+Nkd5evc77+tRVS4ChTUSr34voThsglI/ja/A=="
     },
-    "emoji-datasource": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/emoji-datasource/-/emoji-datasource-4.0.3.tgz",
-      "integrity": "sha1-1gDnDwVoMnyyjPp79B1T88SGeQE="
-    },
     "emoji-regex": {
       "version": "6.5.1",
       "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
@@ -5771,6 +5788,15 @@
         }
       }
     },
+    "find-babel-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-1.1.0.tgz",
+      "integrity": "sha1-rMAQQ6Z0n+w0Qpvmtk9ULrtdY1U=",
+      "requires": {
+        "json5": "0.5.1",
+        "path-exists": "3.0.0"
+      }
+    },
     "find-cache-dir": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
@@ -12610,6 +12636,14 @@
       "resolved": "https://registry.npmjs.org/react-native-push-notification/-/react-native-push-notification-3.0.1.tgz",
       "integrity": "sha1-DiPbMC0Du0o/KNwHLcryqaEXjtg="
     },
+    "react-native-responsive-ui": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/react-native-responsive-ui/-/react-native-responsive-ui-1.1.1.tgz",
+      "integrity": "sha1-60GDnU85Uf8CVmAYXDapqc4zdZ8=",
+      "requires": {
+        "lodash": "4.17.4"
+      }
+    },
     "react-native-scrollable-tab-view": {
       "version": "0.8.0",
       "resolved": "https://registry.npmjs.org/react-native-scrollable-tab-view/-/react-native-scrollable-tab-view-0.8.0.tgz",
@@ -14445,11 +14479,6 @@
         "strip-ansi": "4.0.0"
       }
     },
-    "string.fromcodepoint": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/string.fromcodepoint/-/string.fromcodepoint-0.2.1.tgz",
-      "integrity": "sha1-jZeDM8C8klOPUPOD5IiPPlYZ1lM="
-    },
     "string_decoder": {
       "version": "0.10.31",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
diff --git a/package.json b/package.json
index 71bf39267e11189fa5a238f573e125a7cb6b52b8..7dd8888674608c7f8890ddc83bffb838e8d80717 100644
--- a/package.json
+++ b/package.json
@@ -27,9 +27,9 @@
     "babel-plugin-transform-decorators-legacy": "^1.3.4",
     "babel-plugin-transform-remove-console": "^6.8.5",
     "babel-polyfill": "^6.26.0",
+    "babel-preset-expo": "^4.0.0",
     "deep-equal": "^1.0.1",
     "ejson": "^2.1.2",
-    "emoji-datasource": "^4.0.3",
     "lodash": "^4.17.4",
     "moment": "^2.20.1",
     "prop-types": "^15.6.0",
@@ -51,6 +51,7 @@
     "react-native-modal": "^4.1.1",
     "react-native-optimized-flatlist": "^1.0.3",
     "react-native-push-notification": "^3.0.1",
+    "react-native-responsive-ui": "^1.1.1",
     "react-native-scrollable-tab-view": "^0.8.0",
     "react-native-slider": "^0.11.0",
     "react-native-splash-screen": "^3.0.6",
@@ -72,7 +73,6 @@
     "remote-redux-devtools": "^0.5.12",
     "simple-markdown": "^0.3.1",
     "snyk": "^1.61.1",
-    "string.fromcodepoint": "^0.2.1",
     "strip-ansi": "^4.0.0"
   },
   "devDependencies": {