RocketChat.settings.addGroup 'OAuth', ->
	@section 'WordPress', ->
		enableQuery = {_id: 'Accounts_OAuth_Wordpress', value: true}
		@add 'Accounts_OAuth_Wordpress', false, { type: 'boolean', public: true }
		@add 'API_Wordpress_URL', '', { type: 'string', enableQuery: enableQuery, public: true }
		@add 'Accounts_OAuth_Wordpress_id', '', { type: 'string', enableQuery: enableQuery }
		@add 'Accounts_OAuth_Wordpress_secret', '', { type: 'string', enableQuery: enableQuery }
		@add 'Accounts_OAuth_Wordpress_callback_url', '_oauth/wordpress', { type: 'relativeUrl', readonly: true, force: true, enableQuery: enableQuery }


return ChatSubscription.find query, { sort: 't': 1, 'name': 1 }

return ChatSubscription.find({ f: true }).count()

keep keep keep replace replace keep keep keep keep

query.$or = [
alert: $ne: true
,
hideUnreadStatus: true
]

/* globals RocketChatFileEmojiCustomInstance */
Meteor.methods({
	insertOrUpdateEmoji(emojiData) {
		if (!RocketChat.authz.hasPermission(this.userId, 'manage-emoji')) {
			throw new Meteor.Error('not_authorized');
		}

		if (!s.trim(emojiData.name)) {
			throw new Meteor.Error('error-the-field-is-required', 'The field Name is required', { method: 'insertOrUpdateEmoji', field: 'Name' });
		}

		//let nameValidation = new RegExp('^[0-9a-zA-Z-_+;.]+$');
		//let aliasValidation = new RegExp('^[0-9a-zA-Z-_+;., ]+$');

		//allow all characters except colon, whitespace, comma, >, <, &, ", ', /, \, (, )
		//more practical than allowing specific sets of characters; also allows foreign languages
		const nameValidation = /[\s,:><&"'\/\\\(\)]/;
		const aliasValidation = /[:><&"'\/\\\(\)]/;

		//silently strip colon; this allows for uploading :emojiname: as emojiname
		emojiData.name = emojiData.name.replace(/:/g, '');
		emojiData.aliases = emojiData.aliases.replace(/:/g, '');

		if (nameValidation.test(emojiData.name)) {
			throw new Meteor.Error('error-input-is-not-a-valid-field', `${emojiData.name} is not a valid name`, { method: 'insertOrUpdateEmoji', input: emojiData.name, field: 'Name' });
		}

		if (emojiData.aliases) {
			if (aliasValidation.test(emojiData.aliases)) {
				throw new Meteor.Error('error-input-is-not-a-valid-field', `${emojiData.aliases} is not a valid alias set`, { method: 'insertOrUpdateEmoji', input: emojiData.aliases, field: 'Alias_Set' });
			}
			emojiData.aliases = emojiData.aliases.split(/[\s,]/);
			emojiData.aliases = emojiData.aliases.filter(Boolean);
			emojiData.aliases = _.without(emojiData.aliases, emojiData.name);
		} else {
			emojiData.aliases = [];
		}

		let matchingResults = [];

		if (emojiData._id) {
			matchingResults = RocketChat.models.EmojiCustom.findByNameOrAliasExceptID(emojiData.name, emojiData._id).fetch();
			for (const alias of emojiData.aliases) {
				matchingResults = matchingResults.concat(RocketChat.models.EmojiCustom.findByNameOrAliasExceptID(alias, emojiData._id).fetch());
			}
		} else {
			matchingResults = RocketChat.models.EmojiCustom.findByNameOrAlias(emojiData.name).fetch();
			for (const alias of emojiData.aliases) {
				matchingResults = matchingResults.concat(RocketChat.models.EmojiCustom.findByNameOrAlias(alias).fetch());
			}
		}

		if (matchingResults.length > 0) {
			throw new Meteor.Error('Custom_Emoji_Error_Name_Or_Alias_Already_In_Use', 'The custom emoji or one of its aliases is already in use', { method: 'insertOrUpdateEmoji' });
		}

		if (!emojiData._id) {
			//insert emoji
			const createEmoji = {
				name: emojiData.name,
				aliases: emojiData.aliases,
				extension: emojiData.extension
			};

			const _id = RocketChat.models.EmojiCustom.create(createEmoji);

			RocketChat.Notifications.notifyLogged('updateEmojiCustom', {emojiData: createEmoji});

			return _id;
		} else {
			//update emoji
			if (emojiData.newFile) {
				RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${emojiData.name}.${emojiData.extension}`));
				RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${emojiData.name}.${emojiData.previousExtension}`));
				RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${emojiData.previousName}.${emojiData.extension}`));
				RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${emojiData.previousName}.${emojiData.previousExtension}`));

				RocketChat.models.EmojiCustom.setExtension(emojiData._id, emojiData.extension);
			} else if (emojiData.name !== emojiData.previousName) {
				const rs = RocketChatFileEmojiCustomInstance.getFileWithReadStream(encodeURIComponent(`${emojiData.previousName}.${emojiData.previousExtension}`));
				if (rs !== null) {
					RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${emojiData.name}.${emojiData.extension}`));
					const ws = RocketChatFileEmojiCustomInstance.createWriteStream(encodeURIComponent(`${emojiData.name}.${emojiData.previousExtension}`), rs.contentType);
					ws.on('end', Meteor.bindEnvironment(() =>
						RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${emojiData.previousName}.${emojiData.previousExtension}`))
						));
					rs.readStream.pipe(ws);
				}
			}

			if (emojiData.name !== emojiData.previousName) {
				RocketChat.models.EmojiCustom.setName(emojiData._id, emojiData.name);
			}

			if (emojiData.aliases) {
				RocketChat.models.EmojiCustom.setAliases(emojiData._id, emojiData.aliases);
			} else {
				RocketChat.models.EmojiCustom.setAliases(emojiData._id, []);
			}

			RocketChat.Notifications.notifyLogged('updateEmojiCustom', {emojiData});

			return true;
		}
	}
});


@unreadRooms = ChatSubscription.find query, { sort: 't': 1, 'name': 1 }

Template.directMessages.helpers
	isActive: ->
		return 'active' if ChatSubscription.findOne({ t: { $in: ['d']}, f: { $ne: true }, open: true, rid: Session.get('openedRoom') }, { fields: { _id: 1 } })?

	rooms: ->
		query = { t: { $in: ['d']}, f: { $ne: true }, open: true }

		if Meteor.user()?.settings?.preferences?.unreadRoomsMode
			query.alert =
				$ne: true

		return ChatSubscription.find query, { sort: 't': 1, 'name': 1 }


/*!
 * EventEmitter v5.1.0 - git.io/ee
 * Unlicense - http://unlicense.org/
 * Oliver Caldwell - http://oli.me.uk/
 * @preserve
 */
(function(exports) {
	'use strict';

	/**
	 * Class for managing events.
	 * Can be extended to provide event functionality in other classes.
	 *
	 * @class EventEmitter Manages event registering and emitting.
	 */
	function EventEmitter() {}

	// Shortcuts to improve speed and size
	var proto = EventEmitter.prototype;
	var originalGlobalValue = exports.EventEmitter;

	/**
	 * Finds the index of the listener for the event in its storage array.
	 *
	 * @param {Function[]} listeners Array of listeners to search through.
	 * @param {Function} listener Method to look for.
	 * @return {Number} Index of the specified listener, -1 if not found
	 * @api private
	 */
	function indexOfListener(listeners, listener) {
		var i = listeners.length;
		while (i--) {
			if (listeners[i].listener === listener) {
				return i;
			}
		}

		return -1;
	}

	/**
	 * Alias a method while keeping the context correct, to allow for overwriting of target method.
	 *
	 * @param {String} name The name of the target method.
	 * @return {Function} The aliased method
	 * @api private
	 */
	function alias(name) {
		return function aliasClosure() {
			return this[name].apply(this, arguments);
		};
	}

	/**
	 * Returns the listener array for the specified event.
	 * Will initialise the event object and listener arrays if required.
	 * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
	 * Each property in the object response is an array of listener functions.
	 *
	 * @param {String|RegExp} evt Name of the event to return the listeners from.
	 * @return {Function[]|Object} All listener functions for the event.
	 */
	proto.getListeners = function getListeners(evt) {
		var events = this._getEvents();
		var response;
		var key;

		// Return a concatenated array of all matching events if
		// the selector is a regular expression.
		if (evt instanceof RegExp) {
			response = {};
			for (key in events) {
				if (events.hasOwnProperty(key) && evt.test(key)) {
					response[key] = events[key];
				}
			}
		} else {
			response = events[evt] || (events[evt] = []);
		}

		return response;
	};

	/**
	 * Takes a list of listener objects and flattens it into a list of listener functions.
	 *
	 * @param {Object[]} listeners Raw listener objects.
	 * @return {Function[]} Just the listener functions.
	 */
	proto.flattenListeners = function flattenListeners(listeners) {
		var flatListeners = [];
		var i;

		for (i = 0; i < listeners.length; i += 1) {
			flatListeners.push(listeners[i].listener);
		}

		return flatListeners;
	};

	/**
	 * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
	 *
	 * @param {String|RegExp} evt Name of the event to return the listeners from.
	 * @return {Object} All listener functions for an event in an object.
	 */
	proto.getListenersAsObject = function getListenersAsObject(evt) {
		var listeners = this.getListeners(evt);
		var response;

		if (listeners instanceof Array) {
			response = {};
			response[evt] = listeners;
		}

		return response || listeners;
	};

	function isValidListener(listener) {
		if (typeof listener === 'function' || listener instanceof RegExp) {
			return true;
		} else if (listener && typeof listener === 'object') {
			return isValidListener(listener.listener);
		} else {
			return false;
		}
	}

	/**
	 * Adds a listener function to the specified event.
	 * The listener will not be added if it is a duplicate.
	 * If the listener returns true then it will be removed after it is called.
	 * If you pass a regular expression as the event name then the listener will be added to all events that match it.
	 *
	 * @param {String|RegExp} evt Name of the event to attach the listener to.
	 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.addListener = function addListener(evt, listener) {
		if (!isValidListener(listener)) {
			throw new TypeError('listener must be a function');
		}

		var listeners = this.getListenersAsObject(evt);
		var listenerIsWrapped = typeof listener === 'object';
		var key;

		for (key in listeners) {
			if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
				listeners[key].push(listenerIsWrapped ? listener : {
					listener: listener,
					once: false
				});
			}
		}

		return this;
	};

	/**
	 * Alias of addListener
	 */
	proto.on = alias('addListener');

	/**
	 * Semi-alias of addListener. It will add a listener that will be
	 * automatically removed after its first execution.
	 *
	 * @param {String|RegExp} evt Name of the event to attach the listener to.
	 * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.addOnceListener = function addOnceListener(evt, listener) {
		return this.addListener(evt, {
			listener: listener,
			once: true
		});
	};

	/**
	 * Alias of addOnceListener.
	 */
	proto.once = alias('addOnceListener');

	/**
	 * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
	 * You need to tell it what event names should be matched by a regex.
	 *
	 * @param {String} evt Name of the event to create.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.defineEvent = function defineEvent(evt) {
		this.getListeners(evt);
		return this;
	};

	/**
	 * Uses defineEvent to define multiple events.
	 *
	 * @param {String[]} evts An array of event names to define.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.defineEvents = function defineEvents(evts) {
		for (var i = 0; i < evts.length; i += 1) {
			this.defineEvent(evts[i]);
		}
		return this;
	};

	/**
	 * Removes a listener function from the specified event.
	 * When passed a regular expression as the event name, it will remove the listener from all events that match it.
	 *
	 * @param {String|RegExp} evt Name of the event to remove the listener from.
	 * @param {Function} listener Method to remove from the event.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.removeListener = function removeListener(evt, listener) {
		var listeners = this.getListenersAsObject(evt);
		var index;
		var key;

		for (key in listeners) {
			if (listeners.hasOwnProperty(key)) {
				index = indexOfListener(listeners[key], listener);

				if (index !== -1) {
					listeners[key].splice(index, 1);
				}
			}
		}

		return this;
	};

	/**
	 * Alias of removeListener
	 */
	proto.off = alias('removeListener');

	/**
	 * Adds listeners in bulk using the manipulateListeners method.
	 * If you pass an object as the first argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
	 * You can also pass it a regular expression to add the array of listeners to all events that match it.
	 * Yeah, this function does quite a bit. That's probably a bad thing.
	 *
	 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
	 * @param {Function[]} [listeners] An optional array of listener functions to add.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.addListeners = function addListeners(evt, listeners) {
		// Pass through to manipulateListeners
		return this.manipulateListeners(false, evt, listeners);
	};

	/**
	 * Removes listeners in bulk using the manipulateListeners method.
	 * If you pass an object as the first argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
	 * You can also pass it an event name and an array of listeners to be removed.
	 * You can also pass it a regular expression to remove the listeners from all events that match it.
	 *
	 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
	 * @param {Function[]} [listeners] An optional array of listener functions to remove.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.removeListeners = function removeListeners(evt, listeners) {
		// Pass through to manipulateListeners
		return this.manipulateListeners(true, evt, listeners);
	};

	/**
	 * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
	 * The first argument will determine if the listeners are removed (true) or added (false).
	 * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
	 * You can also pass it an event name and an array of listeners to be added/removed.
	 * You can also pass it a regular expression to manipulate the listeners of all events that match it.
	 *
	 * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
	 * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
	 * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
		var i;
		var value;
		var single = remove ? this.removeListener : this.addListener;
		var multiple = remove ? this.removeListeners : this.addListeners;

		// If evt is an object then pass each of its properties to this method
		if (typeof evt === 'object' && !(evt instanceof RegExp)) {
			for (i in evt) {
				if (evt.hasOwnProperty(i) && (value = evt[i])) {
					// Pass the single listener straight through to the singular method
					if (typeof value === 'function') {
						single.call(this, i, value);
					} else {
						// Otherwise pass back to the multiple function
						multiple.call(this, i, value);
					}
				}
			}
		} else {
			// So evt must be a string
			// And listeners must be an array of listeners
			// Loop over it and pass each one to the multiple method
			i = listeners.length;
			while (i--) {
				single.call(this, evt, listeners[i]);
			}
		}

		return this;
	};

	/**
	 * Removes all listeners from a specified event.
	 * If you do not specify an event then all listeners will be removed.
	 * That means every event will be emptied.
	 * You can also pass a regex to remove all events that match it.
	 *
	 * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.removeEvent = function removeEvent(evt) {
		var type = typeof evt;
		var events = this._getEvents();
		var key;

		// Remove different things depending on the state of evt
		if (type === 'string') {
			// Remove all listeners for the specified event
			delete events[evt];
		} else if (evt instanceof RegExp) {
			// Remove all events matching the regex.
			for (key in events) {
				if (events.hasOwnProperty(key) && evt.test(key)) {
					delete events[key];
				}
			}
		} else {
			// Remove all listeners in all events
			delete this._events;
		}

		return this;
	};

	/**
	 * Alias of removeEvent.
	 *
	 * Added to mirror the node API.
	 */
	proto.removeAllListeners = alias('removeEvent');

	/**
	 * Emits an event of your choice.
	 * When emitted, every listener attached to that event will be executed.
	 * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
	 * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
	 * So they will not arrive within the array on the other side, they will be separate.
	 * You can also pass a regular expression to emit to all events that match it.
	 *
	 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
	 * @param {Array} [args] Optional array of arguments to be passed to each listener.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.emitEvent = function emitEvent(evt, args) {
		var listenersMap = this.getListenersAsObject(evt);
		var listeners;
		var listener;
		var i;
		var key;
		var response;

		for (key in listenersMap) {
			if (listenersMap.hasOwnProperty(key)) {
				listeners = listenersMap[key].slice(0);

				for (i = 0; i < listeners.length; i++) {
					// If the listener returns true then it shall be removed from the event
					// The function is executed either with a basic call or an apply if there is an args array
					listener = listeners[i];

					if (listener.once === true) {
						this.removeListener(evt, listener.listener);
					}

					response = listener.listener.apply(this, args || []);

					if (response === this._getOnceReturnValue()) {
						this.removeListener(evt, listener.listener);
					}
				}
			}
		}

		return this;
	};

	/**
	 * Alias of emitEvent
	 */
	proto.trigger = alias('emitEvent');

	/**
	 * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
	 * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
	 *
	 * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
	 * @param {...*} Optional additional arguments to be passed to each listener.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.emit = function emit(evt) {
		var args = Array.prototype.slice.call(arguments, 1);
		return this.emitEvent(evt, args);
	};

	/**
	 * Sets the current value to check against when executing listeners. If a
	 * listeners return value matches the one set here then it will be removed
	 * after execution. This value defaults to true.
	 *
	 * @param {*} value The new value to check for when executing listeners.
	 * @return {Object} Current instance of EventEmitter for chaining.
	 */
	proto.setOnceReturnValue = function setOnceReturnValue(value) {
		this._onceReturnValue = value;
		return this;
	};

	/**
	 * Fetches the current value to check against when executing listeners. If
	 * the listeners return value matches this one then it should be removed
	 * automatically. It will return true by default.
	 *
	 * @return {*|Boolean} The current value to check for or the default, true.
	 * @api private
	 */
	proto._getOnceReturnValue = function _getOnceReturnValue() {
		if (this.hasOwnProperty('_onceReturnValue')) {
			return this._onceReturnValue;
		} else {
			return true;
		}
	};

	/**
	 * Fetches the events object and creates one if required.
	 *
	 * @return {Object} The events storage object.
	 * @api private
	 */
	proto._getEvents = function _getEvents() {
		return this._events || (this._events = {});
	};

	/**
	 * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
	 *
	 * @return {Function} Non conflicting EventEmitter class.
	 */
	EventEmitter.noConflict = function noConflict() {
		exports.EventEmitter = originalGlobalValue;
		return EventEmitter;
	};

	// Expose the class either via AMD, CommonJS or the global object
	if (typeof module === 'object' && module.exports) {
		module.exports = EventEmitter;
	} else {
		exports.EventEmitter = EventEmitter;
	}
}(this || {}));

/* globals EventEmitter */

(function(w) {
	w.RocketChat = w.RocketChat || { _: [] };
	var config = {};
	var widget;
	var iframe;
	var hookQueue = [];
	var ready = false;

	var widgetWidth = '320px';
	var widgetHeightOpened = '350px';
	var widgetHeightClosed = '30px';

	var validCallbacks = [
		'chat-maximized',
		'chat-minimized',
		'chat-started',
		'chat-ended',
		'pre-chat-form-submit',
		'offline-form-submit'
	];
	var callbacks = new EventEmitter();

	var registerCallback = function(eventName, fn) {
		if (validCallbacks.indexOf(eventName) === -1) {
			return false;
		}

		return callbacks.on(eventName, fn);
	};

	var emitCallback = function(eventName, data) {
		if (typeof data !== 'undefined') {
			callbacks.emit(eventName, data);
		} else {
			callbacks.emit(eventName);
		}
	};

	// hooks
	var callHook = function(action, params) {
		if (!ready) {
			return hookQueue.push(arguments);
		}
		var data = {
			src: 'rocketchat',
			fn: action,
			args: params
		};
		iframe.contentWindow.postMessage(data, '*');
	};

	var closeWidget = function() {
		if (widget.dataset.state === 'closed') {
			return;
		}
		widget.dataset.state = 'closed';
		widget.style.height = widgetHeightClosed;
		callHook('widgetClosed');

		emitCallback('chat-minimized');
	};

	var openWidget = function() {
		if (widget.dataset.state === 'opened') {
			return;
		}
		widget.dataset.state = 'opened';
		widget.style.height = widgetHeightOpened;
		callHook('widgetOpened');
		document.querySelector('.rocketchat-widget iframe').focus();

		emitCallback('chat-maximized');
	};

	var api = {
		ready: function() {
			ready = true;
			if (hookQueue.length > 0) {
				hookQueue.forEach(function(hookParams) {
					callHook.apply(this, hookParams);
				});
				hookQueue = [];
			}
		},
		toggleWindow: function(/*forceClose*/) {
			if (widget.dataset.state === 'closed') {
				openWidget();
			} else {
				closeWidget();
			}
		},
		openPopout: function() {
			closeWidget();
			var popup = window.open(config.url + '?mode=popout', 'livechat-popout', 'width=400, height=450, toolbars=no');
			popup.focus();
		},
		openWidget: function() {
			openWidget();
		},
		removeWidget: function() {
			document.getElementsByTagName('body')[0].removeChild(widget);
		},
		callback: function(eventName, data) {
			emitCallback(eventName, data);
		}
	};

	var pageVisited = function(change) {
		callHook('pageVisited', {
			change: change,
			location: JSON.parse(JSON.stringify(document.location)),
			title: document.title
		});
	};

	var setCustomField = function(key, value, overwrite) {
		if (typeof overwrite === 'undefined') {
			overwrite = true;
		}
		callHook('setCustomField', [key, value, overwrite]);
	};

	var setTheme = function(theme) {
		callHook('setTheme', theme);
	};

	var setDepartment = function(department) {
		callHook('setDepartment', department);
	};

	var clearDepartment = function() {
		callHook('clearDepartment');
	};

	var currentPage = {
		href: null,
		title: null
	};
	var trackNavigation = function() {
		setInterval(function() {
			if (document.location.href !== currentPage.href) {
				pageVisited('url');
				currentPage.href = document.location.href;
			}
			if (document.title !== currentPage.title) {
				pageVisited('title');
				currentPage.title = document.title;
			}
		}, 800);
	};

	var init = function(url) {
		if (!url) {
			return;
		}

		config.url = url;

		var chatWidget = document.createElement('div');
		chatWidget.dataset.state = 'closed';
		chatWidget.className = 'rocketchat-widget';
		chatWidget.innerHTML = '<div class="rocketchat-container" style="width:100%;height:100%">' +
			'<iframe id="rocketchat-iframe" src="' + url + '" style="width:100%;height:100%;border:none;background-color:transparent" allowTransparency="true"></iframe> ' +
			'</div><div class="rocketchat-overlay"></div>';

		chatWidget.style.position = 'fixed';
		chatWidget.style.width = widgetWidth;
		chatWidget.style.height = widgetHeightClosed;
		chatWidget.style.borderTopLeftRadius = '5px';
		chatWidget.style.borderTopRightRadius = '5px';
		chatWidget.style.bottom = '0';
		chatWidget.style.right = '50px';
		chatWidget.style.zIndex = '12345';

		document.getElementsByTagName('body')[0].appendChild(chatWidget);

		widget = document.querySelector('.rocketchat-widget');
		iframe = document.getElementById('rocketchat-iframe');

		w.addEventListener('message', function(msg) {
			if (typeof msg.data === 'object' && msg.data.src !== undefined && msg.data.src === 'rocketchat') {
				if (api[msg.data.fn] !== undefined && typeof api[msg.data.fn] === 'function') {
					var args = [].concat(msg.data.args || []);
					api[msg.data.fn].apply(null, args);
				}
			}
		}, false);

		var mediaqueryresponse = function(mql) {
			if (mql.matches) {
				chatWidget.style.left = '0';
				chatWidget.style.right = '0';
				chatWidget.style.width = '100%';
			} else {
				chatWidget.style.left = 'auto';
				chatWidget.style.right = '50px';
				chatWidget.style.width = widgetWidth;
			}
		};

		var mql = window.matchMedia('screen and (max-device-width: 480px) and (orientation: portrait)');
		mediaqueryresponse(mql);
		mql.addListener(mediaqueryresponse);

		// track user navigation
		trackNavigation();
	};

	if (typeof w.initRocket !== 'undefined') {
		console.warn('initRocket is now deprecated. Please update the livechat code.');
		init(w.initRocket[0]);
	}

	if (typeof w.RocketChat.url !== 'undefined') {
		init(w.RocketChat.url);
	}

	var queue = w.RocketChat._;

	w.RocketChat = w.RocketChat._.push = function(c) {
		c.call(w.RocketChat.livechat);
	};

	// exports
	w.RocketChat.livechat = {
		// methods
		pageVisited: pageVisited,
		setCustomField: setCustomField,
		setTheme: setTheme,
		setDepartment: setDepartment,
		clearDepartment: clearDepartment,

		// callbacks
		onChatMaximized: function(fn) { registerCallback('chat-maximized', fn); },
		onChatMinimized: function(fn) { registerCallback('chat-minimized', fn); },
		onChatStarted: function(fn) { registerCallback('chat-started', fn); },
		onChatEnded: function(fn) { registerCallback('chat-ended', fn); },
		onPrechatFormSubmit: function(fn) { registerCallback('pre-chat-form-submit', fn); },
		onOfflineFormSubmit: function(fn) { registerCallback('offline-form-submit', fn); }
	};

	// proccess queue
	queue.forEach(function(c) {
		c.call(w.RocketChat.livechat);
	});
}(window));


<template name="oauthApp">

		{{#if hasPermission}}
			 {{_ "Back_to_applications"}}

							{{_ "Active"}}

								<input class="input-monitor" type="radio" name="active" value="1" checked="{{$eq data.active true}}" /> {{_ "True"}}
								<input class="input-monitor" type="radio" name="active" value="0" checked="{{$eq data.active false}}" /> {{_ "False"}}

							{{_ "Application_Name"}}

								<input type="text" name="name" value="{{data.name}}" />

{{_ "Give_the_application_a_name_This_will_be_seen_by_your_users"}}

							{{_ "Redirect_URI"}}

								<input type="text" name="redirectUri" value="{{data.redirectUri}}" />

{{_ "After_OAuth2_authentication_users_will_be_redirected_to_this_URL"}}

						{{#if data.clientId}}

								{{_ "Client_ID"}}

									<input type="text" name="clientId" value="{{data.clientId}}" readonly="readonly" />

<button class="clipboard" data-clipboard-target="[name=clientId]">{{_ "COPY_TO_CLIPBOARD"}}</button>

								{{_ "Client_Secret"}}

									<input type="text" name="clientSecret" value="{{data.clientSecret}}" readonly="readonly" />

<button class="clipboard" data-clipboard-target="[name=clientSecret]">{{_ "COPY_TO_CLIPBOARD"}}</button>

								{{_ "Authorization_URL"}}

									<input type="text" name="authorization_url" value="{{data.authorization_url}}" readonly="readonly" />

<button class="clipboard" data-clipboard-target="[name=authorization_url]">{{_ "COPY_TO_CLIPBOARD"}}</button>

								{{_ "Access_Token_URL"}}

									<input type="text" name="access_token_url" value="{{data.access_token_url}}" readonly="readonly" />

<button class="clipboard" data-clipboard-target="[name=access_token_url]">{{_ "COPY_TO_CLIPBOARD"}}</button>

						{{/if}}

					{{#if data.clientId}}
						<button class="button danger delete">{{_ "Delete"}}</button>
					{{/if}}
					<button class="button primary save">{{_ "Save_changes"}}</button>

		{{else}}
			{{_ "Not_authorized"}}
		{{/if}}

</template>


keep keep keep replace replace replace keep keep keep keep

return RocketChat.authz.hasAtLeastOnePermission('delete-message', @rid) or RocketChat.settings.get('Message_AllowDeleting') and @userId is Meteor.userId()

roomFiles = new Mongo.Collection 'room_files'

Template.uploadedFilesList.helpers
	files: ->
		return roomFiles.find({ rid: @rid }, { sort: { uploadedAt: -1 } }).fetch()

	hasFiles: ->
		return roomFiles.find({ rid: @rid }).count() > 0

	hasMore: ->
		return Template.instance().hasMore.get()

	getFileIcon: (type) ->
		if type.match(/^image\/.+$/)
			return 'icon-picture'

		return 'icon-docs'

	customClassForFileType: ->
		if @type.match(/^image\/.+$/)
			return 'room-files-swipebox'

	escapedName: ->
		return s.escapeHTML @name

	canDelete: ->
		msg = ChatMessage.findOne { file: { _id: @_id } }
		if msg
			return RocketChat.authz.hasAtLeastOnePermission('delete-message', msg.rid) or RocketChat.settings.get('Message_AllowDeleting') and msg.u?._id is Meteor.userId()

Template.uploadedFilesList.events
	'click .room-file-item': (e, t) ->
		if $(e.currentTarget).siblings('.icon-picture').length
			e.preventDefault()

	'click .icon-trash': (e, t) ->
		self = this
		swal {
			title: TAPi18n.__('Are_you_sure')
			text: TAPi18n.__('You_will_not_be_able_to_recover_file')
			type: 'warning'
			showCancelButton: true
			confirmButtonColor: '#DD6B55'
			confirmButtonText: TAPi18n.__('Yes_delete_it')
			cancelButtonText: TAPi18n.__('Cancel')
			closeOnConfirm: false
			html: false
		}, ->
			swal
				title: TAPi18n.__('Deleted')
				text: TAPi18n.__('Your_file_has_been_deleted')
				type: 'success'
				timer: 1000
				showConfirmButton: false

				msg = ChatMessage.findOne { file: { _id: self._id } }
				RocketChat.models.Uploads.remove self._id, () ->
					chatMessages[Session.get('openedRoom')].deleteMsg(msg);

	'scroll .content': _.throttle (e, t) ->
		if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight
			t.limit.set(t.limit.get() + 50)
	, 200

Template.uploadedFilesList.onCreated ->
	rid = Template.currentData().rid
	@hasMore = new ReactiveVar true
	@limit = new ReactiveVar 50
	@autorun =>
		@subscribe 'roomFiles', rid, @limit.get(), =>
			if roomFiles.find({ rid: rid }).fetch().length < @limit.get()
				@hasMore.set false

Template.uploadedFilesList.onRendered ->
	$('.room-files-swipebox').swipebox()


Heeft u een moment om een korte enquête over deze chat te beantwoorden

Beoordeel elke vraag naar mate uw tevredenheid, 1 betekent dat u helemaal ontevreden  bent en 5 betekent volledig tevreden.

We zijn offline. Excuses voor het ongemak.


//! moment.js locale configuration
//! locale : slovak (sk)
//! author : Martin Minka : https://github.com/k2s
//! based on work of petrbela : https://github.com/petrbela

(function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('../moment')) :
   typeof define === 'function' && define.amd ? define(['moment'], factory) :
   factory(global.moment)
}(this, function (moment) { 'use strict';

    var months = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_'),
        monthsShort = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_');
    function plural(n) {
        return (n > 1) && (n < 5);
    }
    function translate(number, withoutSuffix, key, isFuture) {
        var result = number + ' ';
        switch (key) {
        case 's':  // a few seconds / in a few seconds / a few seconds ago
            return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami';
        case 'm':  // a minute / in a minute / a minute ago
            return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou');
        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago
            if (withoutSuffix || isFuture) {
                return result + (plural(number) ? 'minúty' : 'minút');
            } else {
                return result + 'minútami';
            }
            break;
        case 'h':  // an hour / in an hour / an hour ago
            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');
        case 'hh': // 9 hours / in 9 hours / 9 hours ago
            if (withoutSuffix || isFuture) {
                return result + (plural(number) ? 'hodiny' : 'hodín');
            } else {
                return result + 'hodinami';
            }
            break;
        case 'd':  // a day / in a day / a day ago
            return (withoutSuffix || isFuture) ? 'deň' : 'dňom';
        case 'dd': // 9 days / in 9 days / 9 days ago
            if (withoutSuffix || isFuture) {
                return result + (plural(number) ? 'dni' : 'dní');
            } else {
                return result + 'dňami';
            }
            break;
        case 'M':  // a month / in a month / a month ago
            return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom';
        case 'MM': // 9 months / in 9 months / 9 months ago
            if (withoutSuffix || isFuture) {
                return result + (plural(number) ? 'mesiace' : 'mesiacov');
            } else {
                return result + 'mesiacmi';
            }
            break;
        case 'y':  // a year / in a year / a year ago
            return (withoutSuffix || isFuture) ? 'rok' : 'rokom';
        case 'yy': // 9 years / in 9 years / 9 years ago
            if (withoutSuffix || isFuture) {
                return result + (plural(number) ? 'roky' : 'rokov');
            } else {
                return result + 'rokmi';
            }
            break;
        }
    }

    var sk = moment.defineLocale('sk', {
        months : months,
        monthsShort : monthsShort,
        monthsParse : (function (months, monthsShort) {
            var i, _monthsParse = [];
            for (i = 0; i < 12; i++) {
                // use custom parser to solve problem with July (červenec)
                _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');
            }
            return _monthsParse;
        }(months, monthsShort)),
        weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'),
        weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'),
        weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),
        longDateFormat : {
            LT: 'H:mm',
            LTS : 'LT:ss',
            L : 'DD.MM.YYYY',
            LL : 'D. MMMM YYYY',
            LLL : 'D. MMMM YYYY LT',
            LLLL : 'dddd D. MMMM YYYY LT'
        },
        calendar : {
            sameDay: '[dnes o] LT',
            nextDay: '[zajtra o] LT',
            nextWeek: function () {
                switch (this.day()) {
                case 0:
                    return '[v nedeľu o] LT';
                case 1:
                case 2:
                    return '[v] dddd [o] LT';
                case 3:
                    return '[v stredu o] LT';
                case 4:
                    return '[vo štvrtok o] LT';
                case 5:
                    return '[v piatok o] LT';
                case 6:
                    return '[v sobotu o] LT';
                }
            },
            lastDay: '[včera o] LT',
            lastWeek: function () {
                switch (this.day()) {
                case 0:
                    return '[minulú nedeľu o] LT';
                case 1:
                case 2:
                    return '[minulý] dddd [o] LT';
                case 3:
                    return '[minulú stredu o] LT';
                case 4:
                case 5:
                    return '[minulý] dddd [o] LT';
                case 6:
                    return '[minulú sobotu o] LT';
                }
            },
            sameElse: 'L'
        },
        relativeTime : {
            future : 'za %s',
            past : 'pred %s',
            s : translate,
            m : translate,
            mm : translate,
            h : translate,
            hh : translate,
            d : translate,
            dd : translate,
            M : translate,
            MM : translate,
            y : translate,
            yy : translate
        },
        ordinalParse: /\d{1,2}\./,
        ordinal : '%d.',
        week : {
            dow : 1, // Monday is the first day of the week.
            doy : 4  // The week that contains Jan 4th is the first week of the year.
        }
    });

    return sk;

}));


msg = ChatMessage.findOne { file: { _id: self._id } }

RocketChat.models.Uploads.remove self._id, () ->

# Check if the upload message for this file is currently loaded


Meteor.methods
	removeRoomOwner: (rid, userId) ->
		unless Meteor.userId()
			throw new Meteor.Error 'invalid-user', '[methods] removeRoomOwner -> Invalid user'

		check rid, String
		check userId, String

		unless RocketChat.authz.hasPermission Meteor.userId(), 'set-owner', rid
			throw new Meteor.Error 403, 'Not allowed'

		subscription = RocketChat.models.Subscriptions.findOneByRoomIdAndUserId rid, userId
		unless subscription?
			throw new Meteor.Error 'invalid-subscription', '[methods] removeRoomOwner -> Invalid Subscription'

		RocketChat.models.Subscriptions.removeRoleById(subscription._id, 'owner')

		user = RocketChat.models.Users.findOneById userId
		fromUser = RocketChat.models.Users.findOneById Meteor.userId()
		RocketChat.models.Messages.createOwnerRemovedWithRoomIdAndUser rid, user,
			u:
				_id: fromUser._id
				username: fromUser.username

		return true


###
# Highlight is a named function that will highlight ``` messages
# @param {Object} message - The message object
###

class Highlight

	constructor: (message) ->

		if s.trim message.html
			message.tokens ?= []

			# Count occurencies of ```
			count = (message.html.match(/```/g) || []).length

			if count

				# Check if we need to add a final ```
				if (count % 2 > 0)
					message.html = message.html + "\n```"
					message.msg = message.msg + "\n```"

				# Separate text in code blocks and non code blocks
				msgParts = message.html.split(/(```\w*[\n\ ]?[\s\S]*?```+?)/)

				for part, index in msgParts
					# Verify if this part is code
					codeMatch = part.match(/```(\w*)[\n\ ]?([\s\S]*?)```+?/)
					if codeMatch?
						# Process highlight if this part is code
						singleLine = codeMatch[0].indexOf('\n') is -1

						if singleLine
							lang = ''
							code = _.unescapeHTML codeMatch[1] + ' ' + codeMatch[2]
						else
							lang = codeMatch[1]
							code = _.unescapeHTML codeMatch[2]

						if lang not in hljs.listLanguages()
							result = hljs.highlightAuto code
						else
							result = hljs.highlight lang, code

						token = "$#{Random.id()}$"

						message.tokens.push
							highlight: true
							token: token
							text: "
```<br></span>" + result.value + "<span class='copyonly'><br>```
"

						msgParts[index] = token
					else
						msgParts[index] = part

				# Re-mount message
				message.html = msgParts.join('')

		return message

RocketChat.callbacks.add 'renderMessage', Highlight, RocketChat.callbacks.priority.HIGH
RocketChat.Highlight = true


###
# Me is a named function that will replace /me commands
# @param {Object} message - The message object
###

class Me
	constructor: (command, params, item) ->
		if(command == "me")
			if _.trim params
				currentUser = Meteor.user()
				msg = item
				msg.msg = '_' + params + '_'
				Meteor.call 'sendMessage', msg

RocketChat.slashCommands.add 'me', Me


if e.target.scrollTop >= e.target.scrollHeight - e.target.clientHeight

Meteor.call 'deleteFileMessage', self._id, (error, result) ->

Meteor.methods
	deleteMessage: (message) ->
		if not Meteor.userId()
			throw new Meteor.Error('invalid-user', "[methods] deleteMessage -> Invalid user")

		originalMessage = RocketChat.models.Messages.findOneById message._id, {fields: {u: 1, rid: 1, file: 1}}
		if not originalMessage?
			throw new Meteor.Error 'message-deleting-not-allowed', "[methods] deleteMessage -> Message with id [#{message._id} dos not exists]"

		hasPermission = RocketChat.authz.hasPermission(Meteor.userId(), 'delete-message', originalMessage.rid)
		deleteAllowed = RocketChat.settings.get 'Message_AllowDeleting'

		deleteOwn = originalMessage?.u?._id is Meteor.userId()

		unless hasPermission or (deleteAllowed and deleteOwn)
			throw new Meteor.Error 'message-deleting-not-allowed', "[methods] deleteMessage -> Message deleting not allowed"

		keepHistory = RocketChat.settings.get 'Message_KeepHistory'
		showDeletedStatus = RocketChat.settings.get 'Message_ShowDeletedStatus'

		if keepHistory
			if showDeletedStatus
				RocketChat.models.Messages.cloneAndSaveAsHistoryById originalMessage._id
			else
				RocketChat.models.Messages.setHiddenById originalMessage._id, true

			if originalMessage.file?._id?
				RocketChat.models.Uploads.update originalMessage.file._id, {$set: {_hidden: true}}

		else
			if not showDeletedStatus
				RocketChat.models.Messages.removeById originalMessage._id

			if originalMessage.file?._id?
				RocketChat.models.Uploads.remove originalMessage.file._id
				Meteor.fileStore.delete originalMessage.file._id

		if showDeletedStatus
			RocketChat.models.Messages.setAsDeletedById originalMessage._id
		else
			RocketChat.Notifications.notifyRoom originalMessage.rid, 'deleteMessage', { _id: originalMessage._id }


describe 'rocketchat:markdown Client', ->

	it 'should exist', ->
	 	expect(RocketChat.Markdown).toBeDefined()


#!/bin/bash
export METEOR_SETTINGS=$(cat settings.json)
meteor add rocketchat:hubot meteorhacks:kadira
meteor build --server https://demo.rocket.chat --directory /var/www/rocket.chat
cd /var/www/rocket.chat/bundle/programs/server
npm install
cd /var/www/rocket.chat/current
pm2 startOrRestart /var/www/rocket.chat/current/pm2.json


RocketChat.Notifications.notifyRoom originalMessage.rid, 'deleteMessage', { _id: originalMessage._id }

RocketChat.Notifications.notifyRoom originalMessage.rid, 'deleteMessage', {_id: originalMessage._id}

Meteor.call 'deleteMessage', RocketChat.models.Messages.findOne { file: { _id: fileID } }


Meteor.methods
	createPrivateGroup: (name, members) ->
		if not Meteor.userId()
			throw new Meteor.Error 'invalid-user', "[methods] createPrivateGroup -> Invalid user"

		unless RocketChat.authz.hasPermission(Meteor.userId(), 'create-p')
			throw new Meteor.Error 'not-authorized', '[methods] createPrivateGroup -> Not authorized'

		try
			nameValidation = new RegExp '^' + RocketChat.settings.get('UTF8_Names_Validation') + '$'
		catch
			nameValidation = new RegExp '^[0-9a-zA-Z-_.]+$'

		if not nameValidation.test name
			throw new Meteor.Error 'name-invalid'

		now = new Date()

		me = Meteor.user()

		members.push me.username

		# name = s.slugify name

		# avoid duplicate names
		if RocketChat.models.Rooms.findOneByName name
			if RocketChat.models.Rooms.findOneByName(name).archived
				throw new Meteor.Error 'archived-duplicate-name'
			else
				throw new Meteor.Error 'duplicate-name'

		# create new room
		room = RocketChat.models.Rooms.createWithTypeNameUserAndUsernames 'p', name, me, members,
			ts: now

		# set creator as group moderator.  permission limited to group by scoping to rid
		RocketChat.authz.addUserRoles(Meteor.userId(), ['moderator','owner'], room._id)

		for username in members
			member = RocketChat.models.Users.findOneByUsername(username, { fields: { username: 1 }})
			if not member?
				continue

			extra = {}

			if username is me.username
				extra.ls = now
			else
				extra.alert = true

			RocketChat.models.Subscriptions.createWithRoomAndUser room, member, extra

		return {
			rid: room._id
		}


limit: limit
sort:
uploadedAt: -1
fields:
_id: 1
rid: 1
name: 1
type: 1
url: 1

keep keep keep keep add keep keep keep keep


**/bin/**
**/build/*
**/node_modules/*
**/tmp/*
/private/certs/*
*.bak
*.iml
*.ipr
*.iws
*.launch
*.log
*.pydevproject
*.sublime-project
*.swp
*.tmp
*.tokens
*.un~
*~
*~.nib
.*.sw[a-z]
.\#*
._*
.buildpath
.classpath
.clover
.cproject
.DS_Store
.elasticbeanstalk
.elc
.emacs.desktop
.emacs.desktop.lock
.env
.externalToolBuilders
.idea
.loadpath
.map
.metadata
.meteor/local
.meteor/meteorite
.mule
.pmd
.project
.sass-cache
.settings
.Spotlight-V100
.Trashes
.wtpmodules
\#*\#
Desktop.ini
ehthumbs.db
example.css
jrat.output
jrat.xml
local.properties
meteor-vulcanize
nb-configuration.xml
nbactions.xml
nbproject
profiles.xml
Session.vim
smart.lock
temp_*
Thumbs.db
thumbs.db
tramp
ecosystem.json
pm2.json
settings.json
build.sh


ئىسىم

توردىكى سىناق نۇسخىسىنى ئىشلىتىپ بېقىش

توردىكى سىناق نۇسخىسىنى ئىشلىتىپ بېقىش

قوللانچى قوشۇش

ھەممە قاناللار

كىرىش بېتىگە قايتىش

باش رەسىم ئالماشتۇرۇش

پاراڭخانىلار

ياسىلىۋاتىدۇ

پارول جەزملەشتۈرۈش

مەخپىي گۇرۇپپا قوشۇش

ئۇدۇل ئۇچۇر يېزىش

تەھرىرلەنگەن

ئىلخەت ياكى ئەزا نامى

ئىلخەت جەزملەندى

ئەزا ئۇچۇرىڭىزنى كىرگۈزۈڭ

پارول ئۆزگەرتىلدى.

پارول ئۇنۇتتىڭىزمۇ

پاراڭخانىنى يوشۇرۇش

ئىككى قېتىم كىرگۈزگەن پارول بىردەك ئەمەس

كىرگۈزگەن ئىلخەت ئادرېسى توغرا ئەمەس

ئەزا نامىنى چوقۇم كىرگۈزۈڭ

پارولنى چوقۇم كىرگۈزۈڭ

%s مۇۋاپىق پاراڭخانا ئىسمى ئەمەسكەن,
 ھازىرچە لاتىنچە ھەرپ، سان ۋە ئاستى سىزىقنىلا قوللايدۇ.

كۆرۈنمەيدىغان

كۆرۈنمەيدىغان

جامائەتكە قوشۇلۇش

پاراڭخانىدىن چېكىنىش

تەۋسىيە يۈكلىنىۋاتىدۇ...

%s بىلەن كىرىش

ياكى بىۋاسىتە كىرىش

باشقا قاناللار

سىز ھېچ قايسى قانالغا تەۋە ئەمەسكەنسىز.

سىز تېخى ھېچقانداق پاراڭ باشلىماپسىز.

خۇرجۇنغا ھېچنېمە سالماپسىز.

سىزنىڭ تېخى مەخپىي گۇرۇپپىڭىز يوقكەن.

بۇ پاراڭخانىغا كىرىشكە ھوقۇقىڭىز يەتمەيدىكەن.

ھوقۇق يەتمىدى

تېپىلمىدى ياكى ھوقۇق يەتمىدى

بىخەتەرلىك كېلىشىمى

مەخپىي گۇرۇپپىلار

دەلىل كەلتۈرۈش

يېڭى ئاكونت تىزىملىتىش

ئېسىدە ساقلىسۇن

پارول يېڭىلاش

پاراڭخانا نامى __user_by__ تەرىپىدىن __room_name__ قىلىپ ئۆزگەرتىلدى

پاراڭخانا نامى مۇۋەپپەقىيەتلىك ئۆزگەرتىلدى

ھەممىنى كۆرۈش

توردىكىلەرنىلا كۆرۈش

باش رەسىم تاللاش

ھۆججەت تاللاش

تاللانغان قوللانچىلار

جەزملەشتۈرۈش ئىلخىتى ئەۋەتىش

__total__ ئەزانىڭ ئىچىدىكى <b>__total_online__</b> كۆرسىتىلدى

%s نەتىجە تېپىلدى

پاراڭ باشلاش

%s چوقۇم تولدۇرۇلىشى كېرەك.

ئىسمىڭىزنىڭ باشلانغان ھەرپلىرىنى ئىشلىتىڭ

ياندىكى تىزىملىك ئارقىلىق پاراڭخانا ۋە پاراڭلارنى تېپىڭ

%s باش رەسىمنى ئىشلىتىش

بۇ ئىسىمنى ئىشلىتىڭ

يۈكلەنگەن باش رەسىمنى ئىشلىتىش

__user_by__ يېڭىدىن __user_added__ دېگەن ئەزانى قوشتى.

قانالغا قوشۇلدى.

<em>__user_left__</em> پاراڭخانىدىن چېكىندى.

ئەزا سىستېمىدىن چېكىندى

__user_by__، __user_removed__ دېگەن ئەزانى ئۆچۈردى.

ئەزا نامى چوقۇم تولدۇرىلىشى كېرەك

ئەزا نامىڭىزنى باشقىلار پاراڭ ئارىلىقىدا @ قىلىش ئارقىلىق سىزنى پاراڭغا چاقىرىدۇ.

%s مۇۋاپىق ئەزا نامى ئەمەسكەن,
 ھازىرچە لاتىنچە ھەرپ، سان ۋە ئاستى سىزىقنىلا قوللايدۇ.

ئەزا تىزىملىتىش

<strong>%s</strong> دېگەن ئىسىمنى باشقىلار ئىشلىتىپ بوپتۇ :(

ھەممىنى كۆرۈش

ئەسسالامۇ-ئەلەيكۇم <em>%s</em>.

كەلگىنىزگە مەرھابا

ئىلخەتنى جەزملەشتۈرۈپ بولغاندىن كېيىن كىرەلەيسىز!

ئۆزىڭىزنىڭ ئوچۇق كودلۇق پاراڭلىشىش ھەل قىلىش ئۇسۇلى


super.update(mutations.concat([]));   // pass copy

import EventEmitter from 'eventemitter3';
import logger from './logger';

let debug = logger('quill:events');

class Emitter extends EventEmitter {
  constructor() {
    super();
    this.on('error', debug.error);
  }

  emit() {
    debug.log.apply(debug, arguments);
    super.emit.apply(this, arguments);
  }
}

Emitter.events = {
  READY             : 'ready',
  SCROLL_OPTIMIZE   : 'scroll-optimize',
  SCROLL_UPDATE     : 'scroll-update',
  SELECTION_CHANGE  : 'selection-change',
  TEXT_CHANGE       : 'text-change'
};
Emitter.sources = {
  API    : 'api',
  SILENT : 'silent',
  USER   : 'user'
};

export default Emitter;


activeColor = #06c
borderColor = #ccc
backgroundColor = #fff
inactiveColor = #444
shadowColor = #ddd
textColor = #444

@import './base'
@import './snow/*'

.ql-container.ql-snow
  a
    color: activeColor
  *
    box-sizing: border-box

  border: 1px solid borderColor


import Delta from 'rich-text/lib/delta';
import Editor from '../../core/editor';
import Emitter from '../../core/emitter';
import Selection from '../../core/selection';
import Scroll from '../../blots/scroll';
import Quill from '../../core/quill';
import equal from 'deep-equal';

let div = document.createElement('div');
div.id = 'test-container';
document.body.appendChild(div);

beforeEach(function() {
  jasmine.addMatchers({
    toEqualHTML: function() {
      return { compare: compareHTML }
    },
    toBeApproximately: function() {
      return { compare: compareApproximately }
    }
  });

  div.innerHTML = '

';
  this.container = div.firstChild;
  this.initialize = initialize.bind(this);
});

function compareApproximately(actual, expected, tolerance) {
  let pass = Math.abs(actual - expected) <= tolerance;
  return {
    pass: pass,
    message: `${actual} is ${(pass ? '' : 'not')} approximately ${expected}`
  };
}

function compareHTML(actual, expected, ignoreClassId) {
  let [div1, div2] = [actual, expected].map(function(html) {
    if (html instanceof HTMLElement) {
      html = html.innerHTML;
    }
    let div = document.createElement('div');
    div.innerHTML = html.replace(/\n\s*/g, '');
    return div;
  });
  let ignoredAttributes = ['width', 'height'];
  if (ignoreClassId) {
    ignoredAttributes = ignoredAttributes.concat(['class', 'id']);
  }
  let message = compareNodes(div1, div2, ignoredAttributes)
  if (message != null) {
    console.error(div1.innerHTML);
    console.error(div2.innerHTML);
    return { pass: false, message: message };
  } else {
    return { pass: true, message: 'HTMLs equal' };
  }
}

function compareNodes(node1, node2, ignoredAttributes = []) {
  let attr1, attr2, message, ref;
  if (node1.nodeType !== node2.nodeType) {
    return `Expected nodeType '${node1.nodeType}' to equal '${node2.nodeType}'`;
  }
  if (node1.nodeType === node1.ELEMENT_NODE) {
    if (node1.tagName !== node2.tagName) {
      return `Expected tagName '${node1.tagName}' to equal '${node2.tagName}'`;
    }
    let [attr1, attr2] = [node1, node2].map(function(node) {
      return [].reduce.call(node.attributes, function(attr, elem) {
        if (ignoredAttributes.indexOf(elem.name) < 0) {
          attr[elem.name] = elem.name === 'style' ? elem.value.trim() : elem.value;
        }
        return attr;
      }, {});
    });
    if (!equal(attr1, attr2)) {
      return `Expected attributes ${jasmine.pp(attr1)} to equal ${jasmine.pp(attr2)}`;
    }
    if (node1.childNodes.length !== node2.childNodes.length) {
      return `Expected node childNodes length '${node1.childNodes.length}' to equal '${node2.childNodes.length}'`;
    }
    if (node1.childNodes.length === 0) return null;
    let message = '';
    if ([].some.call(node1.childNodes, function(child1, i) {
      message = compareNodes(child1, node2.childNodes[i], ignoredAttributes);
      return message;
    })) {
      return message;
    }
  } else if (node1.data !== node2.data) {
    return `Expected node text '${node1.data}' to equal '${node2.data}'`;
  }
  return null;
}

function initialize(klass, html, container = this.container) {
  if (typeof html === 'object') {
    container.innerHTML = html.html;
  } else {
    container.innerHTML = html.replace(/\n\s*/g, '');
  }
  if (klass === HTMLElement) return container;
  if (klass === Quill) return new Quill(container);
  let emitter = new Emitter();
  let scroll = new Scroll(container, { emitter: emitter });
  if (klass === Scroll) return scroll;
  let editor = new Editor(scroll, emitter);
  if (klass === Editor) return editor;
  let selection = new Selection(scroll, emitter);
  if (klass === Selection) return selection;
  if (klass[0] === Editor && klass[1] === Selection) return [editor, selection];
}


keep keep keep keep keep replace replace replace replace replace keep keep keep keep keep

SCROLL_OPTIMIZE      : 'scroll-optimize',

SELECTION_CHANGE     : 'selection-change',

import Parchment from 'parchment';
import equal from 'deep-equal';
import BreakBlot from '../blots/break';
import Emitter from './emitter';
import logger from './logger';

let debug = logger('quill:selection');

class Range {
  constructor(index, length = 0) {
    this.index = index;
    this.length = length;
  }
}

class Selection {
  constructor(scroll, emitter) {
    this.emitter = emitter;
    this.scroll = scroll;
    this.root = this.scroll.domNode;
    this.cursor = Parchment.create('cursor', this);
    // savedRange is last non-null range
    this.lastRange = this.savedRange = new Range(0, 0);
    ['keyup', 'mouseup', 'touchend', 'touchleave'].forEach((eventName) => {
      this.root.addEventListener(eventName, () => {
        // When range used to be a selection and user click within the selection,
        // the range now being a cursor has not updated yet without setTimeout
        setTimeout(this.update.bind(this, Emitter.sources.USER), 1);
      });
    });
    this.emitter.on(Emitter.events.TEXT_CHANGE, (delta) => {
      if (delta.length() > 0) {
        this.update(Emitter.sources.SILENT);
      }
    });
    this.update(Emitter.sources.SILENT);
  }

  focus() {
    if (this.hasFocus()) return;
    this.root.focus();
    this.setRange(this.savedRange);
  }

  format(format, value) {
    this.scroll.update();
    let nativeRange = this.getNativeRange();
    if (nativeRange == null || !nativeRange.native.collapsed || Parchment.query(format, Parchment.Scope.BLOCK)) return;
    if (nativeRange.start.node !== this.cursor.textNode) {
      let blot = Parchment.find(nativeRange.start.node, false);
      if (blot == null) return;
      // TODO Give blot ability to not split
      if (blot instanceof Parchment.Leaf) {
        let after = blot.split(nativeRange.start.offset);
        blot.parent.insertBefore(this.cursor, after);
      } else {
        blot.insertBefore(this.cursor, nativeRange.start.node);  // Should never happen
      }
      this.cursor.attach();
    }
    this.cursor.format(format, value);
    this.scroll.optimize();
    this.setNativeRange(this.cursor.textNode, this.cursor.textNode.data.length);
    this.update();
  }

  getBounds(index, length = 0) {
    let bounds, node, [leaf, offset] = findLeaf(this.scroll, index);
    if (leaf == null) return null;
    [node, offset] = leaf.position(offset, true);
    let range = document.createRange();
    if (length > 0) {
      range.setStart(node, offset);
      [leaf, offset] = findLeaf(this.scroll, index + length);
      if (leaf == null) return null;
      [node, offset] = leaf.position(offset, true);
      range.setEnd(node, offset);
      bounds = range.getBoundingClientRect();
    } else {
      let side = 'left';
      if (node instanceof Text) {
        if (offset < node.data.length) {
          range.setStart(node, offset);
          range.setEnd(node, offset + 1);
        } else {
          range.setStart(node, offset - 1);
          range.setEnd(node, offset);
          side = 'right';
        }
        var rect = range.getBoundingClientRect();
      } else {
        if (leaf instanceof BreakBlot) {
          var rect = leaf.parent.domNode.getBoundingClientRect();
        } else {
          var rect = leaf.domNode.getBoundingClientRect();
        }
        if (offset > 0) side = 'right';
      }
      bounds = {
        height: rect.height,
        left: rect[side],
        width: 0,
        top: rect.top
      };
    }
    let containerBounds = this.root.parentNode.getBoundingClientRect();
    return {
      left: bounds.left - containerBounds.left,
      right: bounds.left + bounds.width - containerBounds.left,
      top: bounds.top - containerBounds.top,
      bottom: bounds.top + bounds.height - containerBounds.top,
      height: bounds.height,
      width: bounds.width
    };
  }

  getNativeRange() {
    let selection = document.getSelection();
    if (selection == null || selection.rangeCount <= 0) return null;
    let nativeRange = selection.getRangeAt(0);
    if (nativeRange == null) return null;
    if (!contains(this.root, nativeRange.startContainer) ||
        (!nativeRange.collapsed && !contains(this.root, nativeRange.endContainer))) {
      return null;
    }
    let range = {
      start: { node: nativeRange.startContainer, offset: nativeRange.startOffset },
      end: { node: nativeRange.endContainer, offset: nativeRange.endOffset },
      native: nativeRange
    };
    [range.start, range.end].forEach(function(position) {
      let node = position.node, offset = position.offset;
      while (!(node instanceof Text) && node.childNodes.length > 0) {
        if (node.childNodes.length > offset) {
          node = node.childNodes[offset];
          offset = 0;
        } else if (node.childNodes.length === offset) {
          node = node.lastChild;
          offset = node instanceof Text ? node.data.length : node.childNodes.length;
        } else {
          break;
        }
      }
      position.node = node, position.offset = offset;
    });
    return range;
  }

  getRange() {
    if (!this.hasFocus()) return [null, null];
    let range = this.getNativeRange();
    if (range == null) return [null, null];
    let positions = [[range.start.node, range.start.offset]];
    if (!range.native.collapsed) {
      positions.push([range.end.node, range.end.offset]);
    }
    let indexes = positions.map((position) => {
      let [node, offset] = position;
      let blot = Parchment.find(node, true);
      let index = blot.offset(this.scroll);
      if (offset === 0) {
        return index;
      } else if (blot instanceof Parchment.Container) {
        return index + blot.length();
      } else {
        return index + blot.index(node, offset);
      }
    });
    let start = Math.min(...indexes), end = Math.max(...indexes);
    return [new Range(start, end-start), range];
  }

  hasFocus() {
    return document.activeElement === this.root;
  }

  scrollIntoView(range = this.lastRange) {
    if (range == null) return;
    let bounds = this.getBounds(range.index, range.length);
    if (this.root.offsetHeight < bounds.bottom) {
      let [line, offset] = this.scroll.line(range.index + range.length);
      this.root.scrollTop = line.domNode.offsetTop + line.domNode.offsetHeight;
    } else if (bounds.top < 0) {
      let [line, offset] = this.scroll.line(range.index);
      this.root.scrollTop = line.domNode.offsetTop;
    }
  }

  setNativeRange(startNode, startOffset, endNode = startNode, endOffset = startOffset) {
    debug.info('setNativeRange', startNode, startOffset, endNode, endOffset);
    let selection = document.getSelection();
    if (selection == null) return;
    if (startNode != null) {
      if (!this.hasFocus()) this.root.focus();
      let nativeRange = this.getNativeRange();
      if (nativeRange == null ||
          startNode !== nativeRange.start.node || startOffset !== nativeRange.start.offset ||
          endNode !== nativeRange.end.node || endOffset !== nativeRange.end.offset) {
        let range = document.createRange();
        range.setStart(startNode, startOffset);
        range.setEnd(endNode, endOffset);
        selection.removeAllRanges();
        selection.addRange(range);
      }
    } else {
      selection.removeAllRanges();
      this.root.blur();
      document.body.focus();  // root.blur() not enough on IE11+Travis+SauceLabs (but not local VMs)
    }
  }

  setRange(range, source = Emitter.sources.API) {
    debug.info('setRange', range);
    if (range != null) {
      let indexes = range.collapsed ? [range.index] : [range.index, range.index + range.length];
      let args = [];
      indexes.forEach((index, i) => {
        let node, [leaf, offset] = findLeaf(this.scroll, index);
        [node, offset] = leaf.position(offset, i !== 0);
        args.push(node, offset);
      });
      this.setNativeRange(...args);
    } else {
      this.setNativeRange(null);
    }
    this.update(source);
  }

  update(source = Emitter.sources.USER) {
    let nativeRange, oldRange = this.lastRange;
    [this.lastRange, nativeRange] = this.getRange();
    if (this.lastRange != null) {
      this.savedRange = this.lastRange;
    }
    if (!equal(oldRange, this.lastRange)) {
      if (nativeRange != null && nativeRange.native.collapsed && nativeRange.start.node !== this.cursor.textNode) {
        this.cursor.restore();
      }
      if (source === Emitter.sources.SILENT) return;
      this.emitter.emit(Emitter.events.SELECTION_CHANGE, this.lastRange, source);
    }
  }
}

function contains(parent, descendant) {
  // IE11 has bug with Text nodes
  // https://connect.microsoft.com/IE/feedback/details/780874/node-contains-is-incorrect
  if (descendant instanceof Text) {
    descendant = descendant.parentNode;
  }
  return parent.contains(descendant);
}

function findLeaf(blot, index) {
  let path = blot.path(index);
  if (path.length > 0) {
    return path.pop();
  } else {
    return [null, -1]
  }
}

export { findLeaf, Range, Selection as default };


import Parchment from 'parchment';
import Quill from '../core/quill';
import logger from '../core/logger';
import Module from '../core/module';

let debug = logger('quill:toolbar');

class Toolbar extends Module {
  constructor(quill, options) {
    super(quill, options);
    this.container = this.options.container || this.options;
    if (typeof this.container === 'string') {
      this.container = document.querySelector(this.container);
    } else if (Array.isArray(this.container)) {
      let container = document.createElement('div');
      addControls(container, this.container);
      quill.container.parentNode.insertBefore(container, quill.container);
      this.container = container;
    }
    if (!(this.container instanceof HTMLElement)) {
      return debug.error('Container required for toolbar', this.options);
    }
    this.container.classList.add('ql-toolbar');
    this.container.classList.toggle('ios', /iPhone|iPad/i.test(navigator.userAgent));
    this.controls = [];
    this.handlers = {
      'clean': () => {
        let range = this.quill.getSelection();
        if (range != null) {
          let startLength = this.quill.getLength();
          this.quill.removeFormat(range);
          let endLength = this.quill.getLength();
          // account for embed removals
          this.quill.setSelection(range.index, range.length - (startLength-endLength));
        }
        return true;
      }
    };
    [].forEach.call(this.container.querySelectorAll('a, button, input[type=button], select'), (input) => {
      this.attach(input);
    });
    this.quill.on(Quill.events.SELECTION_CHANGE, this.update, this);
    this.quill.on(Quill.events.SCROLL_OPTIMIZE, () => {
      let [range, ] = this.quill.selection.getRange();  // quill.getSelection triggers update
      this.update(range);
    });
  }

  attach(input) {
    let format = [].find.call(input.classList, (className) => {
      return className.indexOf('ql-') === 0;
    });
    if (!format) return;
    format = format.slice('ql-'.length);
    let eventName = input.tagName === 'SELECT' ? 'change' : 'click';
    input.addEventListener(eventName, () => {
      this.quill.focus();
      let value;
      if (input.tagName === 'SELECT') {
        if (input.selectedIndex < 0) return;
        value = input.options[input.selectedIndex].value || false;
      } else {
        value = input.classList.contains('ql-active') ? false : input.dataset.value || true;
      }
      if (this.handlers[format]) {
        if (this.handlers[format](value)) return;
      }
      this.quill.format(format, value, Quill.sources.USER);
    });
    // TODO use weakmap
    this.controls.push([format, input]);
  }

  update(range) {
    if (range == null) return;
    let formats = this.quill.getFormat(range);
    this.controls.forEach(function(pair) {
      let [format, input] = pair;
      if (input.tagName === 'SELECT') {
        let option;
        if (formats[format] == null) {
          option = input.querySelector('option[selected]');
        } else if (!Array.isArray(formats[format])) {
          option = input.querySelector(`option[value="${formats[format]}"]`);
        }
        if (option == null) {
          input.value = '';   // TODO make configurable?
          input.selectedIndex = -1;
        } else {
          option.selected = true;
        }
      } if (input.dataset.value) {
        input.classList.toggle('ql-active', input.dataset.value == formats[format]);  // Intentional ==
      } else {
        input.classList.toggle('ql-active', formats[format] || false);
      }
    });
  }
}
Toolbar.DEFAULTS = {};

function addButton(container, format, value) {
  let input = document.createElement('button');
  input.classList.add('ql-' + format);
  if (value != null) {
    input.dataset.value = value;
  }
  container.appendChild(input);
}

function addControls(container, groups) {
  if (!Array.isArray(groups[0])) {
    groups = [groups];
  }
  groups.forEach(function(controls) {
    let group = document.createElement('span');
    group.classList.add('ql-formats');
    controls.forEach(function(control) {
      if (typeof control === 'string') {
        addButton(group, control);
      } else {
        let format = Object.keys(control)[0];
        let value = control[format];
        if (Array.isArray(value)) {
          addSelect(group, format, value);
        } else {
          addButton(group, format, value);
        }
      }
    });
    container.appendChild(group);
  });
}

function addSelect(container, format, values) {
  let input = document.createElement('select');
  input.classList.add('ql-' + format);
  values.forEach(function(value) {
    let option = document.createElement('option');
    if (value !== false) {
      option.setAttribute('value', value);
    } else {
      option.setAttribute('selected', 'selected');
    }
    input.appendChild(option);
  });
  container.appendChild(input);
}

export { Toolbar as default, addControls };


<svg viewbox="0 0 18 18">
  <rect class="ql-stroke-mitter" height="12" width="12" x="3" y="3"></rect>
  <line class="ql-stroke-mitter" x1="9" x2="9" y1="3" y2="15"></line>
  <line class="ql-stroke-mitter" x1="15" x2="3" y1="9" y2="9"></line>
</svg>


<svg viewbox="0 0 18 18">
  <rect class="ql-fill ql-stroke" height="3" width="3" x="4" y="5"></rect>
  <rect class="ql-fill ql-stroke" height="3" width="3" x="11" y="5"></rect>
  <path class="ql-even ql-fill ql-stroke" d="M7,8c0,4.031-3,5-3,5"></path>
  <path class="ql-even ql-fill ql-stroke" d="M14,8c0,4.031-3,5-3,5"></path>
</svg>


this.emitter.on(Emitter.events.SCROLL_BEFORE_UPDATE, () => {

// TODO unclear if this has negative side effects

this.emitter.once(Emitter.events.SCROLL_UPDATE, () => {

this.setNativeRange(native.start.node, native.start.offset, native.end.node, native.end.offsetTop);


language: node_js
node_js: '5.3'
addons:
  apt:
    sources:
      - ubuntu-toolchain-r-test
    packages:
      - g++-4.8
script:
  - npm run build
  - npm run travis
sudo: false
cache:
  directories:
    - node_modules
env:
  matrix:
    - CXX=g++-4.8 BROWSER=mac-chrome-latest
    - CXX=g++-4.8 BROWSER=mac-firefox-latest
    - CXX=g++-4.8 BROWSER=mac-safari-latest
    - CXX=g++-4.8 BROWSER=windows-chrome-latest
    - CXX=g++-4.8 BROWSER=windows-firefox-latest
    - CXX=g++-4.8 BROWSER=windows-microsoftedge-latest
    - CXX=g++-4.8 BROWSER=windows-internet-explorer-latest
    - CXX=g++-4.8 BROWSER=linux-chrome-latest
    - CXX=g++-4.8 BROWSER=linux-firefox-latest
    - CXX=g++-4.8 BROWSER=ios-latest
    - CXX=g++-4.8 BROWSER=android-latest


import Picker from './picker';

class IconPicker extends Picker {
  constructor(select, icons) {
    super(select);
    this.container.classList.add('ql-icon-picker');
    [].forEach.call(this.container.querySelectorAll('.ql-picker-item'), (item) => {
      item.innerHTML = icons[item.dataset.value || ''];
    });
    this.selectItem(this.container.querySelector('.ql-selected'));
  }

  selectItem(item, trigger) {
    super.selectItem(item, trigger);
    this.label.innerHTML = item.innerHTML;
  }
}

export default IconPicker;


'use strict';

var _ = require('lodash');
var util = require('hexo-util');
var Permalink = util.Permalink;
var permalink;

function postPermalinkFilter(data){
  /* jshint validthis: true */
  var config = this.config;
  var meta = {
    id: data.id || data._id,
    title: data.slug,
    year: data.date.format('YYYY'),
    month: data.date.format('MM'),
    day: data.date.format('DD'),
    i_month: data.date.format('M'),
    i_day: data.date.format('D')
  };

  if (!permalink || permalink.rule !== config.permalink){
    permalink = new Permalink(config.permalink);
  }

  var categories = data.categories;

  if (categories.length){
    meta.category = categories.last().slug;
  } else {
    meta.category = config.default_category;
  }

  var keys = Object.keys(data);
  var key = '';

  for (var i = 0, len = keys.length; i < len; i++){
    key = keys[i];
    if (meta.hasOwnProperty(key)) continue;

    // Use Object.getOwnPropertyDescriptor to copy getters to avoid "Maximum call
    // stack size exceeded" error
    Object.defineProperty(meta, key, Object.getOwnPropertyDescriptor(data, key));
  }

  return permalink.stringify(_.defaults(meta, config.permalink_defaults));
}

module.exports = postPermalinkFilter;


'use strict';

function searchFormHelper(options){
  /* jshint validthis: true */
  options = options || {};

  var config = this.config;
  var className = options.class || 'search-form';
  var text = options.hasOwnProperty('text') ? options.text : 'Search';
  var button = options.button;

  return '<form action="//google.com/search" method="get" accept-charset="UTF-8" class="' + className + '">' +
    '<input type="search" name="q" results="0" class="' + className + '-input"' + (text ? ' placeholder="' + text + '"' : '') + '>' +
    (button ? '<button type="submit" class="' + className + '-submit">' + (typeof button === 'string' ? button : text) + '</button>' : '') +
    '<input type="hidden" name="sitesearch" value="' + config.url + '">' +
    '</form>';
}

module.exports = searchFormHelper;


'use strict';

describe('Tags', function(){
  require('./asset_img');
  require('./asset_link');
  require('./asset_path');
  require('./blockquote');
  require('./code');
  require('./gist');
  require('./iframe');
  require('./img');
  require('./include_code');
  require('./jsfiddle');
  require('./link');
  require('./post_link');
  require('./post_path');
  require('./pullquote');
  require('./vimeo');
  require('./youtube');
});


'use strict';

/**
* Pullquote tag
*
* Syntax:
*   {% pullquote [class] %}
*   Quote string
*   {% endpullquote %}
*/
module.exports = function(ctx){
  return function pullquoteTag(args, content){
    var result = '';

    args.unshift('pullquote');

    result += '
';
    result += ctx.render.renderSync({text: content, engine: 'markdown'});
    result += '
';

    return result;
  };
};


/* jshint validthis: true */
var config = this.config;
var meta = {
id: data.id || data._id,
title: data.slug,
year: data.date.format('YYYY'),
month: data.date.format('MM'),
day: data.date.format('DD'),
i_month: data.date.format('M'),
i_day: data.date.format('D')

keep keep keep keep add keep keep keep keep keep

'use strict';

var should = require('chai').should();
var moment = require('moment');

var PERMALINK = ':year/:month/:day/:title/';

describe('post_permalink', function(){
  var Hexo = require('../../../lib/hexo');
  var hexo = new Hexo();
  var postPermalink = require('../../../lib/plugins/filter/post_permalink').bind(hexo);
  var Post = hexo.model('Post');
  var post;

  hexo.config.permalink = PERMALINK;

  before(function(){
    var id;

    return hexo.init().then(function(){
      return Post.insert({
        source: 'foo.md',
        slug: 'foo',
        date: moment('2014-01-02')
      });
    }).then(function(post){
      id = post._id;
      return post.setCategories(['foo', 'bar']);
    }).then(function(){
      post = Post.findById(id);
    });
  });

  it('default', function(){
    postPermalink(post).should.eql('2014/01/02/foo/');
  });

  it('categories', function(){
    hexo.config.permalink = ':category/:title/';
    postPermalink(post).should.eql('foo/bar/foo/');
    hexo.config.permalink = PERMALINK;
  });

  it('uncategorized', function(){
    hexo.config.permalink = ':category/:title/';

    return Post.insert({
      source: 'bar.md',
      slug: 'bar'
    }).then(function(post){
      postPermalink(post).should.eql(hexo.config.default_category + '/bar/');
      hexo.config.permalink = PERMALINK;
      return Post.removeById(post._id);
    });
  });

  it('extra data', function(){
    hexo.config.permalink = ':layout/:title/';
    postPermalink(post).should.eql(post.layout + '/foo/');
    hexo.config.permalink = PERMALINK;
  });

  it('id', function(){
    hexo.config.permalink = ':id';

    postPermalink(post).should.eql(post._id);

    post.id = 1;
    postPermalink(post).should.eql('1');

    hexo.config.permalink = PERMALINK;
  });
});


'use strict';

var pathFn = require('path');
var fs = require('hexo-fs');

module.exports = function(ctx){
  var pkgPath = pathFn.join(ctx.base_dir, 'package.json');

  return readPkg(pkgPath).then(function(pkg){
    if (!pkg) return;

    ctx.env.init = true;

    if (pkg.hexo.version === ctx.version) return;

    pkg.hexo.version = ctx.version;

    ctx.log.debug('Updating package.json');
    return fs.writeFile(pkgPath, JSON.stringify(pkg, null, '  '));
  });
};

function readPkg(path){
  return fs.exists(path).then(function(exist){
    if (!exist) return;

    return fs.readFile(path).then(function(content){
      var pkg = JSON.parse(content);
      if (typeof pkg.hexo !== 'object') return;

      return pkg;
    });
  });
}


'use strict';

var should = require('chai').should();
var fs = require('hexo-fs');

describe('clean', function(){
  var Hexo = require('../../../lib/hexo');
  var hexo = new Hexo(__dirname, {silent: true});
  var clean = require('../../../lib/plugins/console/clean').bind(hexo);

  it('delete database', function(){
    var dbPath = hexo.database.options.path;

    return fs.writeFile(dbPath, '').then(function(){
      return clean();
    }).then(function(){
      return fs.exists(dbPath);
    }).then(function(exist){
      exist.should.be.false;
    });
  });

  it('delete public folder', function(){
    var publicDir = hexo.public_dir;

    return fs.mkdirs(publicDir).then(function(){
      return clean();
    }).then(function(){
      return fs.exists(publicDir);
    }).then(function(exist){
      exist.should.be.false;
    });
  });
});


'use strict';

var Schema = require('warehouse').Schema;

module.exports = function(ctx){
  var PostCategory = new Schema({
    post_id: {type: Schema.Types.CUID, ref: 'Post'},
    category_id: {type: Schema.Types.CUID, ref: 'Category'}
  });

  return PostCategory;
};


hexo.config.permalink = PERMALINK;
});
});


'use strict';

var should = require('chai').should();
var sinon = require('sinon');

describe('migrate', function(){
  var Hexo = require('../../../lib/hexo');
  var hexo = new Hexo(__dirname, {silent: true});
  var migrate = require('../../../lib/plugins/console/migrate').bind(hexo);

  it('default', function(){
    var migrator = sinon.spy(function(args){
      args.foo.should.eql(1);
      args.bar.should.eql(2);
    });

    hexo.extend.migrator.register('test', migrator);

    return migrate({_: ['test'], foo: 1, bar: 2}).then(function(){
      migrator.calledOnce.should.be.true;
    });
  });
});


'use strict';

var htmlTag = require('hexo-util').htmlTag;
var qs = require('querystring');

function mailToHelper(path, text, options){
  options = options || {};

  if (Array.isArray(path)) path = path.join(',');
  if (!text) text = path;

  var attrs = {
    href: 'mailto:' + path,
    title: text
  };

  var keys = Object.keys(options);
  var key = '';

  for (var i = 0, len = keys.length; i < len; i++){
    key = keys[i];
    attrs[key] = options[key];
  }

  if (attrs.class && Array.isArray(attrs.class)){
    attrs.class = attrs.class.join(' ');
  }

  var data = {};

  ['subject', 'cc', 'bcc', 'body'].forEach(function(i){
    var item = attrs[i];

    if (item){
      data[i] = Array.isArray(item) ? item.join(',') : item;
      attrs[i] = null;
    }
  });

  var querystring = qs.stringify(data);
  if (querystring) attrs.href += '?' + querystring;

  return htmlTag('a', attrs, text);
}

module.exports = mailToHelper;


'use strict';

var tildify = require('tildify');
var chalk = require('chalk');

function publishConsole(args){
  /* jshint validthis: true */
  // Display help message if user didn't input any arguments
  if (!args._.length){
    return this.call('help', {_: ['publish']});
  }

  var self = this;

  return this.post.publish({
    slug: args._.pop(),
    layout: args._.length ? args._[0] : this.config.default_layout
  }, args.r || args.replace).then(function(post){
    self.log.info('Published: %s', chalk.magenta(tildify(post.path)));
  });
}

module.exports = publishConsole;


keep keep keep replace keep keep keep keep

const localeList = require('../src/i18n/locales').map(item => item.alternate || item.locale)

// Imports
const fs = require('fs')
const { resolve } = require('path')
const { getApi, getCompleteApi } = require('@vuetify/api-generator')
const rimraf = require('rimraf')

const localeList = require('../src/i18n/locales').map(item => item.locale)

const capitalize = str => {
  return str.charAt(0).toUpperCase() + str.slice(1)
}

function genFrontMatter (component) {
  const fm = [
    `title: ${component} API`,
    `description: API for the ${component} component.`,
    `keywords: ${component}, api, vuetify`,
  ]

  return `---\nmeta:\n${fm.map(s => '  ' + s).join('\n')}\n---\n\n`
}

function genHeader (component) {
  const header = [
    genFrontMatter(component),
    `# ${component} API\n\n`,
    '<entry-ad />',
  ]

  return `${header.join('\n\n')}\n\n`
}

function genFooter () {
  const footer = [
    '<backmatter />',
  ]

  return `${footer.join('\n\n')}\n\n`
}

const sanitize = str => str.replace(/\$/g, '')

function createMdFile (component, data, locale) {
  let str = ''

  str += genHeader(component)

  for (const [header, value] of Object.entries(data)) {
    if (['mixins', 'name'].includes(header) || !value.length) continue

    str += header === 'sass'
      ? '## SASS Variables\n'
      : `## ${capitalize(header)}\n`

    str += `<api-table name="${sanitize(component)}" field="${header}" />\n\n`
  }

  str += genFooter()

  return str
}

function writeFile (componentName, componentApi, locale) {
  const folder = `src/api/${locale}`

  if (!fs.existsSync(resolve(folder))) {
    fs.mkdirSync(resolve(folder), { recursive: true })
  }

  fs.writeFileSync(resolve(`${folder}/${sanitize(componentName)}.md`), createMdFile(componentName, componentApi, locale))
}

function writeData (componentName, componentApi) {
  const folder = `src/api/data`

  if (!fs.existsSync(resolve(folder))) {
    fs.mkdirSync(resolve(folder), { recursive: true })
  }

  fs.writeFileSync(resolve(`${folder}/${sanitize(componentName)}.js`), `module.exports = ${JSON.stringify(componentApi, null, 2)}`)
}

function generateFiles () {
  const api = getCompleteApi(localeList)

  for (const locale of localeList) {
    const pages = {}

    for (const item of api) {
      writeFile(item.name, item, locale)

      pages[`/${locale}/api/${sanitize(item.name)}/`] = item.name
    }

    fs.writeFileSync(resolve(`src/api/${locale}/pages.json`), JSON.stringify(pages, null, 2))
    fs.writeFileSync(resolve(`src/api/${locale}.js`), `export default require.context('./${locale}', true, /\\.md$/)`)
  }

  for (const item of api) {
    writeData(item.name, item)
  }

  fs.writeFileSync(resolve(`src/api/sass.json`), JSON.stringify([
    ...api.filter(item => item.component || item.name === '$vuetify').map(item => item.name),
  ]))
}

class ApiPlugin {
  apply (compiler) {
    rimraf.sync(resolve('src/api'))

    generateFiles()

    let changedFiles = []
    const sourcePaths = [resolve('../api-generator/src/maps'), (resolve('../api-generator/src/locale/en'))]

    compiler.hooks.afterCompile.tap('ApiPlugin', compilation => {
      sourcePaths.forEach(sourcePath => compilation.contextDependencies.add(sourcePath))
    })

    compiler.hooks.watchRun.tap('ApiPlugin', async comp => {
      const changedTimes = comp.watchFileSystem.watcher.mtimes

      changedFiles = Object.keys(changedTimes).filter(filePath => {
        return sourcePaths.some(path => filePath.startsWith(path))
      })

      // Make sure api-gen is using latest files
      changedFiles.forEach(filePath => {
        delete require.cache[filePath]
      })
    })

    compiler.hooks.compilation.tap('ApiPlugin', () => {
      if (!changedFiles.length) return

      for (const filePath of changedFiles) {
        const matches = /[/\\]([-a-z]+|\$vuetify)\.js(?:on)?$/i.exec(filePath)
        const [_, componentName] = matches
        const componentApi = getApi(componentName, localeList)
        writeData(componentName, componentApi)
      }

      changedFiles = []
    })
  }
}

module.exports = ApiPlugin


<template>

    <v-hover>
      <template v-slot:default="{ hover }">
        <v-card
          :elevation="hover ? 24 : 6"
          class="mx-auto pa-6"
        >
          Prop based elevation
        </v-card>
      </template>
    </v-hover>

    <v-hover>
      <template v-slot:default="{ hover }">
        <div
          :class="`elevation-${hover ? 24 : 6}`"
          class="mx-auto pa-6 transition-swing"
        >
          Class based elevation

      </template>
    </v-hover>

</template>


<template>
  <v-row>
    <v-col
      cols="12"
      sm="6"
      md="4"
    >
      <v-menu
        ref="menu"
        v-model="menu"
        :close-on-content-click="false"
        :return-value.sync="date"
        transition="scale-transition"
        offset-y
        min-width="290px"
      >
        <template v-slot:activator="{ on, attrs }">
          <v-text-field
            v-model="date"
            label="Picker in menu"
            prepend-icon="mdi-calendar"
            readonly
            v-bind="attrs"
            v-on="on"
          ></v-text-field>
        </template>
        <v-date-picker
          v-model="date"
          no-title
          scrollable
        >
          <v-spacer></v-spacer>
          <v-btn
            text
            color="primary"
            @click="menu = false"
          >
            Cancel
          </v-btn>
          <v-btn
            text
            color="primary"
            @click="$refs.menu.save(date)"
          >
            OK
          </v-btn>
        </v-date-picker>
      </v-menu>
    </v-col>
    <v-spacer></v-spacer>
    <v-col
      cols="12"
      sm="6"
      md="4"
    >
      <v-dialog
        ref="dialog"
        v-model="modal"
        :return-value.sync="date"
        persistent
        width="290px"
      >
        <template v-slot:activator="{ on, attrs }">
          <v-text-field
            v-model="date"
            label="Picker in dialog"
            prepend-icon="mdi-calendar"
            readonly
            v-bind="attrs"
            v-on="on"
          ></v-text-field>
        </template>
        <v-date-picker
          v-model="date"
          scrollable
        >
          <v-spacer></v-spacer>
          <v-btn
            text
            color="primary"
            @click="modal = false"
          >
            Cancel
          </v-btn>
          <v-btn
            text
            color="primary"
            @click="$refs.dialog.save(date)"
          >
            OK
          </v-btn>
        </v-date-picker>
      </v-dialog>
    </v-col>
    <v-col
      cols="12"
      sm="6"
      md="4"
    >
      <v-menu
        v-model="menu2"
        :close-on-content-click="false"
        :nudge-right="40"
        transition="scale-transition"
        offset-y
        min-width="290px"
      >
        <template v-slot:activator="{ on, attrs }">
          <v-text-field
            v-model="date"
            label="Picker without buttons"
            prepend-icon="mdi-calendar"
            readonly
            v-bind="attrs"
            v-on="on"
          ></v-text-field>
        </template>
        <v-date-picker
          v-model="date"
          @input="menu2 = false"
        ></v-date-picker>
      </v-menu>
    </v-col>
    <v-spacer></v-spacer>
  </v-row>
</template>

<script>
  export default {
    data: () => ({
      date: new Date().toISOString().substr(0, 10),
      menu: false,
      modal: false,
      menu2: false,
    }),
  }
</script>


<template>
  <p class="text-justify">
    Morbi mattis ullamcorper velit. Donec orci lectus, aliquam ut, faucibus non, euismod id, nulla. Fusce convallis metus id felis luctus adipiscing. Aenean massa. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus.

    Nulla consequat massa quis enim. Praesent venenatis metus at tortor pulvinar varius. Donec venenatis vulputate lorem. Phasellus accumsan cursus velit. Pellentesque ut neque.
  </p>
</template>


.map(lang => lang.alternate || lang.locale)

const { kebabCase } = require('lodash')
const glob = require('glob')
const path = require('path')
const resolve = file => path.resolve(__dirname, file)
const DATA_PATH_API_FILES = resolve('../src/api/en/*.md')
const DATA_PATH_DOC_FILES = resolve('../src/pages/en/**/*.md')

require('dotenv').config({ path: resolve('../.env.local') })

const languages = process.env.EN_LOCALE_ONLY === 'true'
  ? ['en']
  : require('../src/i18n/locales')
    .map(lang => lang.locale)
    .filter(lang => lang !== 'eo-UY')

function genRoutes (data, prefix) {
  const files = glob.sync(data)
  const paths = []

  for (const file of files) {
    const route = file
      .split('/en/')
      .pop()
      .split('/')
      .map(i => kebabCase(i.replace(/md/, '')).toLowerCase())
      .join('/')

    if (route === 'home') continue
    paths.push(`/${prefix}${route}/`)
  }

  return paths
}

function genDemos () {
  const files = glob.sync(resolve('../src/examples/wireframes/*.vue'))
  const paths = []

  for (const file of files) {
    const route = file
      .split('/wireframes/')
      .pop()
      .replace(/\.vue$/, '')

    paths.push(`/examples/wireframes/${route}/`)
  }

  return paths
}

const paths = [
  ...genRoutes(DATA_PATH_DOC_FILES, ''),
  ...genRoutes(DATA_PATH_API_FILES, 'api/'),
  ...genDemos(),
]
const routes = [{ locale: '', path: '', fullPath: '/' }]

for (const locale of languages) {
  routes.push({ locale, path: '', fullPath: `/${locale}/` })
  for (const path of paths) {
    routes.push({ locale, path, fullPath: `/${locale}${path}` })
  }
}

module.exports = routes


<template>
  <v-container>
    <v-row justify="center">
      <v-col
        v-for="n in 25"
        :key="n"
        cols="auto"
      >
        <v-card
          :elevation="n - 1"
          height="100"
          width="100"
          class="secondary"
        >
          <v-row
            class="fill-height"
            align="center"
            justify="center"
            v-text="n - 1"
          ></v-row>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>


---
meta:
  title: Avatar component
  description: The avatar component is used to control the size and border radius of an image. It can be used with numerous components to provide better visual context.
  keywords: avatars, vuetify avatar component, vue avatar component
related:
  - /components/badges/
  - /components/icons/
  - /components/lists/
---

# Avatars

The `v-avatar` component is typically used to display circular user profile pictures. This component will allow you to dynamically size and add a border radius of responsive images, icons, and text. A **tile** variation is available for displaying an avatar without border radius.

<entry-ad />

## Usage

Avatars in their simplest form display content within a circular container.

<usage name="v-avatar" />

## API

- [v-avatar](/api/v-avatar)

### Props

#### Size

The `size` prop allows you to define the height and width of `v-avatar`. This prop scales both evenly with an aspect ratio of 1. `height` and `width` props will override this prop.

<example file="v-avatar/prop-size" />

#### Tile

The `tile` prop removes the border radius from v-avatar leaving you with a simple square avatar.

<example file="v-avatar/prop-tile" />

### Slots

#### Default

The `v-avatar` default slot will accept the `v-icon` component, an image, or text. Mix and match these with other props to create something unique.

<example file="v-avatar/slot-default" />

<discovery-ad />

### Misc

#### Advanced usage

Combining an avatar with other components allows you to build beautiful user interfaces right out of the box.

<example file="v-avatar/misc-advanced" />

Another example combining avatar with menu.

<example file="v-avatar/misc-avatar-menu" />

#### Profile Card

Using the **tile** prop, we can create a sleek hard-lined profile card.

<example file="v-avatar/misc-profile-card" />

<backmatter />


<template>
  <v-card
    class="mx-auto"
    max-width="400"
    tile
  >
    <v-list-item>
      <v-list-item-content>
        <v-list-item-title>Single-line item</v-list-item-title>
      </v-list-item-content>
    </v-list-item>

    <v-list-item two-line>
      <v-list-item-content>
        <v-list-item-title>Two-line item</v-list-item-title>
        <v-list-item-subtitle>Secondary text</v-list-item-subtitle>
      </v-list-item-content>
    </v-list-item>

    <v-list-item three-line>
      <v-list-item-content>
        <v-list-item-title>Three-line item</v-list-item-title>
        <v-list-item-subtitle>
          Secondary line text Lorem ipsum dolor sit amet,
        </v-list-item-subtitle>
        <v-list-item-subtitle>
          consectetur adipiscing elit.
        </v-list-item-subtitle>
      </v-list-item-content>
    </v-list-item>
  </v-card>
</template>


const { alternate, locale } = locales.find(l => [l.alternate, l.locale].includes(name))

import locales from '@/i18n/locales'

export function localeLookup (name) {
  return locales.find(l => [l.alternate, l.locale].includes(name)).locale
}


<template>
  <v-card
    v-click-outside="onClickOutside"
    :color="active ? 'primary' : undefined"
    :dark="active"
    class="mx-auto"
    height="256"
    rounded="xl"
    width="256"
    @click="active = true"
  >
    <div class="text-h6 text-md-h4 fill-height d-flex align-center justify-center">
      {{ active ? 'Click Outside' : 'Click Me' }}
    </div>
  </v-card>
</template>

<script>
  export default {
    data: () => ({
      active: false,
    }),

    methods: {
      onClickOutside () {
        this.active = false
      },
    },
  }
</script>


@import '../../styles/styles.sass';

$bottom-nav-btn-font-size: map-deep-get($headings, 'caption', 'size') !default;
$bottom-nav-btn-min-width: 80px !default;
$bottom-nav-btn-max-width: 168px !default;
$bottom-nav-shift-btn-top: calc(100% - 12px) !default;
$bottom-nav-shift-btn-active-top: calc(100% - 22px) !default;


<template>
  <v-card
    class="mx-auto"
    max-width="300"
    tile
  >
    <v-list shaped>
      <v-subheader>REPORTS</v-subheader>
      <v-list-item-group
        v-model="selectedItem"
        color="primary"
      >
        <v-list-item
          v-for="(item, i) in items"
          :key="i"
        >
          <v-list-item-icon>
            <v-icon v-text="item.icon"></v-icon>
          </v-list-item-icon>
          <v-list-item-content>
            <v-list-item-title v-text="item.text"></v-list-item-title>
          </v-list-item-content>
        </v-list-item>
      </v-list-item-group>
    </v-list>
  </v-card>
</template>

<script>
  export default {
    data: () => ({
      selectedItem: 1,
      items: [
        { text: 'Real-Time', icon: 'mdi-clock' },
        { text: 'Audience', icon: 'mdi-account' },
        { text: 'Conversions', icon: 'mdi-flag' },
      ],
    }),
  }
</script>