Compare commits

...

93 Commits

Author SHA1 Message Date
Julian Lam
e9b9f090e4 0.2.2 2014-01-16 09:32:41 -05:00
Julian Lam
b82a6fa888 adding accidentally removed upgrade directives to v0.2.x branch 2014-01-16 09:30:18 -05:00
Baris Soner Usakli
8ab539b518 0.2.1 2014-01-04 00:50:23 -05:00
Baris Soner Usakli
9078c2a536 0.2.0 2014-01-04 00:49:10 -05:00
Baris Soner Usakli
fd20e4a400 5% more 2014-01-04 00:41:25 -05:00
Baris Soner Usakli
1a64e40b21 upgrade check 2014-01-04 00:38:43 -05:00
Julian Lam
cbfba4b45b 0.2.1 2014-01-04 00:04:37 -05:00
Baris Soner Usakli
f21a98f37f first pass, #524, #667 2014-01-03 21:33:41 -05:00
psychobunny
0edd6985ec templates.js added support for !@first and !@last conditionals 2014-01-03 21:23:08 -05:00
psychobunny
98a646fa62 changed numRecentTopics to numRecentReplies, that makes more sense now 2014-01-03 20:37:29 -05:00
psychobunny
1d69436b44 fix to getRecentReplies causing count = 0 to return unlimited 2014-01-03 20:36:00 -05:00
psychobunny
d6c7551120 pull # of recent replies based on settings 2014-01-03 20:29:09 -05:00
psychobunny
fb53e89023 upgrade.js - categories.numRecentTopics 2014-01-03 20:20:23 -05:00
psychobunny
d28beaa4dc admin - add "# recent topics to display" to categories 2014-01-03 20:17:55 -05:00
psychobunny
ac06567617 admin - add custom class to categories (forgot to commit this) 2014-01-03 20:14:26 -05:00
Baris Soner Usakli
d0a2c077ff refactored posts.create to use waterfall 2014-01-03 19:32:52 -05:00
psychobunny
ebf07626de use categories.class instead of hardcoded columns 2014-01-03 17:22:37 -05:00
psychobunny
9ef8bb4cdc woops, fail at iteration 2014-01-03 17:22:23 -05:00
psychobunny
bc8a53aadd upgrade.js - adding categories.class and categories.link 2014-01-03 17:09:19 -05:00
psychobunny
03c4a1bc73 remove console.log(file) - no more exploding terminals 2014-01-03 15:59:49 -05:00
Julian Lam
d93163896f Merge pull request #701 from aonz1982/install_automated_setup
Install automated setup
2014-01-02 18:47:38 -08:00
Julian Lam
08bdbc0bcc cleanup of PR - fixed some logic bugs and linted 2014-01-02 21:44:13 -05:00
Julian Lam
35d6a99775 Merge branch 'AdminButton' of github.com:genderup/NodeBB into genderup-AdminButton 2014-01-02 21:34:03 -05:00
Julian Lam
e45e86fcc1 fixed width icons in ACP. Also, who uses single quotes in HTML? ARGH 2014-01-02 18:13:46 -05:00
Baris Soner Usakli
9589d340b9 removed console.log 2014-01-02 16:00:24 -05:00
Baris Soner Usakli
91afbf106e removed console.log 2014-01-02 16:00:05 -05:00
Baris Soner Usakli
aff11359ae Merge branch 'master' of https://github.com/designcreateplay/NodeBB 2014-01-02 15:59:34 -05:00
Baris Soner Usakli
aff8cef5f3 closes #717 2014-01-02 15:59:25 -05:00
Julian Lam
879855744d Merge branch 'master' of github.com:designcreateplay/NodeBB 2014-01-02 15:21:00 -05:00
Julian Lam
b5ab0c9097 updated minvers for markdown and mentions 2014-01-02 15:20:54 -05:00
psychobunny
2c398f81d2 fixed the twitter link to @NodeBB 2014-01-02 15:06:08 -05:00
Baris Soner Usakli
520fcadd3f closes #456 2014-01-02 14:53:27 -05:00
Baris Soner Usakli
e8eb9f91b9 Merge branch 'master' of https://github.com/designcreateplay/NodeBB 2014-01-02 14:26:30 -05:00
Baris Soner Usakli
8bfb338eee #712 2014-01-02 14:26:08 -05:00
Julian Lam
bbb655abdd Merge branch 'master' of github.com:designcreateplay/NodeBB 2014-01-02 02:17:55 -05:00
Julian Lam
095e5527e3 upping markdown minver 2014-01-02 02:17:47 -05:00
Barış Soner Uşaklı
4eb8c34855 Merge pull request #715 from cmastudios/age
Calculate age based on days instead of years
2014-01-01 18:35:47 -08:00
cmastudios
e3185b9560 Calculate age based on days instead of years
Calculating the age based on the year only caused issues in the display of the age because it was off. Example: Person who was born in march of 1999 is displayed as 15 instead of 14 after the turn of the year.
2014-01-01 19:46:11 -05:00
Julian Lam
449adfae59 Merge branch 'master' of github.com:designcreateplay/NodeBB 2014-01-01 15:31:32 -05:00
Julian Lam
714e61b137 upping markdown minver 2014-01-01 15:31:27 -05:00
Baris Soner Usakli
d0e4689907 removed extra event in websocket.js 2014-01-01 14:44:15 -05:00
Baris Soner Usakli
1996e64c9b if imgur client id is not set but local file uploads are enabled use that 2014-01-01 14:38:12 -05:00
Baris Soner Usakli
e2fb617cc0 thread delete restore fix 2014-01-01 14:15:53 -05:00
Baris Soner Usakli
fd88aff195 mongo string fix 2014-01-01 14:11:12 -05:00
Julian Lam
f7a1cca861 properly fixed #713 2013-12-31 20:53:24 -05:00
Julian Lam
e3fb996a80 Merge branch 'master' of github.com:designcreateplay/NodeBB 2013-12-31 20:28:37 -05:00
Julian Lam
fe53037e53 hopefully fixing #713 2013-12-31 20:28:31 -05:00
Baris Soner Usakli
438f90d859 expire functionality in dbal 2013-12-31 19:08:38 -05:00
Baris Soner Usakli
742c8fb43c closes #712 2013-12-31 17:14:27 -05:00
Baris Soner Usakli
d43f3cebc6 closes #707, closes #686 2013-12-31 17:01:51 -05:00
Julian Lam
9d452241ad Merge branch 'master' of github.com:designcreateplay/NodeBB 2013-12-31 14:46:33 -05:00
Julian Lam
c19a51e1b6 tweaking slugify code to not remove numbers 2013-12-31 14:46:28 -05:00
Baris Soner Usakli
1b41a8f467 fixed typo 2013-12-31 14:32:16 -05:00
Baris Soner Usakli
f933fc0167 forgot topics.js oops 2013-12-31 14:27:56 -05:00
Baris Soner Usakli
8cfb239aac closes #705 2013-12-31 14:25:26 -05:00
Baris Soner Usakli
a974c6fa99 possible fix for mongo crash 2013-12-31 13:45:37 -05:00
Julian Lam
998f780fd2 fuck, I am dumb. 2013-12-31 13:11:32 -05:00
Julian Lam
b022d46d47 upgrade script for Topic titless and Usernames - closes #709 2013-12-31 13:04:29 -05:00
Julian Lam
f7793e54b1 adding events.log 2013-12-31 10:49:26 -05:00
Julian Lam
1e61033667 Merge branch 'master' of github.com:designcreateplay/NodeBB 2013-12-31 10:49:05 -05:00
Julian Lam
53caa5e422 full unicode support in slugify method, thanks to XRegExp 2013-12-31 10:48:59 -05:00
Baris Soner Usakli
40d20846d8 moar refactor 2013-12-31 03:36:42 -05:00
Baris Soner Usakli
204913c63d Merge branch 'master' of https://github.com/designcreateplay/NodeBB 2013-12-31 03:14:29 -05:00
Baris Soner Usakli
6c30437c47 closes #706, refactor admin image uploads, fixed gif uploads 2013-12-31 03:14:22 -05:00
Barış Soner Uşaklı
dd7fe47dfd Merge pull request #704 from akhoury/master
guarding against Errors on Socket Disconnect
2013-12-30 16:55:21 -08:00
Aziz Khoury
50323c3d23 guarding against Errors on Socket Disconnect
Saw this 

```
TypeError: Cannot call method 'indexOf' of undefined
    at Socket.<anonymous> (/home/admin/NodeBB/src/websockets.js:108:33)
    at Socket.EventEmitter.emit [as $emit] (events.js:95:17)
    at Socket.onDisconnect (/home/admin/NodeBB/node_modules/socket.io/lib/socket.js:153:10)
    at SocketNamespace.handleDisconnect (/home/admin/NodeBB/node_modules/socket.io/lib/namespace.js:229:46)
```

and this

```
/home/admin/NodeBB/src/websockets.js:113
			if (userSockets[uid].length === 0) {
			                    ^
TypeError: Cannot read property 'length' of undefined
    at Socket.<anonymous> (/home/admin/NodeBB/src/websockets.js:113:24)
```

in my logs, when users are disconnecting
2013-12-30 19:40:57 -05:00
psychobunny
69e0aa338d resolved some todo that's been in there for many months 2013-12-30 17:11:59 -05:00
psychobunny
6dcd06b63c removed unused parameter in templates.prepare 2013-12-30 16:26:30 -05:00
psychobunny
42d77080f3 plugins: filter:server.create_routes - allow plugins to add custom templates and/or modify individual blocks withiin a template 2013-12-30 16:20:05 -05:00
Baris Soner Usakli
fbb4998999 closes #676 2013-12-30 16:09:07 -05:00
Julian Lam
14744a854f fixes #703 - topic feeds were not saving (who knows for how long!) 2013-12-30 12:39:13 -05:00
Pongsan Sayampol
2c6afb4244 Add a way to set social network logins 2013-12-30 11:46:33 +07:00
Pongsan Sayampol
24907e456d Fix the issue that the default values are saved to config.json 2013-12-30 11:45:10 +07:00
Baris Soner Usakli
2039885d96 removed console.logs 2013-12-29 23:35:04 -05:00
Baris Soner Usakli
daacdb50f3 closes #645 2013-12-29 23:33:28 -05:00
Baris Soner Usakli
21155b1b80 recent rss link fix 2013-12-29 21:35:03 -05:00
Barış Soner Uşaklı
5d69167a64 updated pictures 2013-12-29 20:55:46 -05:00
psychobunny
5db27a835f fix for minification of plugins static directories 2013-12-29 19:36:18 -05:00
Baris Soner Usakli
c8e423e9cf check if item is valid 2013-12-29 18:25:21 -05:00
Baris Soner Usakli
be3465c5ca display events in admin page events section 2013-12-29 18:10:42 -05:00
Baris Soner Usakli
637e037e27 Merge branch 'master' of https://github.com/designcreateplay/NodeBB 2013-12-29 16:03:32 -05:00
Baris Soner Usakli
3e6bcd83cc fixed typo in user reset 2013-12-29 16:03:25 -05:00
psychobunny
dc4aeca427 also send notification data along with event:new_notification socket call 2013-12-29 15:09:34 -05:00
Baris Soner Usakli
9eb09f14cb updated vanilla ver 2013-12-29 13:57:04 -05:00
Baris Soner Usakli
a55fc364a0 closes #697 2013-12-29 13:47:34 -05:00
Baris Soner Usakli
2f90949560 vanilla color fixes 2013-12-28 14:36:33 -05:00
Baris Soner Usakli
a940219321 remvoed the timeout on the login call 2013-12-28 13:11:49 -05:00
Michael Mitchell
aaf6b11dc9 removed extraneous 2013-12-28 08:34:59 -08:00
Michael Mitchell
0f0913bfe5 add admin button 2013-12-27 14:18:30 -08:00
Michael Mitchell
5569337c40 first 2013-12-27 14:09:27 -08:00
Baris Soner Usakli
ba2f47ead6 closes #690, closes #691 2013-12-27 14:09:22 -05:00
Julian Lam
b52782deb8 removed use of strip_tags and using String library instead 2013-12-26 21:10:26 -05:00
Julian Lam
2c6bf93eb5 added String parsing library, sanitizing meta tag "description" for
topics, and added og:description meta tag -- fixes #688
2013-12-26 20:37:45 -05:00
63 changed files with 4712 additions and 687 deletions

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@ feeds/recent.rss
# winston?
error.log
events.log

View File

@@ -8,9 +8,9 @@
* [Follow on Twitter](http://www.twitter.com/NodeBB/ "NodeBB Twitter")
* [Like us on Facebook](http://www.facebook.com/NodeBB/ "NodeBB Facebook")
![NodeBB Main Category Listing](http://i.imgur.com/zffCFoh.png)
![NodeBB Main Category Listing](http://i.imgur.com/zRdzCcj.png)
![NodeBB Topic Page](http://i.imgur.com/JihdcUa.png)
![NodeBB Topic Page](http://i.imgur.com/ZC8W39a.png)
## How can I follow along/contribute?

18
app.js
View File

@@ -27,8 +27,9 @@
async = require('async'),
semver = require('semver'),
winston = require('winston'),
pkg = require('./package.json'),
path = require('path'),
pkg = require('./package.json'),
utils = require('./public/src/utils.js'),
meta;
// Runtime environment
@@ -69,8 +70,8 @@
});
meta = require('./src/meta');
nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path') + '/');
nconf.set('upload_url', nconf.get('url') + 'uploads/');
nconf.set('url', nconf.get('base_url') + (nconf.get('use_port') ? ':' + nconf.get('port') : '') + nconf.get('relative_path') + path.sep);
nconf.set('upload_url', path.join(path.sep, nconf.get('relative_path'), 'uploads', path.sep));
nconf.set('base_dir', __dirname);
winston.info('Initializing NodeBB v' + pkg.version + ', on port ' + nconf.get('port') + ', using Redis store at ' + nconf.get('redis:host') + ':' + nconf.get('redis:port') + '.');
@@ -108,15 +109,10 @@
var customTemplates = meta.config['theme:templates'] ? path.join(__dirname, 'node_modules', meta.config['theme:id'], meta.config['theme:templates']) : false;
// todo: replace below with read directory code, derp.
templates.init([
'header', 'footer', 'logout', 'outgoing', 'admin/header', 'admin/footer', 'admin/index',
'emails/reset', 'emails/reset_plaintext', 'emails/email_confirm', 'emails/email_confirm_plaintext',
'emails/header', 'emails/footer',
'noscript/header', 'noscript/home', 'noscript/category', 'noscript/topic'
], customTemplates);
utils.walk(path.join(__dirname, 'public/templates'), function (err, tplsToLoad) {
templates.init(tplsToLoad, customTemplates);
});
plugins.ready(function() {
templates.ready(webserver.init);

View File

@@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPLv3 or later",
"description": "NodeBB Forum",
"version": "0.2.0",
"version": "0.2.2",
"homepage": "http://www.nodebb.org",
"repository": {
"type": "git",
@@ -38,12 +38,14 @@
"prompt": "~0.2.11",
"uglify-js": "~2.4.0",
"validator": "~1.5.1",
"nodebb-plugin-mentions": "~0.1.16",
"nodebb-plugin-markdown": "~0.2.1",
"nodebb-theme-vanilla": "~0.0.10",
"nodebb-plugin-mentions": "~0.1",
"nodebb-plugin-markdown": "~0.3",
"nodebb-theme-vanilla": "~0.0.12",
"nodebb-theme-cerulean": "0.0.10",
"cron": "~1.0.1",
"semver": "~2.2.1"
"semver": "~2.2.1",
"string": "~1.7.0",
"xregexp": "~2.0.0"
},
"optionalDependencies": {
"redis": "0.8.3",

View File

@@ -12,6 +12,7 @@
"reply": "Reply",
"edit": "Edit",
"delete": "Delete",
"fork": "Fork",
"banned": "banned",
"link": "Link",

View File

@@ -7,6 +7,7 @@
"location": "Location",
"age": "Age",
"joined": "Joined",
"lastonline": "Last Online",
"profile_views": "Profile views",
"reputation": "Reputation",
"posts": "Posts",

View File

@@ -178,17 +178,6 @@ var socket,
return text.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
};
// Willingly stolen from: http://phpjs.org/functions/strip_tags/
app.strip_tags = function (input, allowed) {
allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
return input.replace(commentsAndPhpTags, '').replace(tags, function ($0, $1) {
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
};
// use unique alert_id to have multiple alerts visible at a time, use the same alert_id to fade out the current instance
// type : error, success, info, warning/notify
// title = bolded title text

View File

@@ -95,7 +95,7 @@ define(['forum/accountheader', 'uploader'], function(header, uploader) {
$('#uploadPictureBtn').on('click', function() {
$('#change-picture-modal').modal('hide');
uploader.open(RELATIVE_PATH + '/user/uploadpicture', function(imageUrlOnServer) {
uploader.open(RELATIVE_PATH + '/user/uploadpicture', {}, function(imageUrlOnServer) {
imageUrlOnServer = imageUrlOnServer + '?' + new Date().getTime();
$('#user-current-picture').attr('src', imageUrlOnServer);

View File

@@ -183,8 +183,8 @@ define(['uploader'], function(uploader) {
$('.upload-button').on('click', function() {
var inputEl = this;
uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', function(imageUrlOnServer) {
var cid = $(this).parents('li[data-cid]').attr('data-cid');
uploader.open(RELATIVE_PATH + '/admin/category/uploadpicture', {cid:cid}, function(imageUrlOnServer) {
inputEl.value = imageUrlOnServer;
$(inputEl).parents('li[data-cid]').find('.preview-box').css('background', 'url(' + imageUrlOnServer + '?' + new Date().getTime() + ')');
modified(inputEl);
@@ -270,7 +270,7 @@ define(['uploader'], function(uploader) {
liEl = document.createElement('li');
var numResults = results.length,
resultObj;
for(var x=0;x<numResults;x++) {
resultObj = results[x];
liEl.setAttribute('data-gid', resultObj.gid);
@@ -281,13 +281,13 @@ define(['uploader'], function(uploader) {
'</div>' +
'</div>' +
' '+resultObj.name;
groupsFrag.appendChild(liEl.cloneNode(true));
}
groupsResultsEl.html(groupsFrag);
});
groupsResultsEl.off().on('click', '[data-gpriv]', function(e) {
var btnEl = $(this),
gid = btnEl.parents('li[data-gid]').attr('data-gid'),

View File

@@ -75,7 +75,7 @@ define(['uploader'], function(uploader) {
});
$('#uploadLogoBtn').on('click', function() {
uploader.open(RELATIVE_PATH + '/admin/uploadlogo', function(image) {
uploader.open(RELATIVE_PATH + '/admin/uploadlogo', {}, function(image) {
$('#logoUrl').val(image);
});
@@ -83,7 +83,7 @@ define(['uploader'], function(uploader) {
});
$('#uploadFaviconBtn').on('click', function() {
uploader.open(RELATIVE_PATH + '/admin/uploadfavicon', function(icon) {
uploader.open(RELATIVE_PATH + '/admin/uploadfavicon', {}, function(icon) {
$('#faviconUrl').val(icon);
});

View File

@@ -19,7 +19,7 @@ define(function() {
return parent.attr('data-uid');
}
function updateUserButtons() {
function updateUserBanButtons() {
jQuery('.ban-btn').each(function(index, element) {
var banBtn = $(element);
var uid = getUID(banBtn);
@@ -27,15 +27,37 @@ define(function() {
banBtn.addClass('disabled');
else if (isUserBanned(banBtn))
banBtn.addClass('btn-warning');
else if (!isUserAdmin(banBtn))
banBtn.removeClass('disabled');
else
banBtn.removeClass('btn-warning');
updateUserAdminButtons();
});
}
function updateUserAdminButtons() {
jQuery('.admin-btn').each(function(index, element) {
var adminBtn = $(element);
var uid = getUID(adminBtn);
if (isUserAdmin(adminBtn)) {
adminBtn.attr('value', 'UnMake Admin').html('Remove Admin');
if (uid === yourid) {
adminBtn.addClass('disabled');
}
}
else if (isUserBanned(adminBtn))
adminBtn.addClass('disabled');
else if (!isUserBanned(adminBtn))
adminBtn.removeClass('disabled');
else
adminBtn.removeClass('btn-warning');
});
}
function initUsers() {
updateUserButtons();
updateUserBanButtons();
updateUserAdminButtons();
$('#users-container').on('click', '.ban-btn', function() {
var banBtn = $(this);
@@ -49,17 +71,56 @@ define(function() {
socket.emit('api:admin.user.unbanUser', uid);
banBtn.removeClass('btn-warning');
parent.attr('data-banned', 0);
updateUserAdminButtons();
} else {
bootbox.confirm('Do you really want to ban "' + parent.attr('data-username') + '"?', function(confirm) {
if (confirm) {
socket.emit('api:admin.user.banUser', uid);
banBtn.addClass('btn-warning');
parent.attr('data-banned', 1);
updateUserAdminButtons();
}
});
}
}
return false;
});
$('#users-container').on('click', '.admin-btn', function() {
var adminBtn = $(this);
var isAdmin = isUserAdmin(adminBtn);
var parent = adminBtn.parents('.users-box');
var isBanned = isUserBanned(adminBtn);
var uid = getUID(adminBtn);
if(uid === yourid){
app.alert({
title: 'Error',
message: 'You can\'t remove yourself as Administrator!',
type: 'danger',
timeout: 5000
});
}
else if (!isAdmin) {
socket.emit('api:admin.user.makeAdmin', uid);
adminBtn.attr('value', 'UnMake Admin').html('Remove Admin');
parent.attr('data-admin', 1);
updateUserBanButtons();
} else if(uid !== yourid) {
bootbox.confirm('Do you really want to remove this user as admin "' + parent.attr('data-username') + '"?', function(confirm) {
if (confirm) {
socket.emit('api:admin.user.removeAdmin', uid);
adminBtn.attr('value', 'Make Admin').html('Make Admin');
parent.attr('data-admin', 0);
updateUserBanButtons();
}
});
}
return false;
});
}

View File

@@ -1,7 +1,7 @@
define(function() {
var Login = {};
Login.init = function() {
Login.init = function() {
$('#login').on('click', function() {
var loginData = {
'username': $('#username').val(),
@@ -40,8 +40,7 @@ define(function() {
$('#login').removeAttr('disabled').html('Login');
},
dataType: 'json',
async: true,
timeout: 2000
async: true
});
return false;

View File

@@ -334,13 +334,13 @@ define(['composer'], function(composer) {
return false;
});
$('#post-container').delegate('.edit', 'click', function(e) {
$('#post-container').on('click', '.edit', function(e) {
var pid = $(this).parents('li').attr('data-pid');
composer.editPost(pid);
});
$('#post-container').delegate('.delete', 'click', function(e) {
$('#post-container').on('click', '.delete', function(e) {
var pid = $(this).parents('li').attr('data-pid'),
postEl = $(document.querySelector('#post-container li[data-pid="' + pid + '"]')),
deleteAction = !postEl.hasClass('deleted') ? true : false,
@@ -369,11 +369,27 @@ define(['composer'], function(composer) {
}
});
$('#post-container').on('click', '.fork-post', function(e) {
var post = $(this).parents('li'),
pid = post.attr('data-pid');
socket.emit('api:topic.createTopicFromPost', {pid:pid}, function(err) {
if(err) {
return app.alertError(err.message);
}
post.fadeOut(500, function() {
post.remove();
});
});
});
$('#post-container').on('click', '.chat', function(e) {
var username = $(this).parents('li.row').attr('data-username');
var touid = $(this).parents('li.row').attr('data-uid');
app.openChat(username, touid);
$(this).parents('.btn-group').find('.dropdown-toggle').click();
return false;
});
ajaxify.register_events([

View File

@@ -71,6 +71,7 @@ define(function() {
});
function onTopicsLoaded(topics) {
var html = templates.prepare(templates['unread'].blocks['topics']).parse({
topics: topics
});

View File

@@ -1,4 +1,4 @@
define(['taskbar'], function(taskbar) {
define(['taskbar', 'string'], function(taskbar, S) {
var module = {};
@@ -92,7 +92,6 @@ define(['taskbar'], function(taskbar) {
module.center = function(chatModal) {
chatModal.css("position", "fixed");
chatModal.css("top", "100px");
chatModal.css("left", Math.max(0, (($(window).width() - $(chatModal).outerWidth()) / 2) + $(window).scrollLeft()) + "px");
return chatModal;
}
@@ -103,6 +102,7 @@ define(['taskbar'], function(taskbar) {
module.bringModalToTop(chatModal);
checkOnlineStatus(chatModal);
taskbar.updateActive(uuid);
scrollToBottom(chatModal.find('#chat-content'));
chatModal.find('#chat-message-input').focus();
}
@@ -139,7 +139,7 @@ define(['taskbar'], function(taskbar) {
}
function sendMessage(chatModal) {
var msg = app.strip_tags(chatModal.find('#chat-message-input').val());
var msg = S(chatModal.find('#chat-message-input').val()).stripTags().s;
if(msg.length) {
msg = msg +'\n';
socket.emit('api:chats.send', { touid:chatModal.touid, message:msg});
@@ -153,10 +153,14 @@ define(['taskbar'], function(taskbar) {
var date = new Date(parseInt(timestamp, 10));
chatContent.append('[' + date.toLocaleTimeString() + '] ' + message);
scrollToBottom(chatContent);
};
function scrollToBottom(chatContent) {
chatContent.scrollTop(
chatContent[0].scrollHeight - chatContent.height()
);
};
}
module.toggleNew = function(uuid, state) {
taskbar.toggleNew(uuid, state);

View File

@@ -48,7 +48,6 @@ define(['taskbar'], function(taskbar) {
socket.emit('api:composer.push', {
pid: pid
}, function(threadData) {
console.log(threadData);
push({
pid: pid,
title: threadData.title,
@@ -95,9 +94,8 @@ define(['taskbar'], function(taskbar) {
var postContainer = $(composerTemplate[0]);
if(config.imgurClientIDSet) {
if(config.allowFileUploads || config.imgurClientIDSet)
initializeFileReader(post_uuid);
}
var postData = composer.posts[post_uuid],
titleEl = postContainer.find('.title'),
@@ -202,7 +200,7 @@ define(['taskbar'], function(taskbar) {
}
});
postContainer.on('click', '.formatting-bar span .fa-picture-o', function() {
postContainer.on('click', '.formatting-bar span .fa-picture-o, .formatting-bar span .fa-upload', function() {
$('#files').click();
});
@@ -213,6 +211,7 @@ define(['taskbar'], function(taskbar) {
loadFile(post_uuid, files[i]);
}
}
$('#fileForm')[0].reset();
});
@@ -317,7 +316,12 @@ define(['taskbar'], function(taskbar) {
}
if(config.imgurClientIDSet) {
postContainer.find('.upload-instructions').removeClass('hide')
postContainer.find('.upload-instructions').removeClass('hide');
postContainer.find('.img-upload-btn').removeClass('hide');
}
if(config.allowFileUploads) {
postContainer.find('.file-upload-btn').removeClass('hide');
}
postContainer.css('visibility', 'visible');
@@ -340,6 +344,7 @@ define(['taskbar'], function(taskbar) {
}
}
composer.post = function(post_uuid) {
var postData = composer.posts[post_uuid],
postContainer = $('#cmp-uuid-' + post_uuid),
@@ -350,33 +355,13 @@ define(['taskbar'], function(taskbar) {
bodyEl.val(bodyEl.val().trim());
if(postData.uploadsInProgress && postData.uploadsInProgress.length) {
return app.alert({
type: 'warning',
timeout: 2000,
title: 'Still uploading',
message: "Please wait for uploads to complete.",
alert_id: 'post_error'
});
}
if (titleEl.val().length < config.minimumTitleLength) {
return app.alert({
type: 'danger',
timeout: 2000,
title: 'Title too short',
message: "Please enter a longer title. At least " + config.minimumTitleLength+ " characters.",
alert_id: 'post_error'
});
}
if (bodyEl.val().length < config.minimumPostLength) {
return app.alert({
type: 'danger',
timeout: 2000,
title: 'Content too short',
message: "Please enter a longer post. At least " + config.minimumPostLength + " characters.",
alert_id: 'post_error'
});
return composerAlert('Still uploading', 'Please wait for uploads to complete.');
} else if (titleEl.val().length < parseInt(config.minimumTitleLength, 10)) {
return composerAlert('Title too short', 'Please enter a longer title. At least ' + config.minimumTitleLength+ ' characters.');
} else if (titleEl.val().length > parseInt(config.maximumTitleLength, 10)) {
return composerAlert('Title too long', 'Please enter a shorter title. Titles can\'t be longer than ' + config.maximumTitleLength + ' characters.');
} else if (bodyEl.val().length < parseInt(config.minimumPostLength, 10)) {
return composerAlert('Content too short', 'Please enter a longer post. At least ' + config.minimumPostLength + ' characters.');
}
// Still here? Let's post.
@@ -402,6 +387,17 @@ define(['taskbar'], function(taskbar) {
composer.discard(post_uuid);
}
function composerAlert(title, message) {
app.alert({
type: 'danger',
timeout: 2000,
title: title,
message: message,
alert_id: 'post_error'
});
}
composer.discard = function(post_uuid) {
if (composer.posts[post_uuid]) {
$('#cmp-uuid-' + post_uuid).remove();
@@ -477,36 +473,40 @@ define(['taskbar'], function(taskbar) {
}
function loadFile(post_uuid, file) {
if (!file.type.match('image.*')) {
return;
}
var reader = new FileReader(),
dropDiv = $('#cmp-uuid-' + post_uuid).find('.imagedrop');
$(reader).on('loadend', function(e) {
var bin = this.result.split(',')[1];
var regex = /^data:.*;base64,(.*)$/;
var matches = this.result.match(regex);
var img = {
var fileData = {
name: file.name,
data: bin
data: matches[1]
};
createImagePlaceholder(post_uuid, img);
dropDiv.hide();
if(file.type.match('image.*')) {
uploadFile('api:posts.uploadImage', post_uuid, fileData);
} else {
if(file.size > parseInt(config.maximumFileSize, 10) * 1024) {
return composerAlert('File too big', 'Maximum allowed file size is ' + config.maximumFileSize + 'kbs');
}
uploadFile('api:posts.uploadFile', post_uuid, fileData);
}
});
reader.readAsDataURL(file);
}
function createImagePlaceholder(post_uuid, img) {
var postContainer = $('#cmp-uuid-' + post_uuid),
function uploadFile(method, post_uuid, img) {
var linkStart = method === 'api:posts.uploadImage' ? '!' : '',
postContainer = $('#cmp-uuid-' + post_uuid),
textarea = postContainer.find('textarea'),
text = textarea.val(),
imgText = "![" + img.name + "](uploading...)";
imgText = linkStart + '[' + img.name + '](uploading...)';
text += imgText;
textarea.val(text + " ");
@@ -517,18 +517,17 @@ define(['taskbar'], function(taskbar) {
composer.posts[post_uuid].uploadsInProgress.push(1);
socket.emit("api:posts.uploadImage", img, function(err, data) {
socket.emit(method, img, function(err, data) {
var currentText = textarea.val();
if(err) {
textarea.val(currentText.replace(imgText, linkStart + '[' + img.name + '](upload error)'));
return app.alertError(err.message);
}
var currentText = textarea.val();
imgText = "![" + data.name + "](uploading...)";
if(!err) {
textarea.val(currentText.replace(imgText, "![" + data.name + "](" + data.url + ")"));
} else {
textarea.val(currentText.replace(imgText, "![" + data.name + "](upload error)"));
}
textarea.val(currentText.replace(imgText, linkStart + '[' + data.name + '](' + data.url + ')'));
composer.posts[post_uuid].uploadsInProgress.pop();
});
}

File diff suppressed because one or more lines are too long

View File

@@ -2,12 +2,13 @@ define(function() {
var module = {};
module.open = function(route, callback) {
module.open = function(route, params, callback) {
$('#upload-picture-modal').modal('show').removeClass('hide');
module.hideAlerts();
$('#uploadForm')[0].reset();
$('#uploadForm').attr('action', route);
$('#uploadForm').find('#params').val(JSON.stringify(params));
$('#pictureUploadSubmitBtn').off('click').on('click', function() {
$('#uploadForm').submit();

View File

@@ -48,7 +48,7 @@
}
};
templates.prepare = function (raw_tpl, data) {
templates.prepare = function (raw_tpl) {
var template = {};
template.html = raw_tpl;
template.parse = parse;
@@ -78,7 +78,9 @@
global.templates[file] = new template;
loaded--;
if (loaded == 0) templates.ready();
if (loaded === 0) {
templates.ready();
}
});
}(templatesToLoad[t]));
}
@@ -347,7 +349,9 @@
if (blockInfo) {
checkConditional('@first', blockInfo.iterator === 0);
checkConditional('!@first', blockInfo.iterator !== 0);
checkConditional('@last', blockInfo.iterator === blockInfo.total);
checkConditional('!@last', blockInfo.iterator !== blockInfo.total);
}
template = replace(namespace + d, data[d], template);

View File

@@ -1,10 +1,11 @@
(function(module) {
'use strict';
var utils, fs;
var utils, fs, XRegExp;
if ('undefined' === typeof window) {
fs = require('fs');
XRegExp = require('xregexp').XRegExp;
}
@@ -92,19 +93,13 @@
//http://dense13.com/blog/2009/05/03/converting-string-to-slug-javascript/
slugify: function(str) {
var invalidChars = XRegExp('[^\\p{L} 0-9\-]', 'g');
str = str.replace(/^\s+|\s+$/g, ''); // trim
str = str.toLowerCase();
// remove accents, swap ñ for n, etc
var from = "àáäâèéëêìíïîıòóöôùúüûñçşğ·/_,:;";
var to = "aaaaeeeeiiiiioooouuuuncsg------";
for (var i = 0, l = from.length; i < l; i++) {
str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
}
str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
.replace(/\s+/g, '-') // collapse whitespace and replace by -
.replace(/-+/g, '-'); // collapse dashes
str = XRegExp.replace(str, invalidChars, '');
str = str.replace(/\s+/g, '-') // collapse whitespace and replace by -
str = str.replace(/-+/g, '-'); // collapse dashes
return str;
},
@@ -123,18 +118,6 @@
isPasswordValid: function(password) {
return password && password.indexOf(' ') === -1;
},
// Blatently stolen from: http://phpjs.org/functions/strip_tags/
'strip_tags': function(input, allowed) {
allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
return input.replace(commentsAndPhpTags, '').replace(tags, function($0, $1) {
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
});
},
buildMetaTags: function(tagsArr) {
var tags = '',
tag;

View File

@@ -70,6 +70,10 @@
<span class="timeago" title="{joindate}"></span>
<br/>
<span class="account-bio-label">[[user:lastonline]]</span>
<span class="timeago" title="{lastonline}"></span>
<br/>
<span class="account-bio-label">[[user:profile_views]]</span>
<span class="formatted-number">{profileviews}</span>
<br/>

View File

@@ -76,6 +76,21 @@
</div>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-xs-12">
<div class="form-group">
<label for="cid-{categories.cid}-class">Custom Class</label>
<input id="cid-{categories.cid}-class" type="text" class="form-control" placeholder="col-md-6 col-xs-6" data-name="class" value="{categories.class}" />
</div>
</div>
<div class="col-sm-4 col-xs-12">
<div class="form-group">
<label for="cid-{categories.cid}-numRecentReplies"># of Recent Replies Displayed</label>
<input id="cid-{categories.cid}-numRecentReplies" type="text" class="form-control" placeholder="2" data-name="numRecentReplies" value="{categories.numRecentReplies}" />
</div>
</div>
</div>
<input type="hidden" data-name="order" data-value="{categories.order}"></input>
</form>

View File

@@ -0,0 +1,5 @@
<h1>Events</h1>
<pre>
{eventdata}
</pre>

View File

@@ -17,6 +17,7 @@
<p class="help-block">You may only upload PNG, JPG, or GIF files under 256kb.</p>
</div>
<input id="imageUploadCsrf" type="hidden" name="_csrf" value="" />
<input type="hidden" id="params" name="params">
</form>
<div id="upload-progress-box" class="progress progress-striped">

View File

@@ -95,30 +95,29 @@
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">NodeBB</li>
<li class='active'>
<a href='{relative_path}/admin/index'><i class='fa fa-home'></i> Home</a>
</li>
<li><a href='{relative_path}/admin/categories/active'><i class='fa fa-folder'></i> Categories</a></li>
<li><a href='{relative_path}/admin/users/latest'><i class='fa fa-user'></i> Users</a></li>
<li><a href="{relative_path}/admin/groups"><i class="fa fa-group"></i> Groups</a></li>
<li><a href='{relative_path}/admin/topics'><i class='fa fa-book'></i> Topics</a></li>
<li><a href='{relative_path}/admin/themes'><i class='fa fa-th'></i> Themes</a></li>
<li><a href='{relative_path}/admin/plugins'><i class='fa fa-code-fork'></i> Plugins</a></li>
<li><a href='{relative_path}/admin/settings'><i class='fa fa-cogs'></i> Settings</a></li>
<li><a href='{relative_path}/admin/database'><i class='fa fa-hdd-o'></i> Database</a></li>
<li><a href='{relative_path}/admin/logger'><i class='fa fa-th'></i> Logger</a></li>
<li><a href="{relative_path}/admin/motd"><i class="fa fa-comment"></i> MOTD</a></li>
<li class="active"><a href="{relative_path}/admin/index"><i class="fa fa-fw fa-home"></i> Home</a></li>
<li><a href="{relative_path}/admin/categories/active"><i class="fa fa-fw fa-folder"></i> Categories</a></li>
<li><a href="{relative_path}/admin/users/latest"><i class="fa fa-fw fa-user"></i> Users</a></li>
<li><a href="{relative_path}/admin/groups"><i class="fa fa-fw fa-group"></i> Groups</a></li>
<li><a href="{relative_path}/admin/topics"><i class="fa fa-fw fa-book"></i> Topics</a></li>
<li><a href="{relative_path}/admin/themes"><i class="fa fa-fw fa-th"></i> Themes</a></li>
<li><a href="{relative_path}/admin/plugins"><i class="fa fa-fw fa-code-fork"></i> Plugins</a></li>
<li><a href="{relative_path}/admin/settings"><i class="fa fa-fw fa-cogs"></i> Settings</a></li>
<li><a href="{relative_path}/admin/database"><i class="fa fa-fw fa-hdd-o"></i> Database</a></li>
<li><a href="{relative_path}/admin/logger"><i class="fa fa-fw fa-th"></i> Logger</a></li>
<li><a href="{relative_path}/admin/motd"><i class="fa fa-fw fa-comment"></i> MOTD</a></li>
<li><a href="{relative_path}/admin/events"><i class="fa fa-fw fa-calendar-o"></i> Events</a></li>
</ul>
</div>
<div class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header">Social Authentication</li>
<li><a href='{relative_path}/admin/twitter'><i class='fa fa-twitter-square'></i> Twitter</a></li>
<li><a href='{relative_path}/admin/facebook'><i class='fa fa-facebook-square'></i> Facebook</a></li>
<li><a href='{relative_path}/admin/gplus'><i class='fa fa-google-plus-square'></i> Google+</a></li>
<li><a href="{relative_path}/admin/twitter"><i class="fa fa-fw fa-twitter-square"></i> Twitter</a></li>
<li><a href="{relative_path}/admin/facebook"><i class="fa fa-fw fa-facebook-square"></i> Facebook</a></li>
<li><a href="{relative_path}/admin/gplus"><i class="fa fa-fw fa-google-plus-square"></i> Google+</a></li>
<!-- BEGIN authentication -->
<li>
<a href='{relative_path}/admin{authentication.route}'><i class="fa {authentication.icon}"></i> {authentication.name}</a>
<a href="{relative_path}/admin{authentication.route}"><i class="fa fa-fw {authentication.icon}"></i> {authentication.name}</a>
</li>
<!-- END authentication -->
</ul>
@@ -128,7 +127,7 @@
<li class="nav-header">Plugins</li>
<!-- BEGIN plugins -->
<li>
<a href='{relative_path}/admin{plugins.route}'><i class="fa {plugins.icon}"></i> {plugins.name}</a>
<a href="{relative_path}/admin{plugins.route}"><i class="fa fa-fw {plugins.icon}"></i> {plugins.name}</a>
</li>
<!-- END plugins -->
</ul>
@@ -137,15 +136,15 @@
<ul class="nav nav-list">
<li class="nav-header">Unit Tests</li>
<ul class="nav nav-list">
<li><a href='{relative_path}/admin/testing/categories'>Categories</a></li>
<!--<li><a href='{relative_path}/admin/testing/topics'>Topics</a></li>
<li><a href='{relative_path}/admin/testing/posts'>Posts</a></li>
<li><a href='{relative_path}/admin/testing/accounts'>Accounts</a></li>
<li><a href='{relative_path}/admin/testing/chat'>Chat</a></li>
<li><a href='{relative_path}/admin/testing/notifications'>Notifications</a></li>
<li><a href='{relative_path}/admin/testing/friends'>Friends</a></li>
<li><a href='{relative_path}/admin/testing/feed'>RSS Feed</a></li>
<li><a href='{relative_path}/admin/testing/emails'>Emails</a></li>-->
<li><a href="{relative_path}/admin/testing/categories">Categories</a></li>
<!--<li><a href="{relative_path}/admin/testing/topics">Topics</a></li>
<li><a href="{relative_path}/admin/testing/posts">Posts</a></li>
<li><a href="{relative_path}/admin/testing/accounts">Accounts</a></li>
<li><a href="{relative_path}/admin/testing/chat">Chat</a></li>
<li><a href="{relative_path}/admin/testing/notifications">Notifications</a></li>
<li><a href="{relative_path}/admin/testing/friends">Friends</a></li>
<li><a href="{relative_path}/admin/testing/feed">RSS Feed</a></li>
<li><a href="{relative_path}/admin/testing/emails">Emails</a></li>-->
</ul>
</ul>
</div><!--/.well -->

View File

@@ -103,7 +103,9 @@
<div class="alert alert-warning">
<strong>Post Delay</strong><br /> <input type="text" class="form-control" value="10000" data-field="postDelay"><br />
<strong>Minimum Title Length</strong><br /> <input type="text" class="form-control" value="3" data-field="minimumTitleLength"><br />
<strong>Maximum Title Length</strong><br /> <input type="text" class="form-control" value="255" data-field="maximumTitleLength"><br />
<strong>Minimum Post Length</strong><br /> <input type="text" class="form-control" value="8" data-field="minimumPostLength"><br />
<strong>Chat Messages To Display</strong><br /> <input type="text" class="form-control" value="50" data-field="chatMessagesToDisplay"><br />
<div class="checkbox">
<label>
<input type="checkbox" data-field="allowGuestPosting"> <strong>Allow guests to post without logging in</strong>
@@ -119,6 +121,17 @@
<input type="checkbox" data-field="useOutgoingLinksPage"> <strong>Use Outgoing Links Warning Page</strong>
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" data-field="disableSocialButtons"> <strong>Disable social buttons</strong>
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" data-field="allowFileUploads"> <strong>Allow users to upload regular files</strong>
</label>
</div>
<strong>Maximum File Size</strong><br /> <input type="text" class="form-control" value="2048" data-field="maximumFileSize"><br />
</div>
</form>

View File

@@ -33,6 +33,9 @@
<i class='fa fa-pencil'></i>
<span id='postcount'>{users.postcount}</span>
</div>
<div>
<a href="#" class="btn btn-default admin-btn">Make Admin</a>
</div>
<div>
<a href="#" class="btn btn-default ban-btn">Ban</a>
</div>

View File

@@ -10,12 +10,13 @@
<div>
<button id="new_post" class="btn btn-primary {show_topic_button}">[[category:new_topic_button]]</button>
<!-- IF !disableSocialButtons -->
<div class="inline-block pull-right">
<a href="#" id="facebook-share"><i class="fa fa-facebook-square fa-2x"></i></a>&nbsp;
<a href="#" id="twitter-intent"><i class="fa fa-twitter-square fa-2x"></i></a>&nbsp;
<a href="#" id="google-share"><i class="fa fa-google-plus-square fa-2x"></i></a>&nbsp;
</div>
<!-- ENDIF !disableSocialButtons -->
</div>
<hr/>

View File

@@ -7,10 +7,15 @@
<span class="btn btn-link" tabindex="-1"><i class="fa fa-italic"></i></span>
<span class="btn btn-link" tabindex="-1"><i class="fa fa-list"></i></span>
<span class="btn btn-link" tabindex="-1"><i class="fa fa-link"></i></span>
<span class="btn btn-link" tabindex="-1">
<input type="file" id="files" name="files[]" multiple class="hide"/>
<span class="btn btn-link img-upload-btn hide" tabindex="-1">
<i class="fa fa-picture-o"></i>
</span>
<span class="btn btn-link file-upload-btn hide" tabindex="-1">
<i class="fa fa-upload"></i>
</span>
<form id="fileForm">
<input type="file" id="files" name="files[]" multiple class="hide"/>
</form>
</div>
<!-- <div class="btn btn-link pull-right">Preview</div> -->
</div>

View File

@@ -5,6 +5,7 @@
"^admin/categories.*": "admin/categories",
"^admin/users.*": "admin/users",
"^admin/database.*": "admin/database",
"^admin/events.*": "admin/events",
"^admin/index.*": "admin/index",
"^admin/themes.*": "admin/themes",
"^admin/plugins/?$": "admin/plugins",

View File

@@ -18,14 +18,15 @@
<img title="{posts.username}" class="img-rounded user-img" src="{posts.picture}">
</a>
<a href="../../topic/{posts.tid}/#{posts.pid}">
<a href="../../user/{posts.userslug}">
<strong><span>{posts.username}</span></strong>
<p>{posts.content}</p>
</a>
<p>{posts.content}</p>
<div>
<span class="pull-right">
posted in
<a href="../../topic/{posts.tid}/#{posts.pid}">posted</a>
in
<a href="../../category/{posts.categorySlug}">
<i class="fa {posts.categoryIcon}"></i> {posts.categoryName}
</a>

View File

@@ -2,12 +2,12 @@
</div><!--END container -->
<div id="chat-modal" class="modal chat-modal" tabindex="-1" role="dialog" aria-labelledby="Chat" aria-hidden="true" data-backdrop="none">
<div id="chat-modal" class="modal chat-modal col-lg-12 col-md-12" tabindex="-1" role="dialog" aria-labelledby="Chat" aria-hidden="true" data-backdrop="none">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3 id="myModalLabel">[[footer:chat.chatting_with]]</h3>
<h4 id="myModalLabel">[[footer:chat.chatting_with]]</h4>
</div>
<div class="modal-body">
<textarea class="form-control" id="chat-content" cols="40" rows="10" readonly></textarea><br/>
@@ -36,6 +36,7 @@
<p class="help-block">[[user:image_spec]]</p>
</div>
<input id="imageUploadCsrf" type="hidden" name="_csrf" value="" />
<input type="hidden" id="params" name="params">
</form>
<div id="upload-progress-box" class="progress progress-striped">

View File

@@ -4,7 +4,7 @@
<div class="row home" itemscope itemtype="http://www.schema.org/ItemList">
<!-- BEGIN categories -->
<div class="col-md-3 col-xs-6">
<div class="{categories.class}">
<a href="category/{categories.slug}" itemprop="url">
<meta itemprop="name" content="{categories.name}">
<h4><span class="badge {categories.badgeclass}">{categories.topic_count} </span> {categories.name}</h4>

View File

@@ -1,6 +1,6 @@
<ol class="breadcrumb">
<li><a href="/">Home</a></li>
<li class="active">Recent <a href="./recent.rss"><i class="fa fa-rss-square"></i></a></li>
<li class="active">Recent <a href="/recent.rss"><i class="fa fa-rss-square"></i></a></li>
</ol>
<ul class="nav nav-pills">

View File

@@ -60,7 +60,7 @@
<ul class="dropdown-menu">
<li><a href="/user/{posts.userslug}"><i class="fa fa-user"></i> [[topic:profile]]</a></li>
<li><div class="chat"><i class="fa fa-comment"></i> [[topic:chat]]</div></li>
<li><a href="#" class="chat"><i class="fa fa-comment"></i> [[topic:chat]]</a></li>
</ul>
</div>
@@ -86,15 +86,20 @@
<div class="pull-right">
<div class="btn-group post-tools">
<button class="btn btn-sm btn-default link" type="button" title="[[topic:link]]"><i class="fa fa-link"></i></button>
<!-- IF !disableSocialButtons -->
<button class="btn btn-sm btn-default facebook-share" type="button" title=""><i class="fa fa-facebook"></i></button>
<button class="btn btn-sm btn-default twitter-share" type="button" title=""><i class="fa fa-twitter"></i></button>
<button class="btn btn-sm btn-default google-share" type="button" title=""><i class="fa fa-google-plus"></i></button>
<!-- ENDIF !disableSocialButtons -->
</div>
<!-- IF posts.display_moderator_tools -->
<div class="btn-group post-tools">
<button class="btn btn-sm btn-default edit" type="button" title="[[topic:edit]]"><i class="fa fa-pencil"></i></button>
<button class="btn btn-sm btn-default delete" type="button" title="[[topic:delete]]"><i class="fa fa-trash-o"></i></button>
<!-- IF !@first -->
<button class="btn btn-sm btn-default fork-post" type="button" title="[[topic:fork]]"><i class="fa fa-code-fork"></i></button>
<!-- ENDIF !@first -->
</div>
<!-- ENDIF posts.display_moderator_tools -->
</div>

View File

@@ -0,0 +1,239 @@
/*!
* XRegExp Unicode Base 3.0.0-pre
* <http://xregexp.com/>
* Steven Levithan <20> 2008-2012 MIT License
* Uses Unicode 6.2.0 <http://unicode.org/>
* Unicode data generated by Mathias Bynens <http://mathiasbynens.be/>
*/
/**
* Adds support for the `\p{L}` or `\p{Letter}` Unicode category. Addon packages for other Unicode
* categories, scripts, blocks, and properties are available separately. Also adds flag A (astral),
* which enables 21-bit Unicode support. All Unicode tokens can be inverted using `\P{..}` or
* `\p{^..}`. Token names ignore case, spaces, hyphens, and underscores.
* @requires XRegExp
*/
(function(XRegExp) {
'use strict';
// Storage for Unicode data
var unicode = {};
/* ==============================
* Private functions
* ============================== */
// Generates a token lookup name: lowercase, with hyphens, spaces, and underscores removed
function normalize(name) {
return name.replace(/[- _]+/g, '').toLowerCase();
}
// Adds leading zeros if shorter than four characters
function pad4(str) {
while (str.length < 4) {
str = '0' + str;
}
return str;
}
// Converts a hexadecimal number to decimal
function dec(hex) {
return parseInt(hex, 16);
}
// Converts a decimal number to hexadecimal
function hex(dec) {
return parseInt(dec, 10).toString(16);
}
// Gets the decimal code of a literal code unit, \xHH, \uHHHH, or a backslash-escaped literal
function charCode(chr) {
var esc = /^\\[xu](.+)/.exec(chr);
return esc ?
dec(esc[1]) :
chr.charCodeAt(chr.charAt(0) === '\\' ? 1 : 0);
}
// Inverts a list of ordered BMP characters and ranges
function invertBmp(range) {
var output = '',
lastEnd = -1,
start;
XRegExp.forEach(range, /(\\x..|\\u....|\\?[\s\S])(?:-(\\x..|\\u....|\\?[\s\S]))?/, function(m) {
start = charCode(m[1]);
if (start > (lastEnd + 1)) {
output += '\\u' + pad4(hex(lastEnd + 1));
if (start > (lastEnd + 2)) {
output += '-\\u' + pad4(hex(start - 1));
}
}
lastEnd = charCode(m[2] || m[1]);
});
if (lastEnd < 0xFFFF) {
output += '\\u' + pad4(hex(lastEnd + 1));
if (lastEnd < 0xFFFE) {
output += '-\\uFFFF';
}
}
return output;
}
// Generates an inverted BMP range on first use
function cacheInvertedBmp(slug) {
var prop = 'b!';
return unicode[slug][prop] || (
unicode[slug][prop] = invertBmp(unicode[slug].bmp)
);
}
// Combines and optionally negates BMP and astral data
function buildAstral(slug, isNegated) {
var item = unicode[slug],
combined = '';
if (item.bmp && !item.isBmpLast) {
combined = '[' + item.bmp + ']' + (item.astral ? '|' : '');
}
if (item.astral) {
combined += item.astral;
}
if (item.isBmpLast && item.bmp) {
combined += (item.astral ? '|' : '') + '[' + item.bmp + ']';
}
// Astral Unicode tokens always match a code point, never a code unit
return isNegated ?
'(?:(?!' + combined + ')(?:[\uD800-\uDBFF][\uDC00-\uDFFF]|[\0-\uFFFF]))' :
'(?:' + combined + ')';
}
// Builds a complete astral pattern on first use
function cacheAstral(slug, isNegated) {
var prop = isNegated ? 'a!' : 'a=';
return unicode[slug][prop] || (
unicode[slug][prop] = buildAstral(slug, isNegated)
);
}
/* ==============================
* Core functionality
* ============================== */
/* Add Unicode token syntax: \p{..}, \P{..}, \p{^..}. Also add astral mode (flag A).
*/
XRegExp.addToken(
// Use `*` instead of `+` to avoid capturing `^` as the token name in `\p{^}`
/\\([pP])(?:{(\^?)([^}]*)}|([A-Za-z]))/,
function(match, scope, flags) {
var ERR_DOUBLE_NEG = 'Invalid double negation ',
ERR_UNKNOWN_NAME = 'Unknown Unicode token ',
ERR_UNKNOWN_REF = 'Unicode token missing data ',
ERR_ASTRAL_ONLY = 'Astral mode required for Unicode token ',
ERR_ASTRAL_IN_CLASS = 'Astral mode does not support Unicode tokens within character classes',
// Negated via \P{..} or \p{^..}
isNegated = match[1] === 'P' || !!match[2],
// Switch from BMP (U+FFFF) to astral (U+10FFFF) mode via flag A or implicit opt-in
isAstralMode = flags.indexOf('A') > -1 || XRegExp.isInstalled('astral'),
// Token lookup name. Check `[4]` first to avoid passing `undefined` via `\p{}`
slug = normalize(match[4] || match[3]),
// Token data object
item = unicode[slug];
if (match[1] === 'P' && match[2]) {
throw new SyntaxError(ERR_DOUBLE_NEG + match[0]);
}
if (!unicode.hasOwnProperty(slug)) {
throw new SyntaxError(ERR_UNKNOWN_NAME + match[0]);
}
// Switch to the negated form of the referenced Unicode token
if (item.inverseOf) {
slug = normalize(item.inverseOf);
if (!unicode.hasOwnProperty(slug)) {
throw new ReferenceError(ERR_UNKNOWN_REF + match[0] + ' -> ' + item.inverseOf);
}
item = unicode[slug];
isNegated = !isNegated;
}
if (!(item.bmp || isAstralMode)) {
throw new SyntaxError(ERR_ASTRAL_ONLY + match[0]);
}
if (isAstralMode) {
if (scope === 'class') {
throw new SyntaxError(ERR_ASTRAL_IN_CLASS);
}
return cacheAstral(slug, isNegated);
}
return scope === 'class' ?
(isNegated ? cacheInvertedBmp(slug) : item.bmp) :
(isNegated ? '[^' : '[') + item.bmp + ']';
},
{
scope: 'all',
optionalFlags: 'A'
}
);
/**
* Adds to the list of Unicode tokens that XRegExp regexes can match via `\p` or `\P`.
* @memberOf XRegExp
* @param {Array} data Objects with named character ranges. Each object may have properties `name`,
* `alias`, `isBmpLast`, `inverseOf`, `bmp`, and `astral`. All but `name` are optional, although
* one of `bmp` or `astral` is required (unless `inverseOf` is set). If `astral` is absent, the
* `bmp` data is used for BMP and astral modes. If `bmp` is absent, the name errors in BMP mode
* but works in astral mode. If both `bmp` and `astral` are provided, the `bmp` data only is used
* in BMP mode, and the combination of `bmp` and `astral` data is used in astral mode.
* `isBmpLast` is needed when a token matches orphan high surrogates *and* uses surrogate pairs
* to match astral code points. The `bmp` and `astral` data should be a combination of literal
* characters and `\xHH` or `\uHHHH` escape sequences, with hyphens to create ranges. Any regex
* metacharacters in the data should be escaped, apart from range-creating hyphens. The `astral`
* data can additionally use character classes and alternation, and should use surrogate pairs to
* represent astral code points. `inverseOf` can be used to avoid duplicating character data if a
* Unicode token is defined as the exact inverse of another token.
* @example
*
* // Basic use
* XRegExp.addUnicodeData([{
* name: 'XDigit',
* alias: 'Hexadecimal',
* bmp: '0-9A-Fa-f'
* }]);
* XRegExp('\\p{XDigit}:\\p{Hexadecimal}+').test('0:3D'); // -> true
*/
XRegExp.addUnicodeData = function(data) {
var ERR_NO_NAME = 'Unicode token requires name',
ERR_NO_DATA = 'Unicode token has no character data ',
item,
i;
for (i = 0; i < data.length; ++i) {
item = data[i];
if (!item.name) {
throw new Error(ERR_NO_NAME);
}
if (!(item.inverseOf || item.bmp || item.astral)) {
throw new Error(ERR_NO_DATA + item.name);
}
unicode[normalize(item.name)] = item;
if (item.alias) {
unicode[normalize(item.alias)] = item;
}
}
// Reset the pattern cache used by the `XRegExp` constructor, since the same pattern and
// flags might now produce different results
XRegExp.cache.flush('patterns');
};
/* Add data for the Unicode `L` or `Letter` category. Separate addons are available that add other
* categories, scripts, blocks, and properties.
*/
XRegExp.addUnicodeData([{
name: 'L',
alias: 'Letter',
bmp: 'A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC',
astral: '\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72]|\uD801[\uDC00-\uDC9D]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1E\uDF30-\uDF40\uDF42-\uDF49\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD81A[\uDC00-\uDE38]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD83-\uDDB2\uDDC1-\uDDC4]|\uD86E[\uDC00-\uDC1D]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD803[\uDC00-\uDC48]|\uD80D[\uDC00-\uDC2E]|\uD805[\uDE80-\uDEAA]|\uD87E[\uDC00-\uDE1D]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD82C[\uDC00\uDC01]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD808[\uDC00-\uDF6E]'
}]);
}(XRegExp));

View File

@@ -0,0 +1,904 @@
/*!
* XRegExp Unicode Blocks 3.0.0-pre
* <http://xregexp.com/>
* Steven Levithan <20> 2010-2012 MIT License
* Uses Unicode 6.2.0 <http://unicode.org/>
* Unicode data generated by Mathias Bynens <http://mathiasbynens.be/>
*/
/**
* Adds support for all Unicode blocks. Block names use the prefix 'In'. E.g., `\p{InBasicLatin}`.
* Token names are case insensitive, and any spaces, hyphens, and underscores are ignored.
* @requires XRegExp, Unicode Base
*/
(function(XRegExp) {
'use strict';
if (!XRegExp.addUnicodeData) {
throw new ReferenceError('Unicode Base must be loaded before Unicode Blocks');
}
XRegExp.addUnicodeData([
{
name: 'InAegean_Numbers',
astral: '\uD800[\uDD00-\uDD3F]'
},
{
name: 'InAlchemical_Symbols',
astral: '\uD83D[\uDF00-\uDF7F]'
},
{
name: 'InAlphabetic_Presentation_Forms',
bmp: '\uFB00-\uFB4F'
},
{
name: 'InAncient_Greek_Musical_Notation',
astral: '\uD834[\uDE00-\uDE4F]'
},
{
name: 'InAncient_Greek_Numbers',
astral: '\uD800[\uDD40-\uDD8F]'
},
{
name: 'InAncient_Symbols',
astral: '\uD800[\uDD90-\uDDCF]'
},
{
name: 'InArabic',
bmp: '\u0600-\u06FF'
},
{
name: 'InArabic_Extended_A',
bmp: '\u08A0-\u08FF'
},
{
name: 'InArabic_Mathematical_Alphabetic_Symbols',
astral: '\uD83B[\uDE00-\uDEFF]'
},
{
name: 'InArabic_Presentation_Forms_A',
bmp: '\uFB50-\uFDFF'
},
{
name: 'InArabic_Presentation_Forms_B',
bmp: '\uFE70-\uFEFF'
},
{
name: 'InArabic_Supplement',
bmp: '\u0750-\u077F'
},
{
name: 'InArmenian',
bmp: '\u0530-\u058F'
},
{
name: 'InArrows',
bmp: '\u2190-\u21FF'
},
{
name: 'InAvestan',
astral: '\uD802[\uDF00-\uDF3F]'
},
{
name: 'InBalinese',
bmp: '\u1B00-\u1B7F'
},
{
name: 'InBamum',
bmp: '\uA6A0-\uA6FF'
},
{
name: 'InBamum_Supplement',
astral: '\uD81A[\uDC00-\uDE3F]'
},
{
name: 'InBasic_Latin',
bmp: '\0-\x7F'
},
{
name: 'InBatak',
bmp: '\u1BC0-\u1BFF'
},
{
name: 'InBengali',
bmp: '\u0980-\u09FF'
},
{
name: 'InBlock_Elements',
bmp: '\u2580-\u259F'
},
{
name: 'InBopomofo',
bmp: '\u3100-\u312F'
},
{
name: 'InBopomofo_Extended',
bmp: '\u31A0-\u31BF'
},
{
name: 'InBox_Drawing',
bmp: '\u2500-\u257F'
},
{
name: 'InBrahmi',
astral: '\uD804[\uDC00-\uDC7F]'
},
{
name: 'InBraille_Patterns',
bmp: '\u2800-\u28FF'
},
{
name: 'InBuginese',
bmp: '\u1A00-\u1A1F'
},
{
name: 'InBuhid',
bmp: '\u1740-\u175F'
},
{
name: 'InByzantine_Musical_Symbols',
astral: '\uD834[\uDC00-\uDCFF]'
},
{
name: 'InCJK_Compatibility',
bmp: '\u3300-\u33FF'
},
{
name: 'InCJK_Compatibility_Forms',
bmp: '\uFE30-\uFE4F'
},
{
name: 'InCJK_Compatibility_Ideographs',
bmp: '\uF900-\uFAFF'
},
{
name: 'InCJK_Compatibility_Ideographs_Supplement',
astral: '\uD87E[\uDC00-\uDE1F]'
},
{
name: 'InCJK_Radicals_Supplement',
bmp: '\u2E80-\u2EFF'
},
{
name: 'InCJK_Strokes',
bmp: '\u31C0-\u31EF'
},
{
name: 'InCJK_Symbols_and_Punctuation',
bmp: '\u3000-\u303F'
},
{
name: 'InCJK_Unified_Ideographs',
bmp: '\u4E00-\u9FFF'
},
{
name: 'InCJK_Unified_Ideographs_Extension_A',
bmp: '\u3400-\u4DBF'
},
{
name: 'InCJK_Unified_Ideographs_Extension_B',
astral: '[\uD840-\uD868][\uDC00-\uDFFF]|\uD869[\uDC00-\uDEDF]'
},
{
name: 'InCJK_Unified_Ideographs_Extension_C',
astral: '\uD86D[\uDC00-\uDF3F]|[\uD86A-\uD86C][\uDC00-\uDFFF]|\uD869[\uDF00-\uDFFF]'
},
{
name: 'InCJK_Unified_Ideographs_Extension_D',
astral: '\uD86D[\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1F]'
},
{
name: 'InCarian',
astral: '\uD800[\uDEA0-\uDEDF]'
},
{
name: 'InChakma',
astral: '\uD804[\uDD00-\uDD4F]'
},
{
name: 'InCham',
bmp: '\uAA00-\uAA5F'
},
{
name: 'InCherokee',
bmp: '\u13A0-\u13FF'
},
{
name: 'InCombining_Diacritical_Marks',
bmp: '\u0300-\u036F'
},
{
name: 'InCombining_Diacritical_Marks_Supplement',
bmp: '\u1DC0-\u1DFF'
},
{
name: 'InCombining_Diacritical_Marks_for_Symbols',
bmp: '\u20D0-\u20FF'
},
{
name: 'InCombining_Half_Marks',
bmp: '\uFE20-\uFE2F'
},
{
name: 'InCommon_Indic_Number_Forms',
bmp: '\uA830-\uA83F'
},
{
name: 'InControl_Pictures',
bmp: '\u2400-\u243F'
},
{
name: 'InCoptic',
bmp: '\u2C80-\u2CFF'
},
{
name: 'InCounting_Rod_Numerals',
astral: '\uD834[\uDF60-\uDF7F]'
},
{
name: 'InCuneiform',
astral: '\uD808[\uDC00-\uDFFF]'
},
{
name: 'InCuneiform_Numbers_and_Punctuation',
astral: '\uD809[\uDC00-\uDC7F]'
},
{
name: 'InCurrency_Symbols',
bmp: '\u20A0-\u20CF'
},
{
name: 'InCypriot_Syllabary',
astral: '\uD802[\uDC00-\uDC3F]'
},
{
name: 'InCyrillic',
bmp: '\u0400-\u04FF'
},
{
name: 'InCyrillic_Extended_A',
bmp: '\u2DE0-\u2DFF'
},
{
name: 'InCyrillic_Extended_B',
bmp: '\uA640-\uA69F'
},
{
name: 'InCyrillic_Supplement',
bmp: '\u0500-\u052F'
},
{
name: 'InDeseret',
astral: '\uD801[\uDC00-\uDC4F]'
},
{
name: 'InDevanagari',
bmp: '\u0900-\u097F'
},
{
name: 'InDevanagari_Extended',
bmp: '\uA8E0-\uA8FF'
},
{
name: 'InDingbats',
bmp: '\u2700-\u27BF'
},
{
name: 'InDomino_Tiles',
astral: '\uD83C[\uDC30-\uDC9F]'
},
{
name: 'InEgyptian_Hieroglyphs',
astral: '\uD80C[\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2F]'
},
{
name: 'InEmoticons',
astral: '\uD83D[\uDE00-\uDE4F]'
},
{
name: 'InEnclosed_Alphanumeric_Supplement',
astral: '\uD83C[\uDD00-\uDDFF]'
},
{
name: 'InEnclosed_Alphanumerics',
bmp: '\u2460-\u24FF'
},
{
name: 'InEnclosed_CJK_Letters_and_Months',
bmp: '\u3200-\u32FF'
},
{
name: 'InEnclosed_Ideographic_Supplement',
astral: '\uD83C[\uDE00-\uDEFF]'
},
{
name: 'InEthiopic',
bmp: '\u1200-\u137F'
},
{
name: 'InEthiopic_Extended',
bmp: '\u2D80-\u2DDF'
},
{
name: 'InEthiopic_Extended_A',
bmp: '\uAB00-\uAB2F'
},
{
name: 'InEthiopic_Supplement',
bmp: '\u1380-\u139F'
},
{
name: 'InGeneral_Punctuation',
bmp: '\u2000-\u206F'
},
{
name: 'InGeometric_Shapes',
bmp: '\u25A0-\u25FF'
},
{
name: 'InGeorgian',
bmp: '\u10A0-\u10FF'
},
{
name: 'InGeorgian_Supplement',
bmp: '\u2D00-\u2D2F'
},
{
name: 'InGlagolitic',
bmp: '\u2C00-\u2C5F'
},
{
name: 'InGothic',
astral: '\uD800[\uDF30-\uDF4F]'
},
{
name: 'InGreek_Extended',
bmp: '\u1F00-\u1FFF'
},
{
name: 'InGreek_and_Coptic',
bmp: '\u0370-\u03FF'
},
{
name: 'InGujarati',
bmp: '\u0A80-\u0AFF'
},
{
name: 'InGurmukhi',
bmp: '\u0A00-\u0A7F'
},
{
name: 'InHalfwidth_and_Fullwidth_Forms',
bmp: '\uFF00-\uFFEF'
},
{
name: 'InHangul_Compatibility_Jamo',
bmp: '\u3130-\u318F'
},
{
name: 'InHangul_Jamo',
bmp: '\u1100-\u11FF'
},
{
name: 'InHangul_Jamo_Extended_A',
bmp: '\uA960-\uA97F'
},
{
name: 'InHangul_Jamo_Extended_B',
bmp: '\uD7B0-\uD7FF'
},
{
name: 'InHangul_Syllables',
bmp: '\uAC00-\uD7AF'
},
{
name: 'InHanunoo',
bmp: '\u1720-\u173F'
},
{
name: 'InHebrew',
bmp: '\u0590-\u05FF'
},
{
name: 'InHigh_Private_Use_Surrogates',
bmp: '\uDB80-\uDBFF'
},
{
name: 'InHigh_Surrogates',
bmp: '\uD800-\uDB7F'
},
{
name: 'InHiragana',
bmp: '\u3040-\u309F'
},
{
name: 'InIPA_Extensions',
bmp: '\u0250-\u02AF'
},
{
name: 'InIdeographic_Description_Characters',
bmp: '\u2FF0-\u2FFF'
},
{
name: 'InImperial_Aramaic',
astral: '\uD802[\uDC40-\uDC5F]'
},
{
name: 'InInscriptional_Pahlavi',
astral: '\uD802[\uDF60-\uDF7F]'
},
{
name: 'InInscriptional_Parthian',
astral: '\uD802[\uDF40-\uDF5F]'
},
{
name: 'InJavanese',
bmp: '\uA980-\uA9DF'
},
{
name: 'InKaithi',
astral: '\uD804[\uDC80-\uDCCF]'
},
{
name: 'InKana_Supplement',
astral: '\uD82C[\uDC00-\uDCFF]'
},
{
name: 'InKanbun',
bmp: '\u3190-\u319F'
},
{
name: 'InKangxi_Radicals',
bmp: '\u2F00-\u2FDF'
},
{
name: 'InKannada',
bmp: '\u0C80-\u0CFF'
},
{
name: 'InKatakana',
bmp: '\u30A0-\u30FF'
},
{
name: 'InKatakana_Phonetic_Extensions',
bmp: '\u31F0-\u31FF'
},
{
name: 'InKayah_Li',
bmp: '\uA900-\uA92F'
},
{
name: 'InKharoshthi',
astral: '\uD802[\uDE00-\uDE5F]'
},
{
name: 'InKhmer',
bmp: '\u1780-\u17FF'
},
{
name: 'InKhmer_Symbols',
bmp: '\u19E0-\u19FF'
},
{
name: 'InLao',
bmp: '\u0E80-\u0EFF'
},
{
name: 'InLatin_Extended_Additional',
bmp: '\u1E00-\u1EFF'
},
{
name: 'InLatin_Extended_A',
bmp: '\u0100-\u017F'
},
{
name: 'InLatin_Extended_B',
bmp: '\u0180-\u024F'
},
{
name: 'InLatin_Extended_C',
bmp: '\u2C60-\u2C7F'
},
{
name: 'InLatin_Extended_D',
bmp: '\uA720-\uA7FF'
},
{
name: 'InLatin_1_Supplement',
bmp: '\x80-\xFF'
},
{
name: 'InLepcha',
bmp: '\u1C00-\u1C4F'
},
{
name: 'InLetterlike_Symbols',
bmp: '\u2100-\u214F'
},
{
name: 'InLimbu',
bmp: '\u1900-\u194F'
},
{
name: 'InLinear_B_Ideograms',
astral: '\uD800[\uDC80-\uDCFF]'
},
{
name: 'InLinear_B_Syllabary',
astral: '\uD800[\uDC00-\uDC7F]'
},
{
name: 'InLisu',
bmp: '\uA4D0-\uA4FF'
},
{
name: 'InLow_Surrogates',
bmp: '\uDC00-\uDFFF'
},
{
name: 'InLycian',
astral: '\uD800[\uDE80-\uDE9F]'
},
{
name: 'InLydian',
astral: '\uD802[\uDD20-\uDD3F]'
},
{
name: 'InMahjong_Tiles',
astral: '\uD83C[\uDC00-\uDC2F]'
},
{
name: 'InMalayalam',
bmp: '\u0D00-\u0D7F'
},
{
name: 'InMandaic',
bmp: '\u0840-\u085F'
},
{
name: 'InMathematical_Alphanumeric_Symbols',
astral: '\uD835[\uDC00-\uDFFF]'
},
{
name: 'InMathematical_Operators',
bmp: '\u2200-\u22FF'
},
{
name: 'InMeetei_Mayek',
bmp: '\uABC0-\uABFF'
},
{
name: 'InMeetei_Mayek_Extensions',
bmp: '\uAAE0-\uAAFF'
},
{
name: 'InMeroitic_Cursive',
astral: '\uD802[\uDDA0-\uDDFF]'
},
{
name: 'InMeroitic_Hieroglyphs',
astral: '\uD802[\uDD80-\uDD9F]'
},
{
name: 'InMiao',
astral: '\uD81B[\uDF00-\uDF9F]'
},
{
name: 'InMiscellaneous_Mathematical_Symbols_A',
bmp: '\u27C0-\u27EF'
},
{
name: 'InMiscellaneous_Mathematical_Symbols_B',
bmp: '\u2980-\u29FF'
},
{
name: 'InMiscellaneous_Symbols',
bmp: '\u2600-\u26FF'
},
{
name: 'InMiscellaneous_Symbols_And_Pictographs',
astral: '\uD83D[\uDC00-\uDDFF]|\uD83C[\uDF00-\uDFFF]'
},
{
name: 'InMiscellaneous_Symbols_and_Arrows',
bmp: '\u2B00-\u2BFF'
},
{
name: 'InMiscellaneous_Technical',
bmp: '\u2300-\u23FF'
},
{
name: 'InModifier_Tone_Letters',
bmp: '\uA700-\uA71F'
},
{
name: 'InMongolian',
bmp: '\u1800-\u18AF'
},
{
name: 'InMusical_Symbols',
astral: '\uD834[\uDD00-\uDDFF]'
},
{
name: 'InMyanmar',
bmp: '\u1000-\u109F'
},
{
name: 'InMyanmar_Extended_A',
bmp: '\uAA60-\uAA7F'
},
{
name: 'InNKo',
bmp: '\u07C0-\u07FF'
},
{
name: 'InNew_Tai_Lue',
bmp: '\u1980-\u19DF'
},
{
name: 'InNumber_Forms',
bmp: '\u2150-\u218F'
},
{
name: 'InOgham',
bmp: '\u1680-\u169F'
},
{
name: 'InOl_Chiki',
bmp: '\u1C50-\u1C7F'
},
{
name: 'InOld_Italic',
astral: '\uD800[\uDF00-\uDF2F]'
},
{
name: 'InOld_Persian',
astral: '\uD800[\uDFA0-\uDFDF]'
},
{
name: 'InOld_South_Arabian',
astral: '\uD802[\uDE60-\uDE7F]'
},
{
name: 'InOld_Turkic',
astral: '\uD803[\uDC00-\uDC4F]'
},
{
name: 'InOptical_Character_Recognition',
bmp: '\u2440-\u245F'
},
{
name: 'InOriya',
bmp: '\u0B00-\u0B7F'
},
{
name: 'InOsmanya',
astral: '\uD801[\uDC80-\uDCAF]'
},
{
name: 'InPhags_pa',
bmp: '\uA840-\uA87F'
},
{
name: 'InPhaistos_Disc',
astral: '\uD800[\uDDD0-\uDDFF]'
},
{
name: 'InPhoenician',
astral: '\uD802[\uDD00-\uDD1F]'
},
{
name: 'InPhonetic_Extensions',
bmp: '\u1D00-\u1D7F'
},
{
name: 'InPhonetic_Extensions_Supplement',
bmp: '\u1D80-\u1DBF'
},
{
name: 'InPlaying_Cards',
astral: '\uD83C[\uDCA0-\uDCFF]'
},
{
name: 'InPrivate_Use_Area',
bmp: '\uE000-\uF8FF'
},
{
name: 'InRejang',
bmp: '\uA930-\uA95F'
},
{
name: 'InRumi_Numeral_Symbols',
astral: '\uD803[\uDE60-\uDE7F]'
},
{
name: 'InRunic',
bmp: '\u16A0-\u16FF'
},
{
name: 'InSamaritan',
bmp: '\u0800-\u083F'
},
{
name: 'InSaurashtra',
bmp: '\uA880-\uA8DF'
},
{
name: 'InSharada',
astral: '\uD804[\uDD80-\uDDDF]'
},
{
name: 'InShavian',
astral: '\uD801[\uDC50-\uDC7F]'
},
{
name: 'InSinhala',
bmp: '\u0D80-\u0DFF'
},
{
name: 'InSmall_Form_Variants',
bmp: '\uFE50-\uFE6F'
},
{
name: 'InSora_Sompeng',
astral: '\uD804[\uDCD0-\uDCFF]'
},
{
name: 'InSpacing_Modifier_Letters',
bmp: '\u02B0-\u02FF'
},
{
name: 'InSpecials',
bmp: '\uFFF0-\uFFFF'
},
{
name: 'InSundanese',
bmp: '\u1B80-\u1BBF'
},
{
name: 'InSundanese_Supplement',
bmp: '\u1CC0-\u1CCF'
},
{
name: 'InSuperscripts_and_Subscripts',
bmp: '\u2070-\u209F'
},
{
name: 'InSupplemental_Arrows_A',
bmp: '\u27F0-\u27FF'
},
{
name: 'InSupplemental_Arrows_B',
bmp: '\u2900-\u297F'
},
{
name: 'InSupplemental_Mathematical_Operators',
bmp: '\u2A00-\u2AFF'
},
{
name: 'InSupplemental_Punctuation',
bmp: '\u2E00-\u2E7F'
},
{
name: 'InSupplementary_Private_Use_Area_A',
astral: '[\uDB80-\uDBBF][\uDC00-\uDFFF]'
},
{
name: 'InSupplementary_Private_Use_Area_B',
astral: '[\uDBC0-\uDBFF][\uDC00-\uDFFF]'
},
{
name: 'InSyloti_Nagri',
bmp: '\uA800-\uA82F'
},
{
name: 'InSyriac',
bmp: '\u0700-\u074F'
},
{
name: 'InTagalog',
bmp: '\u1700-\u171F'
},
{
name: 'InTagbanwa',
bmp: '\u1760-\u177F'
},
{
name: 'InTags',
astral: '\uDB40[\uDC00-\uDC7F]'
},
{
name: 'InTai_Le',
bmp: '\u1950-\u197F'
},
{
name: 'InTai_Tham',
bmp: '\u1A20-\u1AAF'
},
{
name: 'InTai_Viet',
bmp: '\uAA80-\uAADF'
},
{
name: 'InTai_Xuan_Jing_Symbols',
astral: '\uD834[\uDF00-\uDF5F]'
},
{
name: 'InTakri',
astral: '\uD805[\uDE80-\uDECF]'
},
{
name: 'InTamil',
bmp: '\u0B80-\u0BFF'
},
{
name: 'InTelugu',
bmp: '\u0C00-\u0C7F'
},
{
name: 'InThaana',
bmp: '\u0780-\u07BF'
},
{
name: 'InThai',
bmp: '\u0E00-\u0E7F'
},
{
name: 'InTibetan',
bmp: '\u0F00-\u0FFF'
},
{
name: 'InTifinagh',
bmp: '\u2D30-\u2D7F'
},
{
name: 'InTransport_And_Map_Symbols',
astral: '\uD83D[\uDE80-\uDEFF]'
},
{
name: 'InUgaritic',
astral: '\uD800[\uDF80-\uDF9F]'
},
{
name: 'InUnified_Canadian_Aboriginal_Syllabics',
bmp: '\u1400-\u167F'
},
{
name: 'InUnified_Canadian_Aboriginal_Syllabics_Extended',
bmp: '\u18B0-\u18FF'
},
{
name: 'InVai',
bmp: '\uA500-\uA63F'
},
{
name: 'InVariation_Selectors',
bmp: '\uFE00-\uFE0F'
},
{
name: 'InVariation_Selectors_Supplement',
astral: '\uDB40[\uDD00-\uDDEF]'
},
{
name: 'InVedic_Extensions',
bmp: '\u1CD0-\u1CFF'
},
{
name: 'InVertical_Forms',
bmp: '\uFE10-\uFE1F'
},
{
name: 'InYi_Radicals',
bmp: '\uA490-\uA4CF'
},
{
name: 'InYi_Syllables',
bmp: '\uA000-\uA48F'
},
{
name: 'InYijing_Hexagram_Symbols',
bmp: '\u4DC0-\u4DFF'
}
]);
}(XRegExp));

View File

@@ -0,0 +1,232 @@
/*!
* XRegExp Unicode Categories 3.0.0-pre
* <http://xregexp.com/>
* Steven Levithan <20> 2010-2012 MIT License
* Uses Unicode 6.2.0 <http://unicode.org/>
* Unicode data generated by Mathias Bynens <http://mathiasbynens.be/>
*/
/**
* Adds support for all Unicode categories. E.g., `\p{Lu}` or `\p{Uppercase Letter}`. Token names
* are case insensitive, and any spaces, hyphens, and underscores are ignored.
* @requires XRegExp, Unicode Base
*/
(function(XRegExp) {
'use strict';
if (!XRegExp.addUnicodeData) {
throw new ReferenceError('Unicode Base must be loaded before Unicode Categories');
}
XRegExp.addUnicodeData([
{
name: 'C',
alias: 'Other',
isBmpLast: true,
bmp: '\0-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF',
astral: '\uD808[\uDF6F-\uDFFF]|\uD809[\uDC63-\uDC6F\uDC74-\uDFFF]|\uD804[\uDC4E-\uDC51\uDC70-\uDC7F\uDCBD\uDCC2-\uDCCF\uDCE9-\uDCEF\uDCFA-\uDCFF\uDD35\uDD44-\uDD7F\uDDC9-\uDDCF\uDDDA-\uDFFF]|\uD802[\uDC06\uDC07\uDC09\uDC36\uDC39-\uDC3B\uDC3D\uDC3E\uDC56\uDC60-\uDCFF\uDD1C-\uDD1E\uDD3A-\uDD3E\uDD40-\uDD7F\uDDB8-\uDDBD\uDDC0-\uDDFF\uDE04\uDE07-\uDE0B\uDE14\uDE18\uDE34-\uDE37\uDE3B-\uDE3E\uDE48-\uDE4F\uDE59-\uDE5F\uDE80-\uDEFF\uDF36-\uDF38\uDF56\uDF57\uDF73-\uDF77\uDF80-\uDFFF]|\uD86D[\uDF35-\uDF3F]|\uD81B[\uDC00-\uDEFF\uDF45-\uDF4F\uDF7F-\uDF8E\uDFA0-\uDFFF]|\uD86E[\uDC1E-\uDFFF]|\uD800[\uDC0C\uDC27\uDC3B\uDC3E\uDC4E\uDC4F\uDC5E-\uDC7F\uDCFB-\uDCFF\uDD03-\uDD06\uDD34-\uDD36\uDD8B-\uDD8F\uDD9C-\uDDCF\uDDFE-\uDE7F\uDE9D-\uDE9F\uDED1-\uDEFF\uDF1F\uDF24-\uDF2F\uDF4B-\uDF7F\uDF9E\uDFC4-\uDFC7\uDFD6-\uDFFF]|\uD869[\uDED7-\uDEFF]|\uD83B[\uDC00-\uDDFF\uDE04\uDE20\uDE23\uDE25\uDE26\uDE28\uDE33\uDE38\uDE3A\uDE3C-\uDE41\uDE43-\uDE46\uDE48\uDE4A\uDE4C\uDE50\uDE53\uDE55\uDE56\uDE58\uDE5A\uDE5C\uDE5E\uDE60\uDE63\uDE65\uDE66\uDE6B\uDE73\uDE78\uDE7D\uDE7F\uDE8A\uDE9C-\uDEA0\uDEA4\uDEAA\uDEBC-\uDEEF\uDEF2-\uDFFF]|\uD87E[\uDE1E-\uDFFF]|\uDB40[\uDC00-\uDCFF\uDDF0-\uDFFF]|\uD803[\uDC49-\uDE5F\uDE7F-\uDFFF]|\uD80D[\uDC2F-\uDFFF]|[\uD806\uD807\uD80A\uD80B\uD80E-\uD819\uD81C-\uD82B\uD82D-\uD833\uD836-\uD83A\uD83E\uD83F\uD86F-\uD87D\uD87F-\uDB3F\uDB41-\uDBFF][\uDC00-\uDFFF]|\uD83D[\uDC3F\uDC41\uDCF8\uDCFD-\uDCFF\uDD3E\uDD3F\uDD44-\uDD4F\uDD68-\uDDFA\uDE41-\uDE44\uDE50-\uDE7F\uDEC6-\uDEFF\uDF74-\uDFFF]|\uD83C[\uDC2C-\uDC2F\uDC94-\uDC9F\uDCAF\uDCB0\uDCBF\uDCC0\uDCD0\uDCE0-\uDCFF\uDD0B-\uDD0F\uDD2F\uDD6C-\uDD6F\uDD9B-\uDDE5\uDE03-\uDE0F\uDE3B-\uDE3F\uDE49-\uDE4F\uDE52-\uDEFF\uDF21-\uDF2F\uDF36\uDF7D-\uDF7F\uDF94-\uDF9F\uDFC5\uDFCB-\uDFDF\uDFF1-\uDFFF]|\uD835[\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]|\uD81A[\uDE39-\uDFFF]|\uD834[\uDCF6-\uDCFF\uDD27\uDD28\uDD73-\uDD7A\uDDDE-\uDDFF\uDE46-\uDEFF\uDF57-\uDF5F\uDF72-\uDFFF]|\uD801[\uDC9E\uDC9F\uDCAA-\uDFFF]|\uD805[\uDC00-\uDE7F\uDEB8-\uDEBF\uDECA-\uDFFF]|\uD82C[\uDC02-\uDFFF]'
},
{
name: 'Cc',
alias: 'Control',
bmp: '\0-\x1F\x7F-\x9F'
},
{
name: 'Cf',
alias: 'Format',
bmp: '\xAD\u0600-\u0604\u06DD\u070F\u200B-\u200F\u202A-\u202E\u2060-\u2064\u206A-\u206F\uFEFF\uFFF9-\uFFFB',
astral: '\uDB40[\uDC01\uDC20-\uDC7F]|\uD834[\uDD73-\uDD7A]|\uD804\uDCBD'
},
{
name: 'Cn',
alias: 'Unassigned',
bmp: '\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u05FF\u0605\u061C\u061D\u070E\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u2065-\u2069\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD\uFEFE\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFF8\uFFFE\uFFFF',
astral: '\uD808[\uDF6F-\uDFFF]|\uDB40[\uDC00\uDC02-\uDC1F\uDC80-\uDCFF\uDDF0-\uDFFF]|\uD834[\uDCF6-\uDCFF\uDD27\uDD28\uDDDE-\uDDFF\uDE46-\uDEFF\uDF57-\uDF5F\uDF72-\uDFFF]|\uD802[\uDC06\uDC07\uDC09\uDC36\uDC39-\uDC3B\uDC3D\uDC3E\uDC56\uDC60-\uDCFF\uDD1C-\uDD1E\uDD3A-\uDD3E\uDD40-\uDD7F\uDDB8-\uDDBD\uDDC0-\uDDFF\uDE04\uDE07-\uDE0B\uDE14\uDE18\uDE34-\uDE37\uDE3B-\uDE3E\uDE48-\uDE4F\uDE59-\uDE5F\uDE80-\uDEFF\uDF36-\uDF38\uDF56\uDF57\uDF73-\uDF77\uDF80-\uDFFF]|\uD86D[\uDF35-\uDF3F]|\uD81B[\uDC00-\uDEFF\uDF45-\uDF4F\uDF7F-\uDF8E\uDFA0-\uDFFF]|\uD809[\uDC63-\uDC6F\uDC74-\uDFFF]|\uD800[\uDC0C\uDC27\uDC3B\uDC3E\uDC4E\uDC4F\uDC5E-\uDC7F\uDCFB-\uDCFF\uDD03-\uDD06\uDD34-\uDD36\uDD8B-\uDD8F\uDD9C-\uDDCF\uDDFE-\uDE7F\uDE9D-\uDE9F\uDED1-\uDEFF\uDF1F\uDF24-\uDF2F\uDF4B-\uDF7F\uDF9E\uDFC4-\uDFC7\uDFD6-\uDFFF]|\uD869[\uDED7-\uDEFF]|\uD804[\uDC4E-\uDC51\uDC70-\uDC7F\uDCC2-\uDCCF\uDCE9-\uDCEF\uDCFA-\uDCFF\uDD35\uDD44-\uDD7F\uDDC9-\uDDCF\uDDDA-\uDFFF]|\uD83B[\uDC00-\uDDFF\uDE04\uDE20\uDE23\uDE25\uDE26\uDE28\uDE33\uDE38\uDE3A\uDE3C-\uDE41\uDE43-\uDE46\uDE48\uDE4A\uDE4C\uDE50\uDE53\uDE55\uDE56\uDE58\uDE5A\uDE5C\uDE5E\uDE60\uDE63\uDE65\uDE66\uDE6B\uDE73\uDE78\uDE7D\uDE7F\uDE8A\uDE9C-\uDEA0\uDEA4\uDEAA\uDEBC-\uDEEF\uDEF2-\uDFFF]|[\uDBBF\uDBFF][\uDFFE\uDFFF]|\uD87E[\uDE1E-\uDFFF]|\uD803[\uDC49-\uDE5F\uDE7F-\uDFFF]|\uD80D[\uDC2F-\uDFFF]|[\uD806\uD807\uD80A\uD80B\uD80E-\uD819\uD81C-\uD82B\uD82D-\uD833\uD836-\uD83A\uD83E\uD83F\uD86F-\uD87D\uD87F-\uDB3F\uDB41-\uDB7F][\uDC00-\uDFFF]|\uD83D[\uDC3F\uDC41\uDCF8\uDCFD-\uDCFF\uDD3E\uDD3F\uDD44-\uDD4F\uDD68-\uDDFA\uDE41-\uDE44\uDE50-\uDE7F\uDEC6-\uDEFF\uDF74-\uDFFF]|\uD86E[\uDC1E-\uDFFF]|\uD83C[\uDC2C-\uDC2F\uDC94-\uDC9F\uDCAF\uDCB0\uDCBF\uDCC0\uDCD0\uDCE0-\uDCFF\uDD0B-\uDD0F\uDD2F\uDD6C-\uDD6F\uDD9B-\uDDE5\uDE03-\uDE0F\uDE3B-\uDE3F\uDE49-\uDE4F\uDE52-\uDEFF\uDF21-\uDF2F\uDF36\uDF7D-\uDF7F\uDF94-\uDF9F\uDFC5\uDFCB-\uDFDF\uDFF1-\uDFFF]|\uD835[\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]|\uD81A[\uDE39-\uDFFF]|\uD801[\uDC9E\uDC9F\uDCAA-\uDFFF]|\uD805[\uDC00-\uDE7F\uDEB8-\uDEBF\uDECA-\uDFFF]|\uD82C[\uDC02-\uDFFF]'
},
{
name: 'Co',
alias: 'Private_Use',
bmp: '\uE000-\uF8FF',
astral: '[\uDB80-\uDBBE\uDBC0-\uDBFE][\uDC00-\uDFFF]|[\uDBBF\uDBFF][\uDC00-\uDFFD]'
},
{
name: 'Cs',
alias: 'Surrogate',
bmp: '\uD800-\uDFFF'
},
// Included in Unicode Base
/*{
name: 'L',
alias: 'Letter',
bmp: '...',
astral: '...'
},*/
{
name: 'Ll',
alias: 'Lowercase_Letter',
bmp: 'a-z\xB5\xDF-\xF6\xF8-\xFF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02AF\u0371\u0373\u0377\u037B-\u037D\u0390\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0561-\u0587\u1D00-\u1D2B\u1D6B-\u1D77\u1D79-\u1D9A\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD0-\u1FD3\u1FD6\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u210A\u210E\u210F\u2113\u212F\u2134\u2139\u213C\u213D\u2146-\u2149\u214E\u2184\u2C30-\u2C5E\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7B\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F\uA771-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7FA\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A',
astral: '\uD835[\uDC1A-\uDC33\uDC4E-\uDC54\uDC56-\uDC67\uDC82-\uDC9B\uDCB6-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDCEA-\uDD03\uDD1E-\uDD37\uDD52-\uDD6B\uDD86-\uDD9F\uDDBA-\uDDD3\uDDEE-\uDE07\uDE22-\uDE3B\uDE56-\uDE6F\uDE8A-\uDEA5\uDEC2-\uDEDA\uDEDC-\uDEE1\uDEFC-\uDF14\uDF16-\uDF1B\uDF36-\uDF4E\uDF50-\uDF55\uDF70-\uDF88\uDF8A-\uDF8F\uDFAA-\uDFC2\uDFC4-\uDFC9\uDFCB]|\uD801[\uDC28-\uDC4F]'
},
{
name: 'Lm',
alias: 'Modifier_Letter',
bmp: '\u02B0-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0374\u037A\u0559\u0640\u06E5\u06E6\u07F4\u07F5\u07FA\u081A\u0824\u0828\u0971\u0E46\u0EC6\u10FC\u17D7\u1843\u1AA7\u1C78-\u1C7D\u1D2C-\u1D6A\u1D78\u1D9B-\u1DBF\u2071\u207F\u2090-\u209C\u2C7C\u2C7D\u2D6F\u2E2F\u3005\u3031-\u3035\u303B\u309D\u309E\u30FC-\u30FE\uA015\uA4F8-\uA4FD\uA60C\uA67F\uA717-\uA71F\uA770\uA788\uA7F8\uA7F9\uA9CF\uAA70\uAADD\uAAF3\uAAF4\uFF70\uFF9E\uFF9F',
astral: '\uD81B[\uDF93-\uDF9F]'
},
{
name: 'Lo',
alias: 'Other_Letter',
bmp: '\xAA\xBA\u01BB\u01C0-\u01C3\u0294\u05D0-\u05EA\u05F0-\u05F2\u0620-\u063F\u0641-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u0800-\u0815\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0972-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E45\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10D0-\u10FA\u10FD-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17DC\u1820-\u1842\u1844-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C77\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u2135-\u2138\u2D30-\u2D67\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3006\u303C\u3041-\u3096\u309F\u30A1-\u30FA\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA014\uA016-\uA48C\uA4D0-\uA4F7\uA500-\uA60B\uA610-\uA61F\uA62A\uA62B\uA66E\uA6A0-\uA6E5\uA7FB-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA6F\uAA71-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB\uAADC\uAAE0-\uAAEA\uAAF2\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF66-\uFF6F\uFF71-\uFF9D\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC',
astral: '\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1E\uDF30-\uDF40\uDF42-\uDF49\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD81A[\uDC00-\uDE38]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD83-\uDDB2\uDDC1-\uDDC4]|\uD86E[\uDC00-\uDC1D]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD803[\uDC00-\uDC48]|\uD80D[\uDC00-\uDC2E]|\uD805[\uDE80-\uDEAA]|\uD87E[\uDC00-\uDE1D]|\uD81B[\uDF00-\uDF44\uDF50]|\uD801[\uDC50-\uDC9D]|\uD82C[\uDC00\uDC01]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD808[\uDC00-\uDF6E]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]'
},
{
name: 'Lt',
alias: 'Titlecase_Letter',
bmp: '\u01C5\u01C8\u01CB\u01F2\u1F88-\u1F8F\u1F98-\u1F9F\u1FA8-\u1FAF\u1FBC\u1FCC\u1FFC'
},
{
name: 'Lu',
alias: 'Uppercase_Letter',
bmp: 'A-Z\xC0-\xD6\xD8-\xDE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA\uFF21-\uFF3A',
astral: '\uD835[\uDC00-\uDC19\uDC34-\uDC4D\uDC68-\uDC81\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB5\uDCD0-\uDCE9\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD38\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD6C-\uDD85\uDDA0-\uDDB9\uDDD4-\uDDED\uDE08-\uDE21\uDE3C-\uDE55\uDE70-\uDE89\uDEA8-\uDEC0\uDEE2-\uDEFA\uDF1C-\uDF34\uDF56-\uDF6E\uDF90-\uDFA8\uDFCA]|\uD801[\uDC00-\uDC27]'
},
{
name: 'M',
alias: 'Mark',
bmp: '\u0300-\u036F\u0483-\u0489\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E4-\u08FE\u0900-\u0903\u093A-\u093C\u093E-\u094F\u0951-\u0957\u0962\u0963\u0981-\u0983\u09BC\u09BE-\u09C4\u09C7\u09C8\u09CB-\u09CD\u09D7\u09E2\u09E3\u0A01-\u0A03\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AE2\u0AE3\u0B01-\u0B03\u0B3C\u0B3E-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B62\u0B63\u0B82\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0C82\u0C83\u0CBC\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CE2\u0CE3\u0D02\u0D03\u0D3E-\u0D44\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0D62\u0D63\u0D82\u0D83\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074\u1082-\u108D\u108F\u109A-\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4-\u17D3\u17DD\u180B-\u180D\u18A9\u1920-\u192B\u1930-\u193B\u19B0-\u19C0\u19C8\u19C9\u1A17-\u1A1B\u1A55-\u1A5E\u1A60-\u1A7C\u1A7F\u1B00-\u1B04\u1B34-\u1B44\u1B6B-\u1B73\u1B80-\u1B82\u1BA1-\u1BAD\u1BE6-\u1BF3\u1C24-\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE8\u1CED\u1CF2-\u1CF4\u1DC0-\u1DE6\u1DFC-\u1DFF\u20D0-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302F\u3099\u309A\uA66F-\uA672\uA674-\uA67D\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA823-\uA827\uA880\uA881\uA8B4-\uA8C4\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA953\uA980-\uA983\uA9B3-\uA9C0\uAA29-\uAA36\uAA43\uAA4C\uAA4D\uAA7B\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEB-\uAAEF\uAAF5\uAAF6\uABE3-\uABEA\uABEC\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE26',
astral: '\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD802[\uDE01-\uDE03\uDE05\uDE06\uDE0C-\uDE0F\uDE38-\uDE3A\uDE3F]|\uD81B[\uDF51-\uDF7E\uDF8F-\uDF92]|\uD804[\uDC00-\uDC02\uDC38-\uDC46\uDC80-\uDC82\uDCB0-\uDCBA\uDD00-\uDD02\uDD27-\uDD34\uDD80-\uDD82\uDDB3-\uDDC0]|\uD805[\uDEAB-\uDEB7]|\uD800\uDDFD|\uDB40[\uDD00-\uDDEF]'
},
{
name: 'Mc',
alias: 'Spacing_Mark',
bmp: '\u0903\u093B\u093E-\u0940\u0949-\u094C\u094E\u094F\u0982\u0983\u09BE-\u09C0\u09C7\u09C8\u09CB\u09CC\u09D7\u0A03\u0A3E-\u0A40\u0A83\u0ABE-\u0AC0\u0AC9\u0ACB\u0ACC\u0B02\u0B03\u0B3E\u0B40\u0B47\u0B48\u0B4B\u0B4C\u0B57\u0BBE\u0BBF\u0BC1\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD7\u0C01-\u0C03\u0C41-\u0C44\u0C82\u0C83\u0CBE\u0CC0-\u0CC4\u0CC7\u0CC8\u0CCA\u0CCB\u0CD5\u0CD6\u0D02\u0D03\u0D3E-\u0D40\u0D46-\u0D48\u0D4A-\u0D4C\u0D57\u0D82\u0D83\u0DCF-\u0DD1\u0DD8-\u0DDF\u0DF2\u0DF3\u0F3E\u0F3F\u0F7F\u102B\u102C\u1031\u1038\u103B\u103C\u1056\u1057\u1062-\u1064\u1067-\u106D\u1083\u1084\u1087-\u108C\u108F\u109A-\u109C\u17B6\u17BE-\u17C5\u17C7\u17C8\u1923-\u1926\u1929-\u192B\u1930\u1931\u1933-\u1938\u19B0-\u19C0\u19C8\u19C9\u1A19-\u1A1B\u1A55\u1A57\u1A61\u1A63\u1A64\u1A6D-\u1A72\u1B04\u1B35\u1B3B\u1B3D-\u1B41\u1B43\u1B44\u1B82\u1BA1\u1BA6\u1BA7\u1BAA\u1BAC\u1BAD\u1BE7\u1BEA-\u1BEC\u1BEE\u1BF2\u1BF3\u1C24-\u1C2B\u1C34\u1C35\u1CE1\u1CF2\u1CF3\u302E\u302F\uA823\uA824\uA827\uA880\uA881\uA8B4-\uA8C3\uA952\uA953\uA983\uA9B4\uA9B5\uA9BA\uA9BB\uA9BD-\uA9C0\uAA2F\uAA30\uAA33\uAA34\uAA4D\uAA7B\uAAEB\uAAEE\uAAEF\uAAF5\uABE3\uABE4\uABE6\uABE7\uABE9\uABEA\uABEC',
astral: '\uD834[\uDD65\uDD66\uDD6D-\uDD72]|\uD804[\uDC00\uDC02\uDC82\uDCB0-\uDCB2\uDCB7\uDCB8\uDD2C\uDD82\uDDB3-\uDDB5\uDDBF\uDDC0]|\uD805[\uDEAC\uDEAE\uDEAF\uDEB6]|\uD81B[\uDF51-\uDF7E]'
},
{
name: 'Me',
alias: 'Enclosing_Mark',
bmp: '\u0488\u0489\u20DD-\u20E0\u20E2-\u20E4\uA670-\uA672'
},
{
name: 'Mn',
alias: 'Nonspacing_Mark',
bmp: '\u0300-\u036F\u0483-\u0487\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED\u0711\u0730-\u074A\u07A6-\u07B0\u07EB-\u07F3\u0816-\u0819\u081B-\u0823\u0825-\u0827\u0829-\u082D\u0859-\u085B\u08E4-\u08FE\u0900-\u0902\u093A\u093C\u0941-\u0948\u094D\u0951-\u0957\u0962\u0963\u0981\u09BC\u09C1-\u09C4\u09CD\u09E2\u09E3\u0A01\u0A02\u0A3C\u0A41\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A70\u0A71\u0A75\u0A81\u0A82\u0ABC\u0AC1-\u0AC5\u0AC7\u0AC8\u0ACD\u0AE2\u0AE3\u0B01\u0B3C\u0B3F\u0B41-\u0B44\u0B4D\u0B56\u0B62\u0B63\u0B82\u0BC0\u0BCD\u0C3E-\u0C40\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C62\u0C63\u0CBC\u0CBF\u0CC6\u0CCC\u0CCD\u0CE2\u0CE3\u0D41-\u0D44\u0D4D\u0D62\u0D63\u0DCA\u0DD2-\u0DD4\u0DD6\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB\u0EBC\u0EC8-\u0ECD\u0F18\u0F19\u0F35\u0F37\u0F39\u0F71-\u0F7E\u0F80-\u0F84\u0F86\u0F87\u0F8D-\u0F97\u0F99-\u0FBC\u0FC6\u102D-\u1030\u1032-\u1037\u1039\u103A\u103D\u103E\u1058\u1059\u105E-\u1060\u1071-\u1074\u1082\u1085\u1086\u108D\u109D\u135D-\u135F\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17B4\u17B5\u17B7-\u17BD\u17C6\u17C9-\u17D3\u17DD\u180B-\u180D\u18A9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193B\u1A17\u1A18\u1A56\u1A58-\u1A5E\u1A60\u1A62\u1A65-\u1A6C\u1A73-\u1A7C\u1A7F\u1B00-\u1B03\u1B34\u1B36-\u1B3A\u1B3C\u1B42\u1B6B-\u1B73\u1B80\u1B81\u1BA2-\u1BA5\u1BA8\u1BA9\u1BAB\u1BE6\u1BE8\u1BE9\u1BED\u1BEF-\u1BF1\u1C2C-\u1C33\u1C36\u1C37\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1DC0-\u1DE6\u1DFC-\u1DFF\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2CEF-\u2CF1\u2D7F\u2DE0-\u2DFF\u302A-\u302D\u3099\u309A\uA66F\uA674-\uA67D\uA69F\uA6F0\uA6F1\uA802\uA806\uA80B\uA825\uA826\uA8C4\uA8E0-\uA8F1\uA926-\uA92D\uA947-\uA951\uA980-\uA982\uA9B3\uA9B6-\uA9B9\uA9BC\uAA29-\uAA2E\uAA31\uAA32\uAA35\uAA36\uAA43\uAA4C\uAAB0\uAAB2-\uAAB4\uAAB7\uAAB8\uAABE\uAABF\uAAC1\uAAEC\uAAED\uAAF6\uABE5\uABE8\uABED\uFB1E\uFE00-\uFE0F\uFE20-\uFE26',
astral: '\uD802[\uDE01-\uDE03\uDE05\uDE06\uDE0C-\uDE0F\uDE38-\uDE3A\uDE3F]|\uD834[\uDD67-\uDD69\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD81B[\uDF8F-\uDF92]|\uD805[\uDEAB\uDEAD\uDEB0-\uDEB5\uDEB7]|\uD804[\uDC01\uDC38-\uDC46\uDC80\uDC81\uDCB3-\uDCB6\uDCB9\uDCBA\uDD00-\uDD02\uDD27-\uDD2B\uDD2D-\uDD34\uDD80\uDD81\uDDB6-\uDDBE]|\uD800\uDDFD|\uDB40[\uDD00-\uDDEF]'
},
{
name: 'N',
alias: 'Number',
bmp: '0-9\xB2\xB3\xB9\xBC-\xBE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D66-\u0D75\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19',
astral: '\uD802[\uDC58-\uDC5F\uDD16-\uDD1B\uDE40-\uDE47\uDE7D\uDE7E\uDF58-\uDF5F\uDF78-\uDF7F]|\uD801[\uDCA0-\uDCA9]|\uD809[\uDC00-\uDC62]|\uD835[\uDFCE-\uDFFF]|\uD800[\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDF20-\uDF23\uDF41\uDF4A\uDFD1-\uDFD5]|\uD834[\uDF60-\uDF71]|\uD803[\uDE60-\uDE7E]|\uD83C[\uDD00-\uDD0A]|\uD805[\uDEC0-\uDEC9]|\uD804[\uDC52-\uDC6F\uDCF0-\uDCF9\uDD36-\uDD3F\uDDD0-\uDDD9]'
},
{
name: 'Nd',
alias: 'Decimal_Number',
bmp: '0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19',
astral: '\uD804[\uDC66-\uDC6F\uDCF0-\uDCF9\uDD36-\uDD3F\uDDD0-\uDDD9]|\uD805[\uDEC0-\uDEC9]|\uD801[\uDCA0-\uDCA9]|\uD835[\uDFCE-\uDFFF]'
},
{
name: 'Nl',
alias: 'Letter_Number',
bmp: '\u16EE-\u16F0\u2160-\u2182\u2185-\u2188\u3007\u3021-\u3029\u3038-\u303A\uA6E6-\uA6EF',
astral: '\uD800[\uDD40-\uDD74\uDF41\uDF4A\uDFD1-\uDFD5]|\uD809[\uDC00-\uDC62]'
},
{
name: 'No',
alias: 'Other_Number',
bmp: '\xB2\xB3\xB9\xBC-\xBE\u09F4-\u09F9\u0B72-\u0B77\u0BF0-\u0BF2\u0C78-\u0C7E\u0D70-\u0D75\u0F2A-\u0F33\u1369-\u137C\u17F0-\u17F9\u19DA\u2070\u2074-\u2079\u2080-\u2089\u2150-\u215F\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA830-\uA835',
astral: '\uD802[\uDC58-\uDC5F\uDD16-\uDD1B\uDE40-\uDE47\uDE7D\uDE7E\uDF58-\uDF5F\uDF78-\uDF7F]|\uD834[\uDF60-\uDF71]|\uD803[\uDE60-\uDE7E]|\uD800[\uDD07-\uDD33\uDD75-\uDD78\uDD8A\uDF20-\uDF23]|\uD83C[\uDD00-\uDD0A]|\uD804[\uDC52-\uDC65]'
},
{
name: 'P',
alias: 'Punctuation',
bmp: '\x21-\x23\x25-\\x2A\x2C-\x2F\x3A\x3B\\x3F\x40\\x5B-\\x5D\x5F\\x7B\x7D\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E3B\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65',
astral: '\uD809[\uDC70-\uDC73]|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDF39-\uDF3F]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDDC5-\uDDC8]'
},
{
name: 'Pc',
alias: 'Connector_Punctuation',
bmp: '\x5F\u203F\u2040\u2054\uFE33\uFE34\uFE4D-\uFE4F\uFF3F'
},
{
name: 'Pd',
alias: 'Dash_Punctuation',
bmp: '\\x2D\u058A\u05BE\u1400\u1806\u2010-\u2015\u2E17\u2E1A\u2E3A\u2E3B\u301C\u3030\u30A0\uFE31\uFE32\uFE58\uFE63\uFF0D'
},
{
name: 'Pe',
alias: 'Close_Punctuation',
bmp: '\\x29\\x5D\x7D\u0F3B\u0F3D\u169C\u2046\u207E\u208E\u232A\u2769\u276B\u276D\u276F\u2771\u2773\u2775\u27C6\u27E7\u27E9\u27EB\u27ED\u27EF\u2984\u2986\u2988\u298A\u298C\u298E\u2990\u2992\u2994\u2996\u2998\u29D9\u29DB\u29FD\u2E23\u2E25\u2E27\u2E29\u3009\u300B\u300D\u300F\u3011\u3015\u3017\u3019\u301B\u301E\u301F\uFD3F\uFE18\uFE36\uFE38\uFE3A\uFE3C\uFE3E\uFE40\uFE42\uFE44\uFE48\uFE5A\uFE5C\uFE5E\uFF09\uFF3D\uFF5D\uFF60\uFF63'
},
{
name: 'Pf',
alias: 'Final_Punctuation',
bmp: '\xBB\u2019\u201D\u203A\u2E03\u2E05\u2E0A\u2E0D\u2E1D\u2E21'
},
{
name: 'Pi',
alias: 'Initial_Punctuation',
bmp: '\xAB\u2018\u201B\u201C\u201F\u2039\u2E02\u2E04\u2E09\u2E0C\u2E1C\u2E20'
},
{
name: 'Po',
alias: 'Other_Punctuation',
bmp: '\x21-\x23\x25-\x27\\x2A\x2C\\x2E\x2F\x3A\x3B\\x3F\x40\\x5C\xA1\xA7\xB6\xB7\xBF\u037E\u0387\u055A-\u055F\u0589\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u166D\u166E\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u1805\u1807-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2016\u2017\u2020-\u2027\u2030-\u2038\u203B-\u203E\u2041-\u2043\u2047-\u2051\u2053\u2055-\u205E\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00\u2E01\u2E06-\u2E08\u2E0B\u2E0E-\u2E16\u2E18\u2E19\u2E1B\u2E1E\u2E1F\u2E2A-\u2E2E\u2E30-\u2E39\u3001-\u3003\u303D\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFE10-\uFE16\uFE19\uFE30\uFE45\uFE46\uFE49-\uFE4C\uFE50-\uFE52\uFE54-\uFE57\uFE5F-\uFE61\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF07\uFF0A\uFF0C\uFF0E\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3C\uFF61\uFF64\uFF65',
astral: '\uD809[\uDC70-\uDC73]|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDF39-\uDF3F]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDDC5-\uDDC8]'
},
{
name: 'Ps',
alias: 'Open_Punctuation',
bmp: '\\x28\\x5B\\x7B\u0F3A\u0F3C\u169B\u201A\u201E\u2045\u207D\u208D\u2329\u2768\u276A\u276C\u276E\u2770\u2772\u2774\u27C5\u27E6\u27E8\u27EA\u27EC\u27EE\u2983\u2985\u2987\u2989\u298B\u298D\u298F\u2991\u2993\u2995\u2997\u29D8\u29DA\u29FC\u2E22\u2E24\u2E26\u2E28\u3008\u300A\u300C\u300E\u3010\u3014\u3016\u3018\u301A\u301D\uFD3E\uFE17\uFE35\uFE37\uFE39\uFE3B\uFE3D\uFE3F\uFE41\uFE43\uFE47\uFE59\uFE5B\uFE5D\uFF08\uFF3B\uFF5B\uFF5F\uFF62'
},
{
name: 'S',
alias: 'Symbol',
bmp: '\\x24\\x2B\x3C-\x3E\\x5E\x60\\x7C\x7E\xA2-\xA6\xA8\xA9\xAC\xAE-\xB1\xB4\xB8\xD7\xF7\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0384\u0385\u03F6\u0482\u058F\u0606-\u0608\u060B\u060E\u060F\u06DE\u06E9\u06FD\u06FE\u07F6\u09F2\u09F3\u09FA\u09FB\u0AF1\u0B70\u0BF3-\u0BFA\u0C7F\u0D79\u0E3F\u0F01-\u0F03\u0F13\u0F15-\u0F17\u0F1A-\u0F1F\u0F34\u0F36\u0F38\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE\u0FCF\u0FD5-\u0FD8\u109E\u109F\u1390-\u1399\u17DB\u1940\u19DE-\u19FF\u1B61-\u1B6A\u1B74-\u1B7C\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u2044\u2052\u207A-\u207C\u208A-\u208C\u20A0-\u20BA\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u2140-\u2144\u214A-\u214D\u214F\u2190-\u2328\u232B-\u23F3\u2400-\u2426\u2440-\u244A\u249C-\u24E9\u2500-\u26FF\u2701-\u2767\u2794-\u27C4\u27C7-\u27E5\u27F0-\u2982\u2999-\u29D7\u29DC-\u29FB\u29FE-\u2B4C\u2B50-\u2B59\u2CE5-\u2CEA\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3004\u3012\u3013\u3020\u3036\u3037\u303E\u303F\u309B\u309C\u3190\u3191\u3196-\u319F\u31C0-\u31E3\u3200-\u321E\u322A-\u3247\u3250\u3260-\u327F\u328A-\u32B0\u32C0-\u32FE\u3300-\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA700-\uA716\uA720\uA721\uA789\uA78A\uA828-\uA82B\uA836-\uA839\uAA77-\uAA79\uFB29\uFBB2-\uFBC1\uFDFC\uFDFD\uFE62\uFE64-\uFE66\uFE69\uFF04\uFF0B\uFF1C-\uFF1E\uFF3E\uFF40\uFF5C\uFF5E\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFFC\uFFFD',
astral: '\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCF7\uDCF9-\uDCFC\uDD00-\uDD3D\uDD40-\uDD43\uDD50-\uDD67\uDDFB-\uDE40\uDE45-\uDE4F\uDE80-\uDEC5\uDF00-\uDF73]|\uD835[\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBE\uDCC1-\uDCCF\uDCD1-\uDCDF\uDD10-\uDD2E\uDD30-\uDD6B\uDD70-\uDD9A\uDDE6-\uDE02\uDE10-\uDE3A\uDE40-\uDE48\uDE50\uDE51\uDF00-\uDF20\uDF30-\uDF35\uDF37-\uDF7C\uDF80-\uDF93\uDFA0-\uDFC4\uDFC6-\uDFCA\uDFE0-\uDFF0]|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD64\uDD6A-\uDD6C\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDDD\uDE00-\uDE41\uDE45\uDF00-\uDF56]|\uD800[\uDD37-\uDD3F\uDD79-\uDD89\uDD90-\uDD9B\uDDD0-\uDDFC]|\uD83B[\uDEF0\uDEF1]'
},
{
name: 'Sc',
alias: 'Currency_Symbol',
bmp: '\\x24\xA2-\xA5\u058F\u060B\u09F2\u09F3\u09FB\u0AF1\u0BF9\u0E3F\u17DB\u20A0-\u20BA\uA838\uFDFC\uFE69\uFF04\uFFE0\uFFE1\uFFE5\uFFE6'
},
{
name: 'Sk',
alias: 'Modifier_Symbol',
bmp: '\\x5E\x60\xA8\xAF\xB4\xB8\u02C2-\u02C5\u02D2-\u02DF\u02E5-\u02EB\u02ED\u02EF-\u02FF\u0375\u0384\u0385\u1FBD\u1FBF-\u1FC1\u1FCD-\u1FCF\u1FDD-\u1FDF\u1FED-\u1FEF\u1FFD\u1FFE\u309B\u309C\uA700-\uA716\uA720\uA721\uA789\uA78A\uFBB2-\uFBC1\uFF3E\uFF40\uFFE3'
},
{
name: 'Sm',
alias: 'Math_Symbol',
bmp: '\\x2B\x3C-\x3E\\x7C\x7E\xAC\xB1\xD7\xF7\u03F6\u0606-\u0608\u2044\u2052\u207A-\u207C\u208A-\u208C\u2118\u2140-\u2144\u214B\u2190-\u2194\u219A\u219B\u21A0\u21A3\u21A6\u21AE\u21CE\u21CF\u21D2\u21D4\u21F4-\u22FF\u2308-\u230B\u2320\u2321\u237C\u239B-\u23B3\u23DC-\u23E1\u25B7\u25C1\u25F8-\u25FF\u266F\u27C0-\u27C4\u27C7-\u27E5\u27F0-\u27FF\u2900-\u2982\u2999-\u29D7\u29DC-\u29FB\u29FE-\u2AFF\u2B30-\u2B44\u2B47-\u2B4C\uFB29\uFE62\uFE64-\uFE66\uFF0B\uFF1C-\uFF1E\uFF5C\uFF5E\uFFE2\uFFE9-\uFFEC',
astral: '\uD83B[\uDEF0\uDEF1]|\uD835[\uDEC1\uDEDB\uDEFB\uDF15\uDF35\uDF4F\uDF6F\uDF89\uDFA9\uDFC3]'
},
{
name: 'So',
alias: 'Other_Symbol',
bmp: '\xA6\xA9\xAE\xB0\u0482\u060E\u060F\u06DE\u06E9\u06FD\u06FE\u07F6\u09FA\u0B70\u0BF3-\u0BF8\u0BFA\u0C7F\u0D79\u0F01-\u0F03\u0F13\u0F15-\u0F17\u0F1A-\u0F1F\u0F34\u0F36\u0F38\u0FBE-\u0FC5\u0FC7-\u0FCC\u0FCE\u0FCF\u0FD5-\u0FD8\u109E\u109F\u1390-\u1399\u1940\u19DE-\u19FF\u1B61-\u1B6A\u1B74-\u1B7C\u2100\u2101\u2103-\u2106\u2108\u2109\u2114\u2116\u2117\u211E-\u2123\u2125\u2127\u2129\u212E\u213A\u213B\u214A\u214C\u214D\u214F\u2195-\u2199\u219C-\u219F\u21A1\u21A2\u21A4\u21A5\u21A7-\u21AD\u21AF-\u21CD\u21D0\u21D1\u21D3\u21D5-\u21F3\u2300-\u2307\u230C-\u231F\u2322-\u2328\u232B-\u237B\u237D-\u239A\u23B4-\u23DB\u23E2-\u23F3\u2400-\u2426\u2440-\u244A\u249C-\u24E9\u2500-\u25B6\u25B8-\u25C0\u25C2-\u25F7\u2600-\u266E\u2670-\u26FF\u2701-\u2767\u2794-\u27BF\u2800-\u28FF\u2B00-\u2B2F\u2B45\u2B46\u2B50-\u2B59\u2CE5-\u2CEA\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3004\u3012\u3013\u3020\u3036\u3037\u303E\u303F\u3190\u3191\u3196-\u319F\u31C0-\u31E3\u3200-\u321E\u322A-\u3247\u3250\u3260-\u327F\u328A-\u32B0\u32C0-\u32FE\u3300-\u33FF\u4DC0-\u4DFF\uA490-\uA4C6\uA828-\uA82B\uA836\uA837\uA839\uAA77-\uAA79\uFDFD\uFFE4\uFFE8\uFFED\uFFEE\uFFFC\uFFFD',
astral: '\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCF7\uDCF9-\uDCFC\uDD00-\uDD3D\uDD40-\uDD43\uDD50-\uDD67\uDDFB-\uDE40\uDE45-\uDE4F\uDE80-\uDEC5\uDF00-\uDF73]|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD64\uDD6A-\uDD6C\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDDD\uDE00-\uDE41\uDE45\uDF00-\uDF56]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBE\uDCC1-\uDCCF\uDCD1-\uDCDF\uDD10-\uDD2E\uDD30-\uDD6B\uDD70-\uDD9A\uDDE6-\uDE02\uDE10-\uDE3A\uDE40-\uDE48\uDE50\uDE51\uDF00-\uDF20\uDF30-\uDF35\uDF37-\uDF7C\uDF80-\uDF93\uDFA0-\uDFC4\uDFC6-\uDFCA\uDFE0-\uDFF0]|\uD800[\uDD37-\uDD3F\uDD79-\uDD89\uDD90-\uDD9B\uDDD0-\uDDFC]'
},
{
name: 'Z',
alias: 'Separator',
bmp: '\x20\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000'
},
{
name: 'Zl',
alias: 'Line_Separator',
bmp: '\u2028'
},
{
name: 'Zp',
alias: 'Paragraph_Separator',
bmp: '\u2029'
},
{
name: 'Zs',
alias: 'Space_Separator',
bmp: '\x20\xA0\u1680\u180E\u2000-\u200A\u202F\u205F\u3000'
}
]);
}(XRegExp));

View File

@@ -0,0 +1,69 @@
/*!
* XRegExp Unicode Properties 3.0.0-pre
* <http://xregexp.com/>
* Steven Levithan <20> 2012 MIT License
* Uses Unicode 6.2.0 <http://unicode.org/>
* Unicode data generated by Mathias Bynens <http://mathiasbynens.be/>
*/
/**
* Adds Level 1 Unicode properties (detailed in UTS #18 RL1.2). Token names are case insensitive,
* and any spaces, hyphens, and underscores are ignored.
* @requires XRegExp, Unicode Base
*/
(function(XRegExp) {
'use strict';
if (!XRegExp.addUnicodeData) {
throw new ReferenceError('Unicode Base must be loaded before Unicode Properties');
}
XRegExp.addUnicodeData([
{
name: 'ASCII',
bmp: '\0-\x7F'
},
{
name: 'Alphabetic',
bmp: 'A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0345\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05B0-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0657\u0659-\u065F\u066E-\u06D3\u06D5-\u06DC\u06E1-\u06E8\u06ED-\u06EF\u06FA-\u06FC\u06FF\u0710-\u073F\u074D-\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0817\u081A-\u082C\u0840-\u0858\u08A0\u08A2-\u08AC\u08E4-\u08E9\u08F0-\u08FE\u0900-\u093B\u093D-\u094C\u094E-\u0950\u0955-\u0963\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD-\u09C4\u09C7\u09C8\u09CB\u09CC\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09F0\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3E-\u0A42\u0A47\u0A48\u0A4B\u0A4C\u0A51\u0A59-\u0A5C\u0A5E\u0A70-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD-\u0AC5\u0AC7-\u0AC9\u0ACB\u0ACC\u0AD0\u0AE0-\u0AE3\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D-\u0B44\u0B47\u0B48\u0B4B\u0B4C\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCC\u0BD0\u0BD7\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4C\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCC\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4C\u0D4E\u0D57\u0D60-\u0D63\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E46\u0E4D\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0ECD\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F71-\u0F81\u0F88-\u0F97\u0F99-\u0FBC\u1000-\u1036\u1038\u103B-\u103F\u1050-\u1062\u1065-\u1068\u106E-\u1086\u108E\u109C\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1713\u1720-\u1733\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17B3\u17B6-\u17C8\u17D7\u17DC\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u1938\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A1B\u1A20-\u1A5E\u1A61-\u1A74\u1AA7\u1B00-\u1B33\u1B35-\u1B43\u1B45-\u1B4B\u1B80-\u1BA9\u1BAC-\u1BAF\u1BBA-\u1BE5\u1BE7-\u1BF1\u1C00-\u1C35\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u24B6-\u24E9\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA674-\uA67B\uA67F-\uA697\uA69F-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA827\uA840-\uA873\uA880-\uA8C3\uA8F2-\uA8F7\uA8FB\uA90A-\uA92A\uA930-\uA952\uA960-\uA97C\uA980-\uA9B2\uA9B4-\uA9BF\uA9CF\uAA00-\uAA36\uAA40-\uAA4D\uAA60-\uAA76\uAA7A\uAA80-\uAABE\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF5\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC',
astral: '\uD803[\uDC00-\uDC48]|\uD801[\uDC00-\uDC9D]|\uD809[\uDC00-\uDC62]|\uD81A[\uDC00-\uDE38]|\uD804[\uDC00-\uDC45\uDC82-\uDCB8\uDCD0-\uDCE8\uDD00-\uDD32\uDD80-\uDDBF\uDDC1-\uDDC4]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD87E[\uDC00-\uDE1D]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1E\uDF30-\uDF4A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF93-\uDF9F]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD82C[\uDC00\uDC01]|\uD808[\uDC00-\uDF6E]|\uD805[\uDE80-\uDEB5]'
},
// Assert: In BMP-only mode, `[\P{Any}]` (inverted Any within a character class) compiles to `[]`
{
name: 'Any',
isBmpLast: true,
bmp: '\0-\uFFFF',
astral: '[\uD800-\uDBFF][\uDC00-\uDFFF]'
},
// Defined as the inverse of Unicode category Cn (Unassigned)
{
name: 'Assigned',
inverseOf: 'Cn'
},
{
name: 'Default_Ignorable_Code_Point',
bmp: '\xAD\u034F\u115F\u1160\u17B4\u17B5\u180B-\u180D\u200B-\u200F\u202A-\u202E\u2060-\u206F\u3164\uFE00-\uFE0F\uFEFF\uFFA0\uFFF0-\uFFF8',
astral: '[\uDB40-\uDB43][\uDC00-\uDFFF]|\uD834[\uDD73-\uDD7A]'
},
{
name: 'Lowercase',
bmp: 'a-z\xAA\xB5\xBA\xDF-\xF6\xF8-\xFF\u0101\u0103\u0105\u0107\u0109\u010B\u010D\u010F\u0111\u0113\u0115\u0117\u0119\u011B\u011D\u011F\u0121\u0123\u0125\u0127\u0129\u012B\u012D\u012F\u0131\u0133\u0135\u0137\u0138\u013A\u013C\u013E\u0140\u0142\u0144\u0146\u0148\u0149\u014B\u014D\u014F\u0151\u0153\u0155\u0157\u0159\u015B\u015D\u015F\u0161\u0163\u0165\u0167\u0169\u016B\u016D\u016F\u0171\u0173\u0175\u0177\u017A\u017C\u017E-\u0180\u0183\u0185\u0188\u018C\u018D\u0192\u0195\u0199-\u019B\u019E\u01A1\u01A3\u01A5\u01A8\u01AA\u01AB\u01AD\u01B0\u01B4\u01B6\u01B9\u01BA\u01BD-\u01BF\u01C6\u01C9\u01CC\u01CE\u01D0\u01D2\u01D4\u01D6\u01D8\u01DA\u01DC\u01DD\u01DF\u01E1\u01E3\u01E5\u01E7\u01E9\u01EB\u01ED\u01EF\u01F0\u01F3\u01F5\u01F9\u01FB\u01FD\u01FF\u0201\u0203\u0205\u0207\u0209\u020B\u020D\u020F\u0211\u0213\u0215\u0217\u0219\u021B\u021D\u021F\u0221\u0223\u0225\u0227\u0229\u022B\u022D\u022F\u0231\u0233-\u0239\u023C\u023F\u0240\u0242\u0247\u0249\u024B\u024D\u024F-\u0293\u0295-\u02B8\u02C0\u02C1\u02E0-\u02E4\u0345\u0371\u0373\u0377\u037A-\u037D\u0390\u03AC-\u03CE\u03D0\u03D1\u03D5-\u03D7\u03D9\u03DB\u03DD\u03DF\u03E1\u03E3\u03E5\u03E7\u03E9\u03EB\u03ED\u03EF-\u03F3\u03F5\u03F8\u03FB\u03FC\u0430-\u045F\u0461\u0463\u0465\u0467\u0469\u046B\u046D\u046F\u0471\u0473\u0475\u0477\u0479\u047B\u047D\u047F\u0481\u048B\u048D\u048F\u0491\u0493\u0495\u0497\u0499\u049B\u049D\u049F\u04A1\u04A3\u04A5\u04A7\u04A9\u04AB\u04AD\u04AF\u04B1\u04B3\u04B5\u04B7\u04B9\u04BB\u04BD\u04BF\u04C2\u04C4\u04C6\u04C8\u04CA\u04CC\u04CE\u04CF\u04D1\u04D3\u04D5\u04D7\u04D9\u04DB\u04DD\u04DF\u04E1\u04E3\u04E5\u04E7\u04E9\u04EB\u04ED\u04EF\u04F1\u04F3\u04F5\u04F7\u04F9\u04FB\u04FD\u04FF\u0501\u0503\u0505\u0507\u0509\u050B\u050D\u050F\u0511\u0513\u0515\u0517\u0519\u051B\u051D\u051F\u0521\u0523\u0525\u0527\u0561-\u0587\u1D00-\u1DBF\u1E01\u1E03\u1E05\u1E07\u1E09\u1E0B\u1E0D\u1E0F\u1E11\u1E13\u1E15\u1E17\u1E19\u1E1B\u1E1D\u1E1F\u1E21\u1E23\u1E25\u1E27\u1E29\u1E2B\u1E2D\u1E2F\u1E31\u1E33\u1E35\u1E37\u1E39\u1E3B\u1E3D\u1E3F\u1E41\u1E43\u1E45\u1E47\u1E49\u1E4B\u1E4D\u1E4F\u1E51\u1E53\u1E55\u1E57\u1E59\u1E5B\u1E5D\u1E5F\u1E61\u1E63\u1E65\u1E67\u1E69\u1E6B\u1E6D\u1E6F\u1E71\u1E73\u1E75\u1E77\u1E79\u1E7B\u1E7D\u1E7F\u1E81\u1E83\u1E85\u1E87\u1E89\u1E8B\u1E8D\u1E8F\u1E91\u1E93\u1E95-\u1E9D\u1E9F\u1EA1\u1EA3\u1EA5\u1EA7\u1EA9\u1EAB\u1EAD\u1EAF\u1EB1\u1EB3\u1EB5\u1EB7\u1EB9\u1EBB\u1EBD\u1EBF\u1EC1\u1EC3\u1EC5\u1EC7\u1EC9\u1ECB\u1ECD\u1ECF\u1ED1\u1ED3\u1ED5\u1ED7\u1ED9\u1EDB\u1EDD\u1EDF\u1EE1\u1EE3\u1EE5\u1EE7\u1EE9\u1EEB\u1EED\u1EEF\u1EF1\u1EF3\u1EF5\u1EF7\u1EF9\u1EFB\u1EFD\u1EFF-\u1F07\u1F10-\u1F15\u1F20-\u1F27\u1F30-\u1F37\u1F40-\u1F45\u1F50-\u1F57\u1F60-\u1F67\u1F70-\u1F7D\u1F80-\u1F87\u1F90-\u1F97\u1FA0-\u1FA7\u1FB0-\u1FB4\u1FB6\u1FB7\u1FBE\u1FC2-\u1FC4\u1FC6\u1FC7\u1FD0-\u1FD3\u1FD6\u1FD7\u1FE0-\u1FE7\u1FF2-\u1FF4\u1FF6\u1FF7\u2071\u207F\u2090-\u209C\u210A\u210E\u210F\u2113\u212F\u2134\u2139\u213C\u213D\u2146-\u2149\u214E\u2170-\u217F\u2184\u24D0-\u24E9\u2C30-\u2C5E\u2C61\u2C65\u2C66\u2C68\u2C6A\u2C6C\u2C71\u2C73\u2C74\u2C76-\u2C7D\u2C81\u2C83\u2C85\u2C87\u2C89\u2C8B\u2C8D\u2C8F\u2C91\u2C93\u2C95\u2C97\u2C99\u2C9B\u2C9D\u2C9F\u2CA1\u2CA3\u2CA5\u2CA7\u2CA9\u2CAB\u2CAD\u2CAF\u2CB1\u2CB3\u2CB5\u2CB7\u2CB9\u2CBB\u2CBD\u2CBF\u2CC1\u2CC3\u2CC5\u2CC7\u2CC9\u2CCB\u2CCD\u2CCF\u2CD1\u2CD3\u2CD5\u2CD7\u2CD9\u2CDB\u2CDD\u2CDF\u2CE1\u2CE3\u2CE4\u2CEC\u2CEE\u2CF3\u2D00-\u2D25\u2D27\u2D2D\uA641\uA643\uA645\uA647\uA649\uA64B\uA64D\uA64F\uA651\uA653\uA655\uA657\uA659\uA65B\uA65D\uA65F\uA661\uA663\uA665\uA667\uA669\uA66B\uA66D\uA681\uA683\uA685\uA687\uA689\uA68B\uA68D\uA68F\uA691\uA693\uA695\uA697\uA723\uA725\uA727\uA729\uA72B\uA72D\uA72F-\uA731\uA733\uA735\uA737\uA739\uA73B\uA73D\uA73F\uA741\uA743\uA745\uA747\uA749\uA74B\uA74D\uA74F\uA751\uA753\uA755\uA757\uA759\uA75B\uA75D\uA75F\uA761\uA763\uA765\uA767\uA769\uA76B\uA76D\uA76F-\uA778\uA77A\uA77C\uA77F\uA781\uA783\uA785\uA787\uA78C\uA78E\uA791\uA793\uA7A1\uA7A3\uA7A5\uA7A7\uA7A9\uA7F8-\uA7FA\uFB00-\uFB06\uFB13-\uFB17\uFF41-\uFF5A',
astral: '\uD835[\uDC1A-\uDC33\uDC4E-\uDC54\uDC56-\uDC67\uDC82-\uDC9B\uDCB6-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDCEA-\uDD03\uDD1E-\uDD37\uDD52-\uDD6B\uDD86-\uDD9F\uDDBA-\uDDD3\uDDEE-\uDE07\uDE22-\uDE3B\uDE56-\uDE6F\uDE8A-\uDEA5\uDEC2-\uDEDA\uDEDC-\uDEE1\uDEFC-\uDF14\uDF16-\uDF1B\uDF36-\uDF4E\uDF50-\uDF55\uDF70-\uDF88\uDF8A-\uDF8F\uDFAA-\uDFC2\uDFC4-\uDFC9\uDFCB]|\uD801[\uDC28-\uDC4F]'
},
{
name: 'Noncharacter_Code_Point',
bmp: '\uFDD0-\uFDEF\uFFFE\uFFFF',
astral: '[\uDB3F\uDB7F\uDBBF\uDBFF\uD83F\uD87F\uD8BF\uDAFF\uD97F\uD9BF\uD9FF\uDA3F\uD8FF\uDABF\uDA7F\uD93F][\uDFFE\uDFFF]'
},
{
name: 'Uppercase',
bmp: 'A-Z\xC0-\xD6\xD8-\xDE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178\u0179\u017B\u017D\u0181\u0182\u0184\u0186\u0187\u0189-\u018B\u018E-\u0191\u0193\u0194\u0196-\u0198\u019C\u019D\u019F\u01A0\u01A2\u01A4\u01A6\u01A7\u01A9\u01AC\u01AE\u01AF\u01B1-\u01B3\u01B5\u01B7\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A\u023B\u023D\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u0386\u0388-\u038A\u038C\u038E\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E\u213F\u2145\u2160-\u216F\u2183\u24B6-\u24CF\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA\uFF21-\uFF3A',
astral: '\uD835[\uDC00-\uDC19\uDC34-\uDC4D\uDC68-\uDC81\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB5\uDCD0-\uDCE9\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD38\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD6C-\uDD85\uDDA0-\uDDB9\uDDD4-\uDDED\uDE08-\uDE21\uDE3C-\uDE55\uDE70-\uDE89\uDEA8-\uDEC0\uDEE2-\uDEFA\uDF1C-\uDF34\uDF56-\uDF6E\uDF90-\uDFA8\uDFCA]|\uD801[\uDC00-\uDC27]'
},
{
name: 'White_Space',
bmp: '\x09-\x0D\x20\x85\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000'
}
]);
}(XRegExp));

View File

@@ -0,0 +1,440 @@
/*!
* XRegExp Unicode Scripts 3.0.0-pre
* <http://xregexp.com/>
* Steven Levithan <20> 2010-2012 MIT License
* Uses Unicode 6.2.0 <http://unicode.org/>
* Unicode data generated by Mathias Bynens <http://mathiasbynens.be/>
*/
/**
* Adds support for all Unicode scripts. E.g., `\p{Latin}`. Token names are case insensitive, and
* any spaces, hyphens, and underscores are ignored.
* @requires XRegExp, Unicode Base
*/
(function(XRegExp) {
'use strict';
if (!XRegExp.addUnicodeData) {
throw new ReferenceError('Unicode Base must be loaded before Unicode Scripts');
}
XRegExp.addUnicodeData([
{
name: 'Arabic',
bmp: '\u0600-\u0604\u0606-\u060B\u060D-\u061A\u061E\u0620-\u063F\u0641-\u064A\u0656-\u065F\u066A-\u066F\u0671-\u06DC\u06DE-\u06FF\u0750-\u077F\u08A0\u08A2-\u08AC\u08E4-\u08FE\uFB50-\uFBC1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFC\uFE70-\uFE74\uFE76-\uFEFC',
astral: '\uD803[\uDE60-\uDE7E]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB\uDEF0\uDEF1]'
},
{
name: 'Armenian',
bmp: '\u0531-\u0556\u0559-\u055F\u0561-\u0587\u058A\u058F\uFB13-\uFB17'
},
{
name: 'Avestan',
astral: '\uD802[\uDF00-\uDF35\uDF39-\uDF3F]'
},
{
name: 'Balinese',
bmp: '\u1B00-\u1B4B\u1B50-\u1B7C'
},
{
name: 'Bamum',
bmp: '\uA6A0-\uA6F7',
astral: '\uD81A[\uDC00-\uDE38]'
},
{
name: 'Batak',
bmp: '\u1BC0-\u1BF3\u1BFC-\u1BFF'
},
{
name: 'Bengali',
bmp: '\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09FB'
},
{
name: 'Bopomofo',
bmp: '\u02EA\u02EB\u3105-\u312D\u31A0-\u31BA'
},
{
name: 'Brahmi',
astral: '\uD804[\uDC00-\uDC4D\uDC52-\uDC6F]'
},
{
name: 'Braille',
bmp: '\u2800-\u28FF'
},
{
name: 'Buginese',
bmp: '\u1A00-\u1A1B\u1A1E\u1A1F'
},
{
name: 'Buhid',
bmp: '\u1740-\u1753'
},
{
name: 'Canadian_Aboriginal',
bmp: '\u1400-\u167F\u18B0-\u18F5'
},
{
name: 'Carian',
astral: '\uD800[\uDEA0-\uDED0]'
},
{
name: 'Chakma',
astral: '\uD804[\uDD00-\uDD34\uDD36-\uDD43]'
},
{
name: 'Cham',
bmp: '\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA5C-\uAA5F'
},
{
name: 'Cherokee',
bmp: '\u13A0-\u13F4'
},
{
name: 'Common',
bmp: '\0-\x40\\x5B-\x60\\x7B-\xA9\xAB-\xB9\xBB-\xBF\xD7\xF7\u02B9-\u02DF\u02E5-\u02E9\u02EC-\u02FF\u0374\u037E\u0385\u0387\u0589\u060C\u061B\u061F\u0640\u0660-\u0669\u06DD\u0964\u0965\u0E3F\u0FD5-\u0FD8\u10FB\u16EB-\u16ED\u1735\u1736\u1802\u1803\u1805\u1CD3\u1CE1\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u2000-\u200B\u200E-\u2064\u206A-\u2070\u2074-\u207E\u2080-\u208E\u20A0-\u20BA\u2100-\u2125\u2127-\u2129\u212C-\u2131\u2133-\u214D\u214F-\u215F\u2189\u2190-\u23F3\u2400-\u2426\u2440-\u244A\u2460-\u26FF\u2701-\u27FF\u2900-\u2B4C\u2B50-\u2B59\u2E00-\u2E3B\u2FF0-\u2FFB\u3000-\u3004\u3006\u3008-\u3020\u3030-\u3037\u303C-\u303F\u309B\u309C\u30A0\u30FB\u30FC\u3190-\u319F\u31C0-\u31E3\u3220-\u325F\u327F-\u32CF\u3358-\u33FF\u4DC0-\u4DFF\uA700-\uA721\uA788-\uA78A\uA830-\uA839\uFD3E\uFD3F\uFDFD\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFEFF\uFF01-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65\uFF70\uFF9E\uFF9F\uFFE0-\uFFE6\uFFE8-\uFFEE\uFFF9-\uFFFD',
astral: '\uD800[\uDD00-\uDD02\uDD07-\uDD33\uDD37-\uDD3F\uDD90-\uDD9B\uDDD0-\uDDFC]|\uD83C[\uDC00-\uDC2B\uDC30-\uDC93\uDCA0-\uDCAE\uDCB1-\uDCBE\uDCC1-\uDCCF\uDCD1-\uDCDF\uDD00-\uDD0A\uDD10-\uDD2E\uDD30-\uDD6B\uDD70-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE10-\uDE3A\uDE40-\uDE48\uDE50\uDE51\uDF00-\uDF20\uDF30-\uDF35\uDF37-\uDF7C\uDF80-\uDF93\uDFA0-\uDFC4\uDFC6-\uDFCA\uDFE0-\uDFF0]|\uDB40[\uDC01\uDC20-\uDC7F]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDFCB\uDFCE-\uDFFF]|\uD834[\uDC00-\uDCF5\uDD00-\uDD26\uDD29-\uDD66\uDD6A-\uDD7A\uDD83\uDD84\uDD8C-\uDDA9\uDDAE-\uDDDD\uDF00-\uDF56\uDF60-\uDF71]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCF7\uDCF9-\uDCFC\uDD00-\uDD3D\uDD40-\uDD43\uDD50-\uDD67\uDDFB-\uDE40\uDE45-\uDE4F\uDE80-\uDEC5\uDF00-\uDF73]'
},
{
name: 'Coptic',
bmp: '\u03E2-\u03EF\u2C80-\u2CF3\u2CF9-\u2CFF'
},
{
name: 'Cuneiform',
astral: '\uD809[\uDC00-\uDC62\uDC70-\uDC73]|\uD808[\uDC00-\uDF6E]'
},
{
name: 'Cypriot',
astral: '\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F]'
},
{
name: 'Cyrillic',
bmp: '\u0400-\u0484\u0487-\u0527\u1D2B\u1D78\u2DE0-\u2DFF\uA640-\uA697\uA69F'
},
{
name: 'Deseret',
astral: '\uD801[\uDC00-\uDC4F]'
},
{
name: 'Devanagari',
bmp: '\u0900-\u0950\u0953-\u0963\u0966-\u0977\u0979-\u097F\uA8E0-\uA8FB'
},
{
name: 'Egyptian_Hieroglyphs',
astral: '\uD80C[\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]'
},
{
name: 'Ethiopic',
bmp: '\u1200-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u137C\u1380-\u1399\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E'
},
{
name: 'Georgian',
bmp: '\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u10FF\u2D00-\u2D25\u2D27\u2D2D'
},
{
name: 'Glagolitic',
bmp: '\u2C00-\u2C2E\u2C30-\u2C5E'
},
{
name: 'Gothic',
astral: '\uD800[\uDF30-\uDF4A]'
},
{
name: 'Greek',
bmp: '\u0370-\u0373\u0375-\u0377\u037A-\u037D\u0384\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03E1\u03F0-\u03FF\u1D26-\u1D2A\u1D5D-\u1D61\u1D66-\u1D6A\u1DBF\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FC4\u1FC6-\u1FD3\u1FD6-\u1FDB\u1FDD-\u1FEF\u1FF2-\u1FF4\u1FF6-\u1FFE\u2126',
astral: '\uD834[\uDE00-\uDE45]|\uD800[\uDD40-\uDD8A]'
},
{
name: 'Gujarati',
bmp: '\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AF1'
},
{
name: 'Gurmukhi',
bmp: '\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75'
},
{
name: 'Han',
bmp: '\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u3005\u3007\u3021-\u3029\u3038-\u303B\u3400-\u4DB5\u4E00-\u9FCC\uF900-\uFA6D\uFA70-\uFAD9',
astral: '[\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD87E[\uDC00-\uDE1D]'
},
{
name: 'Hangul',
bmp: '\u1100-\u11FF\u302E\u302F\u3131-\u318E\u3200-\u321E\u3260-\u327E\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uFFA0-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'
},
{
name: 'Hanunoo',
bmp: '\u1720-\u1734'
},
{
name: 'Hebrew',
bmp: '\u0591-\u05C7\u05D0-\u05EA\u05F0-\u05F4\uFB1D-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFB4F'
},
{
name: 'Hiragana',
bmp: '\u3041-\u3096\u309D-\u309F',
astral: '\uD82C\uDC01|\uD83C\uDE00'
},
{
name: 'Imperial_Aramaic',
astral: '\uD802[\uDC40-\uDC55\uDC57-\uDC5F]'
},
{
name: 'Inherited',
bmp: '\u0300-\u036F\u0485\u0486\u064B-\u0655\u0670\u0951\u0952\u1CD0-\u1CD2\u1CD4-\u1CE0\u1CE2-\u1CE8\u1CED\u1CF4\u1DC0-\u1DE6\u1DFC-\u1DFF\u200C\u200D\u20D0-\u20F0\u302A-\u302D\u3099\u309A\uFE00-\uFE0F\uFE20-\uFE26',
astral: '\uD834[\uDD67-\uDD69\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD]|\uD800\uDDFD|\uDB40[\uDD00-\uDDEF]'
},
{
name: 'Inscriptional_Pahlavi',
astral: '\uD802[\uDF60-\uDF72\uDF78-\uDF7F]'
},
{
name: 'Inscriptional_Parthian',
astral: '\uD802[\uDF40-\uDF55\uDF58-\uDF5F]'
},
{
name: 'Javanese',
bmp: '\uA980-\uA9CD\uA9CF-\uA9D9\uA9DE\uA9DF'
},
{
name: 'Kaithi',
astral: '\uD804[\uDC80-\uDCC1]'
},
{
name: 'Kannada',
bmp: '\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2'
},
{
name: 'Katakana',
bmp: '\u30A1-\u30FA\u30FD-\u30FF\u31F0-\u31FF\u32D0-\u32FE\u3300-\u3357\uFF66-\uFF6F\uFF71-\uFF9D',
astral: '\uD82C\uDC00'
},
{
name: 'Kayah_Li',
bmp: '\uA900-\uA92F'
},
{
name: 'Kharoshthi',
astral: '\uD802[\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F-\uDE47\uDE50-\uDE58]'
},
{
name: 'Khmer',
bmp: '\u1780-\u17DD\u17E0-\u17E9\u17F0-\u17F9\u19E0-\u19FF'
},
{
name: 'Lao',
bmp: '\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF'
},
{
name: 'Latin',
bmp: 'A-Za-z\xAA\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02B8\u02E0-\u02E4\u1D00-\u1D25\u1D2C-\u1D5C\u1D62-\u1D65\u1D6B-\u1D77\u1D79-\u1DBE\u1E00-\u1EFF\u2071\u207F\u2090-\u209C\u212A\u212B\u2132\u214E\u2160-\u2188\u2C60-\u2C7F\uA722-\uA787\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA7FF\uFB00-\uFB06\uFF21-\uFF3A\uFF41-\uFF5A'
},
{
name: 'Lepcha',
bmp: '\u1C00-\u1C37\u1C3B-\u1C49\u1C4D-\u1C4F'
},
{
name: 'Limbu',
bmp: '\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1940\u1944-\u194F'
},
{
name: 'Linear_B',
astral: '\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA]'
},
{
name: 'Lisu',
bmp: '\uA4D0-\uA4FF'
},
{
name: 'Lycian',
astral: '\uD800[\uDE80-\uDE9C]'
},
{
name: 'Lydian',
astral: '\uD802[\uDD20-\uDD39\uDD3F]'
},
{
name: 'Malayalam',
bmp: '\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D75\u0D79-\u0D7F'
},
{
name: 'Mandaic',
bmp: '\u0840-\u085B\u085E'
},
{
name: 'Meetei_Mayek',
bmp: '\uAAE0-\uAAF6\uABC0-\uABED\uABF0-\uABF9'
},
{
name: 'Meroitic_Cursive',
astral: '\uD802[\uDDA0-\uDDB7\uDDBE\uDDBF]'
},
{
name: 'Meroitic_Hieroglyphs',
astral: '\uD802[\uDD80-\uDD9F]'
},
{
name: 'Miao',
astral: '\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]'
},
{
name: 'Mongolian',
bmp: '\u1800\u1801\u1804\u1806-\u180E\u1810-\u1819\u1820-\u1877\u1880-\u18AA'
},
{
name: 'Myanmar',
bmp: '\u1000-\u109F\uAA60-\uAA7B'
},
{
name: 'New_Tai_Lue',
bmp: '\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u19DE\u19DF'
},
{
name: 'Nko',
bmp: '\u07C0-\u07FA'
},
{
name: 'Ogham',
bmp: '\u1680-\u169C'
},
{
name: 'Ol_Chiki',
bmp: '\u1C50-\u1C7F'
},
{
name: 'Old_Italic',
astral: '\uD800[\uDF00-\uDF1E\uDF20-\uDF23]'
},
{
name: 'Old_Persian',
astral: '\uD800[\uDFA0-\uDFC3\uDFC8-\uDFD5]'
},
{
name: 'Old_South_Arabian',
astral: '\uD802[\uDE60-\uDE7F]'
},
{
name: 'Old_Turkic',
astral: '\uD803[\uDC00-\uDC48]'
},
{
name: 'Oriya',
bmp: '\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B77'
},
{
name: 'Osmanya',
astral: '\uD801[\uDC80-\uDC9D\uDCA0-\uDCA9]'
},
{
name: 'Phags_Pa',
bmp: '\uA840-\uA877'
},
{
name: 'Phoenician',
astral: '\uD802[\uDD00-\uDD1B\uDD1F]'
},
{
name: 'Rejang',
bmp: '\uA930-\uA953\uA95F'
},
{
name: 'Runic',
bmp: '\u16A0-\u16EA\u16EE-\u16F0'
},
{
name: 'Samaritan',
bmp: '\u0800-\u082D\u0830-\u083E'
},
{
name: 'Saurashtra',
bmp: '\uA880-\uA8C4\uA8CE-\uA8D9'
},
{
name: 'Sharada',
astral: '\uD804[\uDD80-\uDDC8\uDDD0-\uDDD9]'
},
{
name: 'Shavian',
astral: '\uD801[\uDC50-\uDC7F]'
},
{
name: 'Sinhala',
bmp: '\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2-\u0DF4'
},
{
name: 'Sora_Sompeng',
astral: '\uD804[\uDCD0-\uDCE8\uDCF0-\uDCF9]'
},
{
name: 'Sundanese',
bmp: '\u1B80-\u1BBF\u1CC0-\u1CC7'
},
{
name: 'Syloti_Nagri',
bmp: '\uA800-\uA82B'
},
{
name: 'Syriac',
bmp: '\u0700-\u070D\u070F-\u074A\u074D-\u074F'
},
{
name: 'Tagalog',
bmp: '\u1700-\u170C\u170E-\u1714'
},
{
name: 'Tagbanwa',
bmp: '\u1760-\u176C\u176E-\u1770\u1772\u1773'
},
{
name: 'Tai_Le',
bmp: '\u1950-\u196D\u1970-\u1974'
},
{
name: 'Tai_Tham',
bmp: '\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA0-\u1AAD'
},
{
name: 'Tai_Viet',
bmp: '\uAA80-\uAAC2\uAADB-\uAADF'
},
{
name: 'Takri',
astral: '\uD805[\uDE80-\uDEB7\uDEC0-\uDEC9]'
},
{
name: 'Tamil',
bmp: '\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BFA'
},
{
name: 'Telugu',
bmp: '\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C78-\u0C7F'
},
{
name: 'Thaana',
bmp: '\u0780-\u07B1'
},
{
name: 'Thai',
bmp: '\u0E01-\u0E3A\u0E40-\u0E5B'
},
{
name: 'Tibetan',
bmp: '\u0F00-\u0F47\u0F49-\u0F6C\u0F71-\u0F97\u0F99-\u0FBC\u0FBE-\u0FCC\u0FCE-\u0FD4\u0FD9\u0FDA'
},
{
name: 'Tifinagh',
bmp: '\u2D30-\u2D67\u2D6F\u2D70\u2D7F'
},
{
name: 'Ugaritic',
astral: '\uD800[\uDF80-\uDF9D\uDF9F]'
},
{
name: 'Vai',
bmp: '\uA500-\uA62B'
},
{
name: 'Yi',
bmp: '\uA000-\uA48C\uA490-\uA4C6'
}
]);
}(XRegExp));

1665
public/vendor/xregexp/xregexp.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -80,6 +80,7 @@ var db = require('./database.js'),
'category_id': category_id,
'active_users': [],
'topics': [],
'disableSocialButtons': meta.config.disableSocialButtons !== undefined ? parseInt(meta.config.disableSocialButtons, 10) !== 0 : false,
'twitter-intent-url': 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug) + '&text=' + encodeURIComponent(category_name),
'facebook-share-url': 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug),
'google-share-url': 'https://plus.google.com/share?url=' + encodeURIComponent(nconf.get('url') + 'category/' + category_slug),
@@ -216,6 +217,10 @@ var db = require('./database.js'),
};
Categories.getRecentReplies = function(cid, count, callback) {
if(count === 0) {
return callback(null, []);
}
db.getSortedSetRevRange('categories:recent_posts:cid:' + cid, 0, count - 1, function(err, pids) {
if (err) {
@@ -400,4 +405,25 @@ var db = require('./database.js'),
db.setRemove('cid:' + cid + ':active_users', uid);
};
Categories.onNewPostMade = function(uid, tid, pid, timestamp) {
topics.getTopicFields(tid, ['cid', 'pinned'], function(err, topicData) {
var cid = topicData.cid;
db.sortedSetAdd('categories:recent_posts:cid:' + cid, timestamp, pid);
if(parseInt(topicData.pinned, 10) === 0) {
db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
}
db.setCount('cid:' + cid + ':active_users', function(err, amount) {
if (amount > 15) {
db.setRemoveRandom('cid:' + cid + ':active_users');
}
Categories.addActiveUser(cid, uid);
});
});
}
}(exports));

View File

@@ -50,13 +50,20 @@
function createCollections() {
db.createCollection('objects', function(err, collection) {
if(err) {
winston.error("Error creating collection " + err.message);
winston.error('Error creating collection ' + err.message);
return;
}
if(collection) {
collection.ensureIndex({_key :1}, {background:true}, function(err, name){
collection.ensureIndex({_key :1}, {background:true}, function(err, name) {
if(err) {
winston.error("Error creating index " + err.message);
winston.error('Error creating index ' + err.message);
}
});
collection.ensureIndex({'expireAt':1}, {expireAfterSeconds:0, background:true}, function(err, name) {
if(err) {
winston.error('Error creating index ' + err.message);
}
});
}
@@ -64,13 +71,13 @@
db.createCollection('search', function(err, collection) {
if(err) {
winston.error("Error creating collection " + err.message);
winston.error('Error creating collection ' + err.message);
return;
}
if(collection) {
collection.ensureIndex({content:'text'}, {background:true}, function(err, name){
if(err) {
winston.error("Error creating index " + err.message);
winston.error('Error creating index ' + err.message);
}
});
}
@@ -241,6 +248,14 @@
});
}
module.expire = function(key, seconds, callback) {
module.expireAt(key, Math.round(Date.now() / 1000) + seconds, callback);
}
module.expireAt = function(key, timestamp, callback) {
module.setObjectField(key, 'expireAt', new Date(timestamp * 1000), callback);
}
//hashes
module.setObject = function(key, data, callback) {
data['_key'] = key;
@@ -254,6 +269,9 @@
module.setObjectField = function(key, field, value, callback) {
var data = {};
// if there is a '.' in the field name it inserts subdocument in mongo, replace '.'s with \uff0E
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E');
data[field] = value;
db.collection('objects').update({_key:key}, {$set:data}, {upsert:true, w: 1}, function(err, result) {
@@ -303,7 +321,11 @@
var _fields = {};
for(var i=0; i<fields.length; ++i) {
_fields[fields[i].replace(/\./g, '\uff0E')] = 1;
if(typeof fields[i] !== 'string') {
_fields[fields[i].toString().replace(/\./g, '\uff0E')] = 1;
} else {
_fields[fields[i].replace(/\./g, '\uff0E')] = 1;
}
}
db.collection('objects').findOne({_key:key}, _fields, function(err, item) {
@@ -344,6 +366,9 @@
module.isObjectField = function(key, field, callback) {
var data = {};
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E');
data[field] = '';
db.collection('objects').findOne({_key:key}, {fields:data}, function(err, item) {
@@ -356,6 +381,9 @@
module.deleteObjectField = function(key, field, callback) {
var data = {};
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E');
data[field] = "";
db.collection('objects').update({_key:key}, {$unset : data}, function(err, result) {
@@ -375,6 +403,9 @@
module.incrObjectFieldBy = function(key, field, value, callback) {
var data = {};
if(typeof field !== 'string') {
field = field.toString();
}
field = field.replace(/\./g, '\uff0E');
data[field] = value;
db.collection('objects').update({_key:key}, {$inc : data}, {upsert:true}, function(err, result) {
@@ -707,6 +738,21 @@
});
}
module.listRemoveAll = function(key, value, callback) {
db.collection('objects').update({_key: key }, { $pull: { array: value } }, function(err, result) {
if(err) {
if(callback) {
return callback(err);
}
return;
}
if(callback) {
callback(null, result);
}
});
}
module.getListRange = function(key, start, stop, callback) {
if(stop === -1) {

View File

@@ -211,6 +211,14 @@
redisClient.keys(key, callback);
}
module.expire = function(key, seconds, callback) {
redisClient.expire(key, seconds, callback);
}
module.expireAt = function(key, timestamp, callback) {
redisClient.expireat(key, timestamp, callback);
}
//hashes
module.setObject = function(key, data, callback) {
@@ -394,6 +402,10 @@
redisClient.rpop(key, callback);
}
module.listRemoveAll = function(key, value, callback) {
redisClient.lrem(key, 0, value, callback);
}
module.getListRange = function(key, start, stop, callback) {
redisClient.lrange(key, start, stop, callback);
}

View File

@@ -7,6 +7,8 @@ var fs = require('fs'),
(function(events) {
var logFileName = 'events.log';
events.logPasswordChange = function(uid) {
log(uid, 'changed password');
}
@@ -54,7 +56,7 @@ var fs = require('fs'),
var date = new Date().toUTCString();
var msg = '[' + date + '] - ' + username + '(uid ' + uid + ') ' + string + '\n';
var logFile = path.join(nconf.get('base_dir'), 'events.log');
var logFile = path.join(nconf.get('base_dir'), logFileName);
fs.appendFile(logFile, msg, function(err) {
if(err) {
@@ -63,8 +65,12 @@ var fs = require('fs'),
}
});
});
}
events.getLog = function(callback) {
var logFile = path.join(nconf.get('base_dir'), logFileName);
fs.readFile(logFile, callback);
}
}(module.exports));

View File

@@ -69,13 +69,15 @@
next();
}, function() {
if (process.env.NODE_ENV === 'development') {
winston.info('[rss] Re-generated RSS Feed for tid ' + tid + '.');
}
Feed.saveFeed('feeds/topics/' + tid + '.rss', feed, function (err) {
if (process.env.NODE_ENV === 'development') {
winston.info('[rss] Re-generated RSS Feed for tid ' + tid + '.');
}
if (callback) {
callback();
}
if (callback) {
callback();
}
});
});
});
@@ -111,7 +113,9 @@
winston.info('[rss] Re-generated RSS Feed for cid ' + cid + '.');
}
if (callback) callback();
if (callback) {
callback();
}
});
});
});

View File

@@ -20,6 +20,7 @@ var request = require('request'),
try {
var response = JSON.parse(body);
if(response.success) {
callback(null, response.data);
} else {

View File

@@ -134,6 +134,11 @@ var async = require('async'),
return next(new Error('unknown database : ' + config.database));
}
var allQuestions = install.redisQuestions.concat(install.mongoQuestions);
for(var x=0;x<allQuestions.length;x++) {
delete config[allQuestions[x].name];
}
config.bcrypt_rounds = 12;
config.upload_path = '/public/uploads';
config.use_port = config.use_port.slice(0, 1) === 'y';
@@ -212,9 +217,18 @@ var async = require('async'),
}, {
field: 'allowRegistration',
value: 1
}, {
field: 'allowFileUploads',
value: 0,
}, {
filed: 'maximumFileSize',
value: 2048
}, {
field: 'minimumTitleLength',
value: 3
}, {
field: 'maximumTitleLength',
value: 255
}, {
field: 'minimumUsernameLength',
value: 2
@@ -233,6 +247,9 @@ var async = require('async'),
}, {
field: 'maximumProfileImageSize',
value: 256
}, {
field: 'chatMessagesToDisplay',
value: 50
}, {
field: 'theme:type',
value: 'local'
@@ -246,6 +263,21 @@ var async = require('async'),
}, function (err) {
meta.configs.init(next);
});
if (install.values) {
if (install.values['social:twitter:key'] && install.values['social:twitter:secret']) {
meta.configs.setOnEmpty('social:twitter:key', install.values['social:twitter:key']);
meta.configs.setOnEmpty('social:twitter:secret', install.values['social:twitter:secret']);
}
if (install.values['social:google:id'] && install.values['social:google:secret']) {
meta.configs.setOnEmpty('social:google:id', install.values['social:google:id']);
meta.configs.setOnEmpty('social:google:secret', install.values['social:google:secret']);
}
if (install.values['social:facebook:key'] && install.values['social:facebook:secret']) {
meta.configs.setOnEmpty('social:facebook:app_id', install.values['social:facebook:app_id']);
meta.configs.setOnEmpty('social:facebook:secret', install.values['social:facebook:secret']);
}
}
},
function (next) {
// Check if an administrator needs to be created

View File

@@ -3,11 +3,12 @@
*/
var fs = require('fs'),
path = require('path'),
express = require('express'),
winston = require('winston'),
util = require('util'),
socketio = require('socket.io'),
meta = require('./meta.js');
meta = require('./meta');
var opts = {
/*
@@ -71,11 +72,29 @@ var opts = {
Logger.open = function(value) {
/* Open the streams to log to: either a path or stdout */
var stream;
if(value && fs.existsSync(value)) {
stream = fs.createWriteStream(value, {flags: 'a'});
}
else
if(value) {
if(fs.existsSync(value)) {
stats = fs.statSync(value);
if(stats) {
if(stats.isDirectory()) {
stream = fs.createWriteStream(path.join(value, 'nodebb.log'), {flags: 'a'});
} else {
stream = fs.createWriteStream(value, {flags: 'a'});
}
}
} else {
stream = fs.createWriteStream(value, {flags: 'a'});
}
if(stream) {
stream.on('error', function(err) {
winston.error(err.message);
});
}
} else {
stream = process.stdout;
}
return stream;
}
@@ -112,8 +131,7 @@ var opts = {
*/
if(meta.config.loggerStatus > 0) {
return opts.express.ofn(req,res,next);
}
else {
} else {
return next();
}
}
@@ -140,11 +158,13 @@ var opts = {
for(var v in clients) {
var client = clients[v];
if(client.oEmit != undefined && client.oEmit != client.emit)
if(client.oEmit != undefined && client.oEmit != client.emit) {
client.emit = client.oEmit;
}
if(client.$oEmit != undefined && client.$oEmit != client.$emit)
if(client.$oEmit != undefined && client.$oEmit != client.$emit) {
client.$emit = client.$oEmit;
}
}
}
@@ -177,8 +197,9 @@ var opts = {
var emit = socket.emit;
socket.emit = function() {
if(opts.streams.log.f != null) {
opts.streams.log.f.write(Logger.prepare_io_string("emit",uid,arguments));
opts.streams.log.f.write(Logger.prepare_io_string("emit", uid, arguments));
}
try {
emit.apply(socket, arguments);
} catch(err) {

View File

@@ -1,6 +1,7 @@
var db = require('./database'),
async = require('async'),
user = require('./user');
user = require('./user'),
meta = require('./meta');
(function(Messaging) {
@@ -38,7 +39,7 @@ var db = require('./database'),
Messaging.getMessages = function(fromuid, touid, callback) {
var uids = sortUids(fromuid, touid);
db.getListRange('messages:' + uids[0] + ':' + uids[1], 0, -1, function(err, mids) {
db.getListRange('messages:' + uids[0] + ':' + uids[1], -((meta.config.chatMessagesToDisplay || 50) - 1), -1, function(err, mids) {
if (err) {
return callback(err, null);
}
@@ -49,6 +50,9 @@ var db = require('./database'),
user.getUserField(touid, 'username', function(err, tousername) {
if(err) {
return callback(err, null);
}
var messages = [];
@@ -78,7 +82,7 @@ var db = require('./database'),
});
});
});
}
};
Messaging.updateChatTime = function(uid, toUid, callback) {
db.sortedSetAdd('uid:' + uid + ':chats', Date.now(), toUid, function(err) {
@@ -90,11 +94,11 @@ var db = require('./database'),
Messaging.getRecentChats = function(uid, callback) {
db.getSortedSetRevRange('uid:' + uid + ':chats', 0, 9, function(err, uids) {
if (!err) {
user.getMultipleUserFields(uids, ['username', 'picture', 'uid'], callback);
} else {
callback(err);
if(err) {
return callback(err);
}
user.getMultipleUserFields(uids, ['username', 'picture', 'uid'], callback);
});
};

View File

@@ -196,6 +196,8 @@ var fs = require('fs'),
'vendor/requirejs/require.js',
'vendor/bootbox/bootbox.min.js',
'vendor/tinycon/tinycon.js',
'vendor/xregexp/xregexp.js',
'vendor/xregexp/unicode/unicode-base.js',
'src/app.js',
'src/templates.js',
'src/ajaxify.js',
@@ -207,22 +209,36 @@ var fs = require('fs'),
plugins.fireHook('filter:scripts.get', this.scripts, function(err, scripts) {
var mtime,
jsPaths = scripts.map(function (jsPath) {
return path.join(__dirname, '..', '/public', jsPath);
if (jsPath.substring(0, 7) === 'plugins') {
var paths = jsPath.split('/'),
pluginID = paths[1];
jsPath = jsPath.replace(path.join('plugins', pluginID), '');
return path.join(plugins.staticDirs[pluginID], jsPath);
} else {
return path.join(__dirname, '..', '/public', jsPath);
}
});
Meta.js.scripts = jsPaths;
if (process.env.NODE_ENV !== 'development') {
async.parallel({
mtime: function (next) {
async.map(jsPaths, fs.stat, function (err, stats) {
async.reduce(stats, 0, function (memo, item, callback) {
mtime = +new Date(item.mtime);
callback(null, mtime > memo ? mtime : memo);
if(item) {
mtime = +new Date(item.mtime);
callback(null, mtime > memo ? mtime : memo);
} else {
callback(null, memo);
}
}, next);
});
},
minFile: function (next) {
if (!fs.existsSync(Meta.js.minFile)) {
if (process.env.NODE_ENV === 'development') winston.warn('No minified client-side library found');
winston.warn('No minified client-side library found');
return next(null, 0);
}
@@ -232,12 +248,12 @@ var fs = require('fs'),
}
}, function (err, results) {
if (results.minFile > results.mtime) {
if (process.env.NODE_ENV === 'development') winston.info('No changes to client-side libraries -- skipping minification');
winston.info('No changes to client-side libraries -- skipping minification');
callback(null, [path.relative(path.join(__dirname, '../public'), Meta.js.minFile)]);
} else {
Meta.js.minify(function () {
callback(null, [
path.relative(path.join(__dirname, '../public'), Meta.js.minFile) + (meta.config['cache-buster'] ? '?v=' + meta.config['cache-buster'] : '')
path.relative(path.join(__dirname, '../public'), Meta.js.minFile) + (meta.config['cache-buster'] ? '?vs=' + meta.config['cache-buster'] : '')
]);
});
}
@@ -254,9 +270,7 @@ var fs = require('fs'),
},
minify: function (callback) {
var uglifyjs = require('uglify-js'),
jsPaths = this.scripts.map(function (jsPath) {
return path.join(__dirname, '..', '/public', jsPath);
}),
jsPaths = this.scripts,
minified;
if (process.env.NODE_ENV === 'development') {

View File

@@ -85,7 +85,7 @@ var async = require('async'),
remove_by_uniqueId(notif_data.uniqueId, uid, function() {
db.sortedSetAdd('uid:' + uid + ':notifications:unread', notif_data.datetime, nid);
websockets.in('uid_' + uid).emit('event:new_notification');
websockets.in('uid_' + uid).emit('event:new_notification', notif_data);
if (callback) {
callback(true);

View File

@@ -137,7 +137,7 @@ var winston = require('winston'),
events.logPostDelete(uid, pid);
posts.getPostFields(pid, ['tid', 'uid'], function(err, postData) {
db.incrObjectFieldBy('topic:' + postData.tid, 'postcount', -1);
topics.decreasePostCount(postData.tid);
user.decrementUserFieldBy(postData.uid, 'postcount', 1, function(err, postcount) {
db.sortedSetAdd('users:postcount', postcount, postData.uid);
@@ -152,7 +152,7 @@ var winston = require('winston'),
// Delete the thread if it is the last undeleted post
threadTools.getLatestUndeletedPid(postData.tid, function(err, pid) {
if (err && err.message === 'no-undeleted-pids-found') {
threadTools.delete(postData.tid, function(err) {
threadTools.delete(postData.tid, uid, function(err) {
if (err) {
winston.error('Could not delete topic (tid: ' + postData.tid + ')', err.stack);
}
@@ -193,7 +193,7 @@ var winston = require('winston'),
events.logPostRestore(uid, pid);
posts.getPostFields(pid, ['tid', 'uid', 'content'], function(err, postData) {
db.incrObjectFieldBy('topic:' + postData.tid, 'postcount', 1);
topics.increasePostCount(postData.tid);
user.incrementUserFieldBy(postData.uid, 'postcount', 1);

View File

@@ -12,10 +12,13 @@ var db = require('./database'),
meta = require('./meta'),
async = require('async'),
path = require('path'),
fs = require('fs'),
nconf = require('nconf'),
validator = require('validator'),
winston = require('winston'),
gravatar = require('gravatar');
gravatar = require('gravatar'),
S = require('string');
(function(Posts) {
var customUserInfo = {};
@@ -25,146 +28,73 @@ var db = require('./database'),
return callback(new Error('invalid-user'), null);
}
topics.isLocked(tid, function(err, locked) {
if(err) {
return callback(err, null);
} else if(locked) {
return callback(new Error('topic-locked'), null);
}
db.incrObjectField('global', 'nextPid', function(err, pid) {
if(err) {
return callback(err, null);
async.waterfall([
function(next) {
topics.isLocked(tid, next);
},
function(locked, next) {
if(locked) {
return next(new Error('topic-locked'));
}
db.incrObjectField('global', 'nextPid', next);
},
function(pid, next) {
plugins.fireHook('filter:post.save', content, function(err, newContent) {
next(err, pid, newContent)
});
},
function(pid, newContent, next) {
var timestamp = Date.now(),
postData = {
'pid': pid,
'uid': uid,
'tid': tid,
'content': newContent,
'timestamp': timestamp,
'reputation': 0,
'editor': '',
'edited': 0,
'deleted': 0
};
db.setObject('post:' + pid, postData, function(err) {
if(err) {
return callback(err, null);
return next(err);
}
var timestamp = Date.now(),
postData = {
'pid': pid,
'uid': uid,
'tid': tid,
'content': newContent,
'timestamp': timestamp,
'reputation': 0,
'editor': '',
'edited': 0,
'deleted': 0
};
db.setObject('post:' + pid, postData);
postData.favourited = false;
postData.display_moderator_tools = true;
postData.relativeTime = new Date(timestamp).toISOString();
topics.addPostToTopic(tid, pid);
topics.increasePostCount(tid);
topics.updateTimestamp(tid, timestamp);
db.incrObjectField('global', 'postCount');
topics.getTopicFields(tid, ['cid', 'pinned'], function(err, topicData) {
var cid = topicData.cid;
feed.updateTopic(tid);
feed.updateRecent();
db.sortedSetAdd('categories:recent_posts:cid:' + cid, timestamp, pid);
if(parseInt(topicData.pinned, 10) === 0) {
db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
}
db.setCount('cid:' + cid + ':active_users', function(err, amount) {
if (amount > 15) {
db.setRemoveRandom('cid:' + cid + ':active_users');
}
categories.addActiveUser(cid, uid);
});
});
topics.onNewPostMade(tid, pid, timestamp);
categories.onNewPostMade(uid, tid, pid, timestamp);
user.onNewPostMade(uid, tid, pid, timestamp);
plugins.fireHook('filter:post.get', postData, function(err, newPostData) {
if(err) {
return callback(err, null);
}
postData = newPostData;
postTools.parse(postData.content, function(err, content) {
if(err) {
return callback(err, null);
}
postData.content = content;
plugins.fireHook('action:post.save', postData);
db.searchIndex('post', content, pid);
callback(null, postData);
});
});
next(null, postData);
});
});
},
function(postData, next) {
plugins.fireHook('filter:post.get', postData, next);
},
function(postData, next) {
postTools.parse(postData.content, function(err, content) {
if(err) {
return next(err, null);
}
postData.content = content;
plugins.fireHook('action:post.save', postData);
db.searchIndex('post', content, postData.pid);
next(null, postData);
});
}
], function(err, postData) {
callback(err, postData);
});
};
Posts.reply = function(tid, uid, content, callback) {
threadTools.privileges(tid, uid, function(err, privileges) {
if (content) {
content = content.trim();
}
if (!content || content.length < meta.config.minimumPostLength) {
return callback(new Error('content-too-short'));
} else if (!privileges.write) {
return callback(new Error('no-privileges'));
}
Posts.create(uid, tid, content, function(err, postData) {
if(err) {
return callback(err, null);
} else if(!postData) {
callback(new Error('reply-error'), null);
}
Posts.getCidByPid(postData.pid, function(err, cid) {
if(err) {
return callback(err, null);
}
db.delete('cid:' + cid + ':read_by_uid');
});
topics.markAsUnreadForAll(tid, function(err) {
if(err) {
return callback(err, null);
}
topics.markAsRead(tid, uid);
topics.pushUnreadCount();
});
threadTools.notifyFollowers(tid, uid);
Posts.addUserInfoToPost(postData, function(err) {
if(err) {
return callback(err, null);
}
callback(null, postData);
});
});
});
}
Posts.getPostsByTid = function(tid, start, end, callback) {
db.getListRange('tid:' + tid + ':posts', start, end, function(err, pids) {
if(err) {
@@ -294,7 +224,7 @@ var db = require('./database'),
}
if(stripTags) {
postData.content = utils.strip_tags(content);
postData.content = S(content).stripTags().s;
} else {
postData.content = content;
}
@@ -435,38 +365,56 @@ var db = require('./database'),
});
}
Posts.emitContentTooShortAlert = function(socket) {
socket.emit('event:alert', {
type: 'danger',
timeout: 2000,
title: 'Content too short',
message: "Please enter a longer post. At least " + meta.config.minimumPostLength + " characters.",
alert_id: 'post_error'
});
}
Posts.emitTooManyPostsAlert = function(socket) {
socket.emit('event:alert', {
title: 'Too many posts!',
message: 'You can only post every ' + meta.config.postDelay + ' seconds.',
type: 'danger',
timeout: 2000
});
}
Posts.uploadPostImage = function(image, callback) {
if(!image) {
return callback('invalid image', null);
if(meta.config.imgurClientID) {
if(!image) {
return callback('invalid image', null);
}
require('./imgur').upload(meta.config.imgurClientID, image.data, 'base64', function(err, data) {
if(err) {
callback(err.message, null);
} else {
callback(null, {
url: data.link,
name: image.name
});
}
});
} else if (meta.config.allowFileUploads) {
Posts.uploadPostFile(image, callback);
} else {
callback('Uploads are disabled!');
}
}
Posts.uploadPostFile = function(file, callback) {
if(!meta.config.allowFileUploads) {
return callback('File uploads are not allowed');
}
require('./imgur').upload(meta.config.imgurClientID, image.data, 'base64', function(err, data) {
if(!file) {
return callback('invalid file');
}
var buffer = new Buffer(file.data, 'base64');
if(buffer.length > parseInt(meta.config.maximumFileSize, 10) * 1024) {
return callback('File too big');
}
var filename = 'upload-' + utils.generateUUID() + path.extname(file.name);
var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename);
fs.writeFile(uploadPath, buffer, function (err) {
if(err) {
callback(err.message, null);
} else {
callback(null, {
url: data.link,
name: image.name
url: nconf.get('upload_url') + filename,
name: file.name
});
}
});

View File

@@ -11,6 +11,7 @@ var nconf = require('nconf'),
categories = require('./../categories'),
meta = require('../meta'),
plugins = require('../plugins'),
events = require('./../events'),
utils = require('./../../public/src/utils.js');
@@ -56,7 +57,7 @@ var nconf = require('nconf'),
(function () {
var routes = [
'categories/active', 'categories/disabled', 'users', 'topics', 'settings', 'themes',
'twitter', 'facebook', 'gplus', 'database', 'motd', 'groups', 'plugins', 'logger',
'twitter', 'facebook', 'gplus', 'database', 'events', 'motd', 'groups', 'plugins', 'logger',
'users/latest', 'users/sort-posts', 'users/sort-reputation',
'users/search'
];
@@ -103,6 +104,14 @@ var nconf = require('nconf'),
return res.redirect('/403');
var allowedTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'];
var params = null;
try {
params = JSON.parse(req.body.params);
} catch (e) {
return res.send({
error: 'Error uploading file! Error :' + e.message
});
}
if (allowedTypes.indexOf(req.files.userPhoto.type) === -1) {
res.send({
@@ -111,38 +120,9 @@ var nconf = require('nconf'),
return;
}
var tempPath = req.files.userPhoto.path;
var extension = path.extname(req.files.userPhoto.name);
var filename = 'category-' + params.cid + path.extname(req.files.userPhoto.name);
if (!extension) {
res.send({
error: 'Error uploading file! Error : Invalid extension!'
});
return;
}
var filename = 'category' + utils.generateUUID() + extension;
var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename);
winston.info('Attempting upload to: ' + uploadPath);
var is = fs.createReadStream(tempPath);
var os = fs.createWriteStream(uploadPath);
is.on('end', function () {
fs.unlinkSync(tempPath);
console.log(nconf.get('upload_url') + filename);
res.json({
path: nconf.get('upload_url') + filename
});
});
os.on('error', function (err) {
fs.unlinkSync(tempPath);
winston.err(err);
});
is.pipe(os);
uploadImage(filename, req, res);
});
app.post('/uploadfavicon', function(req, res) {
@@ -158,38 +138,7 @@ var nconf = require('nconf'),
return;
}
var tempPath = req.files.userPhoto.path;
var extension = path.extname(req.files.userPhoto.name);
if (!extension) {
res.send({
error: 'Error uploading file! Error : Invalid extension!'
});
return;
}
var filename = 'favicon.ico';
var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename);
winston.info('Attempting upload to: ' + uploadPath);
var is = fs.createReadStream(tempPath);
var os = fs.createWriteStream(uploadPath);
is.on('end', function () {
fs.unlinkSync(tempPath);
res.json({
path: nconf.get('upload_url') + filename
});
});
os.on('error', function (err) {
fs.unlinkSync(tempPath);
winston.err(err);
});
is.pipe(os);
uploadImage('favicon.ico', req, res);
});
app.post('/uploadlogo', function(req, res) {
@@ -206,41 +155,46 @@ var nconf = require('nconf'),
return;
}
var tempPath = req.files.userPhoto.path;
var extension = path.extname(req.files.userPhoto.name);
var filename = 'site-logo' + path.extname(req.files.userPhoto.name);
if (!extension) {
res.send({
error: 'Error uploading file! Error : Invalid extension!'
});
return;
}
var filename = 'site-logo' + extension;
var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename);
winston.info('Attempting upload to: ' + uploadPath);
var is = fs.createReadStream(tempPath);
var os = fs.createWriteStream(uploadPath);
is.on('end', function () {
fs.unlinkSync(tempPath);
res.json({
path: nconf.get('upload_url') + filename
});
});
os.on('error', function (err) {
fs.unlinkSync(tempPath);
winston.err(err);
});
is.pipe(os);
uploadImage(filename, req, res);
});
});
function uploadImage(filename, req, res) {
var tempPath = req.files.userPhoto.path;
var extension = path.extname(req.files.userPhoto.name);
if (!extension) {
res.send({
error: 'Error uploading file! Error : Invalid extension!'
});
return;
}
var uploadPath = path.join(nconf.get('base_dir'), nconf.get('upload_path'), filename);
winston.info('Attempting upload to: ' + uploadPath);
var is = fs.createReadStream(tempPath);
var os = fs.createWriteStream(uploadPath);
is.on('end', function () {
fs.unlinkSync(tempPath);
res.json({
path: nconf.get('upload_url') + filename
});
});
os.on('error', function (err) {
fs.unlinkSync(tempPath);
winston.err(err);
});
is.pipe(os);
}
var custom_routes = {
'routes': [],
@@ -403,6 +357,15 @@ var nconf = require('nconf'),
// });
});
app.get('/events', function(req, res, next) {
events.getLog(function(err, data) {
if(err) {
return next(err);
}
res.json(200, {eventdata: data.toString()});
});
});
app.get('/plugins', function (req, res) {
plugins.showInstalled(function (err, plugins) {
if (err || !Array.isArray(plugins)) plugins = [];

View File

@@ -30,6 +30,7 @@ var path = require('path'),
config.postDelay = meta.config.postDelay;
config.minimumTitleLength = meta.config.minimumTitleLength;
config.maximumTitleLength = meta.config.maximumTitleLength;
config.minimumPostLength = meta.config.minimumPostLength;
config.imgurClientIDSet = !! meta.config.imgurClientID;
config.minimumUsernameLength = meta.config.minimumUsernameLength;
@@ -39,6 +40,8 @@ var path = require('path'),
config.useOutgoingLinksPage = meta.config.useOutgoingLinksPage;
config.allowGuestPosting = meta.config.allowGuestPosting;
config.allowRegistration = meta.config.allowRegistration || '1';
config.allowFileUploads = meta.config.allowFileUploads;
config.maximumFileSize = meta.config.maximumFileSize;
config.emailSetup = !!meta.config['email:from'];
res.json(200, config);
@@ -52,9 +55,9 @@ var path = require('path'),
});
function iterator(category, callback) {
categories.getRecentReplies(category.cid, 2, function (err, posts) {
categories.getRecentReplies(category.cid, parseInt(category.numRecentReplies, 10), function (err, posts) {
category.posts = posts;
category.post_count = posts.length > 2 ? 2 : posts.length;
category.post_count = posts.length > 2 ? 2 : posts.length; // this was a hack to make metro work back in the day, post_count should just = length
callback(null);
});
}
@@ -63,7 +66,7 @@ var path = require('path'),
data.motd_class = (parseInt(meta.config.show_motd, 10) === 1 || meta.config.show_motd === undefined) ? '' : ' none';
data.motd_class += (meta.config.motd && meta.config.motd.length > 0 ? '' : ' default');
data.motd = require('marked')(meta.config.motd || "<div class=\"pull-right btn-group\"><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-comment\"></i><span class='hidden-mobile'>&nbsp;Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-github\"></i><span class='hidden-mobile'>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/dcplabs\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-twitter\"></i><span class='hidden-mobile'>&nbsp;@NodeBB</span></a></div>\n\n# NodeBB <span>v" + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.");
data.motd = require('marked')(meta.config.motd || "<div class=\"pull-right btn-group\"><a target=\"_blank\" href=\"http://www.nodebb.org\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-comment\"></i><span class='hidden-mobile'>&nbsp;Get NodeBB</span></a> <a target=\"_blank\" href=\"https://github.com/designcreateplay/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-github\"></i><span class='hidden-mobile'>&nbsp;Fork us on Github</span></a> <a target=\"_blank\" href=\"https://twitter.com/NodeBB\" class=\"btn btn-default btn-lg\"><i class=\"fa fa-twitter\"></i><span class='hidden-mobile'>&nbsp;@NodeBB</span></a></div>\n\n# NodeBB <span>v" + pkg.version + "</span>\nWelcome to NodeBB, the discussion platform of the future.");
res.json(data);
});
});

View File

@@ -161,12 +161,7 @@ var fs = require('fs'),
is.on('end', function () {
fs.unlinkSync(tempPath);
im.crop({
srcPath: uploadPath,
dstPath: uploadPath,
width: 128,
height: 128
}, function (err, stdout, stderr) {
function done(err) {
if (err) {
winston.err(err);
res.send({
@@ -180,7 +175,7 @@ var fs = require('fs'),
user.setUserField(uid, 'uploadedpicture', imageUrl);
user.setUserField(uid, 'picture', imageUrl);
if (convertToPNG) {
if (convertToPNG && extension !== '.png') {
im.convert([uploadPath, 'png:-'],
function(err, stdout){
if (err) {
@@ -195,11 +190,25 @@ var fs = require('fs'),
});
}
res.json({
path: imageUrl
});
});
}
if(extension === '.gif') {
im.convert([uploadPath, '-coalesce', '-repage', '0x0', '-crop', '128x128+0+0', '+repage', 'uploadPath'], function(err, stdout) {
done(err);
});
} else {
im.crop({
srcPath: uploadPath,
dstPath: uploadPath,
width: 128,
height: 128
}, function (err, stdout, stderr) {
done(err);
});
}
});
os.on('error', function (err) {
@@ -521,11 +530,16 @@ var fs = require('fs'),
user.getUserData(uid, function (err, data) {
if (data) {
data.joindate = new Date(parseInt(data.joindate, 10)).toISOString();
if(data.lastonline) {
data.lastonline = new Date(parseInt(data.lastonline, 10)).toISOString();
} else {
data.lastonline = data.joindate;
}
if (!data.birthday) {
data.age = '';
} else {
data.age = new Date().getFullYear() - new Date(data.birthday).getFullYear();
data.age = Math.floor((new Date().getTime() - new Date(data.birthday).getTime()) / 31536000000);
}
function canSeeEmail() {
@@ -567,4 +581,4 @@ var fs = require('fs'),
};
}(exports));
}(exports));

View File

@@ -91,7 +91,7 @@ var winston = require('winston'),
}
}
ThreadTools.delete = function(tid, callback) {
ThreadTools.delete = function(tid, uid, callback) {
topics.delete(tid);
db.decrObjectField('global', 'topicCount');
@@ -112,7 +112,7 @@ var winston = require('winston'),
}
}
ThreadTools.restore = function(tid, socket, callback) {
ThreadTools.restore = function(tid, uid, callback) {
topics.restore(tid);
db.incrObjectField('global', 'topicCount');
ThreadTools.unlock(tid);

View File

@@ -2,6 +2,7 @@ var async = require('async'),
gravatar = require('gravatar'),
nconf = require('nconf'),
validator = require('validator'),
S = require('string'),
db = require('./database'),
posts = require('./posts'),
@@ -22,6 +23,50 @@ var async = require('async'),
(function(Topics) {
Topics.create = function(uid, title, cid, callback) {
db.incrObjectField('global', 'nextTid', function(err, tid) {
if(err) {
return callback(err);
}
db.setAdd('topics:tid', tid);
var slug = tid + '/' + utils.slugify(title),
timestamp = Date.now();
db.setObject('topic:' + tid, {
'tid': tid,
'uid': uid,
'cid': cid,
'title': title,
'slug': slug,
'timestamp': timestamp,
'lastposttime': 0,
'postcount': 0,
'viewcount': 0,
'locked': 0,
'deleted': 0,
'pinned': 0
}, function(err) {
if(err) {
return callback(err);
}
db.searchIndex('topic', title, tid);
user.addTopicIdToUser(uid, tid);
// in future it may be possible to add topics to several categories, so leaving the door open here.
db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
db.incrObjectField('category:' + cid, 'topic_count');
db.incrObjectField('global', 'topicCount');
feed.updateCategory(cid);
callback(null, tid);
});
});
};
Topics.post = function(uid, title, content, cid, callback) {
categoryTools.privileges(cid, uid, function(err, privileges) {
@@ -32,8 +77,10 @@ var async = require('async'),
return callback(new Error('no-privileges'));
} else if (!cid) {
return callback(new Error('invalid-cid'));
} else if (!title || title.length < meta.config.minimumTitleLength) {
} else if (!title || title.length < parseInt(meta.config.minimumTitleLength, 10)) {
return callback(new Error('title-too-short'), null);
} else if(title.length > parseInt(meta.config.maximumTitleLength, 10)) {
return callback(new Error('title-too-long'), null);
} else if (!content || content.length < meta.config.miminumPostLength) {
return callback(new Error('content-too-short'), null);
}
@@ -58,58 +105,20 @@ var async = require('async'),
return callback(new Error('too-many-posts'), null);
}
db.incrObjectField('global', 'nextTid', function(err, tid) {
Topics.create(uid, title, cid, function(err, tid) {
if(err) {
return callback(err);
}
db.setAdd('topics:tid', tid);
var slug = tid + '/' + utils.slugify(title);
var timestamp = Date.now();
db.setObject('topic:' + tid, {
'tid': tid,
'uid': uid,
'cid': cid,
'title': title,
'slug': slug,
'timestamp': timestamp,
'lastposttime': 0,
'postcount': 0,
'viewcount': 0,
'locked': 0,
'deleted': 0,
'pinned': 0
});
db.searchIndex('topic', title, tid);
user.addTopicIdToUser(uid, tid);
// let everyone know that there is an unread topic in this category
db.delete('cid:' + cid + ':read_by_uid', function(err, data) {
Topics.markAsRead(tid, uid);
});
// in future it may be possible to add topics to several categories, so leaving the door open here.
db.sortedSetAdd('categories:' + cid + ':tid', timestamp, tid);
db.incrObjectField('category:' + cid, 'topic_count');
db.incrObjectField('global', 'topicCount');
feed.updateCategory(cid);
posts.create(uid, tid, content, function(err, postData) {
Topics.reply(tid, uid, content, function(err, postData) {
if(err) {
return callback(err, null);
} else if(!postData) {
return callback(new Error('invalid-post'), null);
}
// Auto-subscribe the post creator to the newly created topic
threadTools.toggleFollow(tid, uid);
Topics.pushUnreadCount();
Topics.getTopicForCategoryView(tid, uid, function(topicData) {
topicData.unreplied = 1;
@@ -124,6 +133,105 @@ var async = require('async'),
});
};
Topics.reply = function(tid, uid, content, callback) {
threadTools.privileges(tid, uid, function(err, privileges) {
if (content) {
content = content.trim();
}
if (!content || content.length < meta.config.minimumPostLength) {
return callback(new Error('content-too-short'));
} else if (!privileges.write) {
return callback(new Error('no-privileges'));
}
posts.create(uid, tid, content, function(err, postData) {
if(err) {
return callback(err, null);
} else if(!postData) {
callback(new Error('reply-error'), null);
}
posts.getCidByPid(postData.pid, function(err, cid) {
if(err) {
return callback(err, null);
}
db.delete('cid:' + cid + ':read_by_uid', function(err) {
Topics.markAsUnreadForAll(tid, function(err) {
if(err) {
return callback(err, null);
}
Topics.markAsRead(tid, uid);
Topics.pushUnreadCount();
});
});
});
db.getObjectField('tid:lastFeedUpdate', tid, function(err, lastFeedUpdate) {
var now = Date.now();
if(!lastFeedUpdate || parseInt(lastFeedUpdate, 10) < now - 3600000) {
feed.updateTopic(tid);
db.setObjectField('tid:lastFeedUpdate', tid, now);
}
});
feed.updateRecent();
threadTools.notifyFollowers(tid, uid);
user.sendPostNotificationToFollowers(uid, tid, postData.pid);
posts.addUserInfoToPost(postData, function(err) {
if(err) {
return callback(err, null);
}
postData.favourited = false;
postData.display_moderator_tools = true;
postData.relativeTime = new Date(postData.timestamp).toISOString();
callback(null, postData);
});
});
});
}
Topics.createTopicFromPost = function(pid, callback) {
posts.getPostData(pid, function(err, postData) {
if(err) {
return callback(err);
}
posts.getCidByPid(pid, function(err, cid) {
if(err) {
return callback(err);
}
// TODO : title should be given by client
var title = postData.content.substr(0, 20);
Topics.create(postData.uid, title, cid, function(err, tid) {
if(err) {
return callback(err);
}
Topics.removePostFromTopic(postData.tid, postData.pid);
Topics.decreasePostCount(postData.tid);
posts.setPostField(pid, 'tid', tid);
Topics.onNewPostMade(tid, postData.pid, postData.timestamp);
Topics.getTopicData(tid, function(err, topicData) {
callback(err, topicData);
});
});
});
});
}
Topics.getTopicData = function(tid, callback) {
db.getObject('topic:' + tid, function(err, data) {
if(err) {
@@ -398,9 +506,10 @@ var async = require('async'),
}
function sendUnreadTopics(topicIds) {
Topics.getTopicsByTids(topicIds, uid, function(topicData) {
unreadTopics.topics = topicData;
unreadTopics.nextStart = start + topicIds.length;
unreadTopics.nextStart = stop + 1;
if (!topicData || topicData.length === 0) {
unreadTopics.no_topics_message = 'show';
}
@@ -606,6 +715,7 @@ var async = require('async'),
'unreplied': parseInt(topicData.postcount, 10) > 1,
'topic_id': tid,
'expose_tools': privileges.editable ? 1 : 0,
'disableSocialButtons': meta.config.disableSocialButtons !== undefined ? parseInt(meta.config.disableSocialButtons, 10) !== 0 : false,
'posts': topicPosts
});
});
@@ -826,7 +936,7 @@ var async = require('async'),
if (postData.content) {
stripped = postData.content.replace(/>.+\n\n/, '');
postTools.parse(stripped, function(err, stripped) {
returnObj.text = utils.strip_tags(stripped);
returnObj.text = S(stripped).stripTags().s;
callback(null, returnObj);
});
} else {
@@ -838,16 +948,6 @@ var async = require('async'),
});
}
Topics.emitTitleTooShortAlert = function(socket) {
socket.emit('event:alert', {
type: 'danger',
timeout: 2000,
title: 'Title too short',
message: "Please enter a longer title. At least " + meta.config.minimumTitleLength + " characters.",
alert_id: 'post_error'
});
}
Topics.getTopicField = function(tid, field, callback) {
db.getObjectField('topic:' + tid, field, callback);
}
@@ -864,6 +964,10 @@ var async = require('async'),
db.incrObjectField('topic:' + tid, 'postcount', callback);
}
Topics.decreasePostCount = function(tid, callback) {
db.decrObjectField('topic:' + tid, 'postcount', callback);
}
Topics.increaseViewCount = function(tid, callback) {
db.incrObjectField('topic:' + tid, 'viewcount', callback);
}
@@ -882,10 +986,20 @@ var async = require('async'),
Topics.setTopicField(tid, 'lastposttime', timestamp);
}
Topics.onNewPostMade = function(tid, pid, timestamp) {
Topics.addPostToTopic(tid, pid);
Topics.increasePostCount(tid);
Topics.updateTimestamp(tid, timestamp);
}
Topics.addPostToTopic = function(tid, pid) {
db.listAppend('tid:' + tid + ':posts', pid);
}
Topics.removePostFromTopic = function(tid, pid) {
db.listRemoveAll('tid:' + tid + ':posts', pid);
}
Topics.getPids = function(tid, callback) {
db.getListRange('tid:' + tid + ':posts', 0, -1, callback);
}

View File

@@ -3,16 +3,20 @@
var db = require('./database'),
async = require('async'),
winston = require('winston'),
User = require('./user'),
Topics = require('./topics'),
Utils = require('../public/src/utils'),
notifications = require('./notifications'),
categories = require('./categories'),
nconf = require('nconf'),
Upgrade = {},
schemaDate, thisSchemaDate;
Upgrade.check = function(callback) {
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema
var latestSchema = new Date(2013, 11, 11).getTime();
var latestSchema = new Date(2014, 0, 4).getTime();
db.get('schemaDate', function(err, value) {
if (parseInt(value, 10) >= latestSchema) {
@@ -24,28 +28,13 @@ Upgrade.check = function(callback) {
};
Upgrade.upgrade = function(callback) {
var databaseType = nconf.get('database');
var updatesMade = false;
if(databaseType === 'redis') {
Upgrade.upgradeRedis(callback);
} else if(databaseType === 'mongo') {
Upgrade.upgradeMongo(callback);
} else {
winston.error('Unknown database type. Aborting upgrade');
callback(new Error('unknown-database'));
}
};
Upgrade.upgradeRedis = function(callback) {
var RDB = db.client,
updatesMade = false;
winston.info('Beginning Redis database schema update');
winston.info('Beginning database schema update');
async.series([
function(next) {
RDB.get('schemaDate', function(err, value) {
db.get('schemaDate', function(err, value) {
schemaDate = value;
next();
});
@@ -56,11 +45,11 @@ Upgrade.upgradeRedis = function(callback) {
updatesMade = true;
async.series([
function(next) {
RDB.keys('uid:*:notifications:flag', function(err, keys) {
db.keys('uid:*:notifications:flag', function(err, keys) {
if (keys.length > 0) {
winston.info('[2013/10/03] Removing deprecated Notification Flags');
async.each(keys, function(key, next) {
RDB.del(key, next);
db.delete(key, next);
}, next);
} else {
winston.info('[2013/10/03] No Notification Flags found. Good.');
@@ -70,13 +59,13 @@ Upgrade.upgradeRedis = function(callback) {
},
function(next) {
winston.info('[2013/10/03] Updating Notifications');
RDB.keys('uid:*:notifications:*', function(err, keys) {
db.keys('uid:*:notifications:*', function(err, keys) {
async.each(keys, function(key, next) {
RDB.zrange(key, 0, -1, function(err, nids) {
db.getSortedSetRange(key, 0, -1, function(err, nids) {
async.each(nids, function(nid, next) {
notifications.get(nid, null, function(notif_data) {
if (notif_data) {
RDB.zadd(key, notif_data.datetime, nid, next);
db.sortedSetAdd(key, notif_data.datetime, nid, next);
} else {
next();
}
@@ -87,7 +76,7 @@ Upgrade.upgradeRedis = function(callback) {
});
},
function(next) {
RDB.keys('notifications:*', function(err, keys) {
db.keys('notifications:*', function(err, keys) {
if (keys.length > 0) {
winston.info('[2013/10/03] Removing Notification Scores');
async.each(keys, function(key, next) {
@@ -95,7 +84,7 @@ Upgrade.upgradeRedis = function(callback) {
return next();
}
RDB.hdel(key, 'score', next);
db.deleteObjectField(key, 'score', next);
}, next);
} else {
winston.info('[2013/10/03] No Notification Scores found. Good.');
@@ -113,7 +102,7 @@ Upgrade.upgradeRedis = function(callback) {
thisSchemaDate = new Date(2013, 9, 23).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
RDB.keys('notifications:*', function(err, keys) {
db.keys('notifications:*', function(err, keys) {
keys = keys.filter(function(key) {
if (key === 'notifications:next_nid') {
@@ -129,9 +118,11 @@ Upgrade.upgradeRedis = function(callback) {
if(keys && Array.isArray(keys)) {
async.each(keys, function(key, cb) {
RDB.sadd('notifications', key, cb);
db.setAdd('notifications', key, cb);
}, next);
} else next();
} else {
next();
}
});
} else {
@@ -143,7 +134,7 @@ Upgrade.upgradeRedis = function(callback) {
thisSchemaDate = new Date(2013, 10, 11).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
RDB.hset('config', 'postDelay', 10, function(err, success) {
db.setObjectField('config', 'postDelay', 10, function(err, success) {
winston.info('[2013/11/11] Updated postDelay to 10 seconds.');
next();
});
@@ -156,10 +147,10 @@ Upgrade.upgradeRedis = function(callback) {
thisSchemaDate = new Date(2013, 10, 22).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
RDB.keys('category:*', function(err, categories) {
db.keys('category:*', function(err, categories) {
async.each(categories, function(categoryStr, next) {
var hex;
RDB.hgetall(categoryStr, function(err, categoryObj) {
db.getObject(categoryStr, function(err, categoryObj) {
switch(categoryObj.blockclass) {
case 'category-purple':
hex = '#ab1290';
@@ -186,8 +177,8 @@ Upgrade.upgradeRedis = function(callback) {
break;
}
RDB.hset(categoryStr, 'bgColor', hex, next);
RDB.hdel(categoryStr, 'blockclass');
db.setObjectField(categoryStr, 'bgColor', hex, next);
db.deleteObjectField(categoryStr, 'blockclass');
});
}, function() {
winston.info('[2013/11/22] Updated Category colours.');
@@ -217,7 +208,7 @@ Upgrade.upgradeRedis = function(callback) {
icon = category.icon.replace('icon-', 'fa-');
}
RDB.hset('category:' + category.cid, 'icon', icon, next);
db.setObjectField('category:' + category.cid, 'icon', icon, next);
}
async.each(categories.categories, updateIcon, function(err) {
@@ -236,15 +227,15 @@ Upgrade.upgradeRedis = function(callback) {
function(next) {
function updateKeyToHash(key, next) {
RDB.get(key, function(err, value) {
db.get(key, function(err, value) {
if(err) {
return next(err);
}
if(value === null) {
RDB.hset('global', newKeys[key], initialValues[key], next);
db.setObjectField('global', newKeys[key], initialValues[key], next);
} else {
RDB.hset('global', newKeys[key], value, next);
db.setObjectField('global', newKeys[key], value, next);
}
});
}
@@ -305,67 +296,6 @@ Upgrade.upgradeRedis = function(callback) {
}
},
function(next) {
thisSchemaDate = new Date(2013, 11, 11).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
RDB.hset('config', 'allowGuestSearching', '0', function(err){
if (err) {
return next(err);
}
winston.info('[2013/12/11] Updated guest search config.');
next();
});
} else {
winston.info('[2013/12/11] Update to guest search skipped');
next();
}
}
// Add new schema updates here
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 12!!!
], function(err) {
if (!err) {
RDB.set('schemaDate', thisSchemaDate, function(err) {
if (!err) {
if(updatesMade) {
winston.info('[upgrade] Redis schema update complete!');
} else {
winston.info('[upgrade] Redis schema already up to date!');
}
if (callback) {
callback(err);
} else {
process.exit();
}
} else {
winston.error('[upgrade] Could not update NodeBB schema date!');
process.exit();
}
});
} else {
winston.error('[upgrade] Errors were encountered while updating the NodeBB schema: ' + err.message);
process.exit();
}
});
};
Upgrade.upgradeMongo = function(callback) {
// why can't we just use the abstracted db module here? and in upgradeRedis()?
var MDB = db.client,
updatesMade = false;
winston.info('Beginning Mongo database schema update');
async.series([
function(next) {
db.get('schemaDate', function(err, value) {
schemaDate = value;
thisSchemaDate = new Date(2013, 11, 6).getTime();
next();
});
},
function(next) {
thisSchemaDate = new Date(2013, 11, 11).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
@@ -381,17 +311,144 @@ Upgrade.upgradeMongo = function(callback) {
winston.info('[2013/12/11] Update to guest search skipped');
next();
}
},
function(next) {
thisSchemaDate = new Date(2013, 11, 31).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
async.parallel([
function(next) {
// Re-slugify all topics
db.getSortedSetRange('topics:recent', 0, -1, function(err, tids) {
var newTitle;
async.each(tids, function(tid, next) {
Topics.getTopicField(tid, 'title', function(err, title) {
newTitle = tid + '/' + Utils.slugify(title);
Topics.setTopicField(tid, 'slug', newTitle, next);
});
}, function(err) {
next(err);
});
});
},
function(next) {
// Re-slugify all users
db.getObjectValues('username:uid', function(err, uids) {
var newUserSlug;
async.each(uids, function(uid, next) {
User.getUserField(uid, 'username', function(err, username) {
if(err) {
return next(err);
}
if(username) {
newUserSlug = Utils.slugify(username);
User.setUserField(uid, 'userslug', newUserSlug, next);
} else {
winston.warn('uid '+ uid + ' doesn\'t have a valid username (' + username + '), skipping');
next(null);
}
});
}, function(err) {
next(err);
});
});
}
], function(err) {
winston.info('[2013/12/31] Re-slugify Topics and Users');
next(err);
});
} else {
winston.info('[2013/12/31] Re-slugify Topics and Users skipped');
next();
}
},
function(next) {
thisSchemaDate = new Date(2014, 0, 1).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
db.isObjectField('config', 'maximumTitleLength', function(err, isField) {
if(err) {
return next(err);
}
if(!isField) {
db.setObjectField('config', 'maximumTitleLength', 255, function(err) {
if(err) {
return next(err);
}
winston.info('[2013/12/31] Added maximumTitleLength');
next();
});
} else {
winston.info('[2013/12/31] maximumTitleLength already set');
next();
}
});
} else {
winston.info('[2013/12/31] maximumTitleLength skipped');
next();
}
},
function(next) {
// Custom classes for each category, adding link field for each category
thisSchemaDate = new Date(2014, 0, 3).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
db.getListRange('categories:cid', 0, -1, function(err, cids) {
if(err) {
return next(err);
}
for (var cid in cids) {
db.setObjectField('category:' + cids[cid], 'link', '');
db.setObjectField('category:' + cids[cid], 'class', 'col-md-3 col-xs-6');
}
winston.info('[2013/12/31] Added categories.class, categories.link fields');
next();
});
} else {
winston.info('[2014/1/3] categories.class, categories.link fields skipped');
next();
}
},
function(next) {
// Custom classes for each category, adding link field for each category
thisSchemaDate = new Date(2014, 0, 4).getTime();
if (schemaDate < thisSchemaDate) {
updatesMade = true;
db.getListRange('categories:cid', 0, -1, function(err, cids) {
if(err) {
return next(err);
}
for (var cid in cids) {
db.setObjectField('category:' + cids[cid], 'numRecentReplies', '2');
}
winston.info('[2013/12/31] Added categories.numRecentReplies fields');
next();
});
} else {
winston.info('[2014/1/3] categories.numRecentReplies fields skipped');
next();
}
}
// Add new schema updates here
// IMPORTANT: REMEMBER TO UPDATE VALUE OF latestSchema IN LINE 17!!!
], function(err) {
if (!err) {
db.set('schemaDate', thisSchemaDate, function(err) {
if (!err) {
if(updatesMade) {
winston.info('[upgrade] Mongo schema update complete!');
winston.info('[upgrade] Schema update complete!');
} else {
winston.info('[upgrade] Mongo schema already up to date!');
winston.info('[upgrade] Schema already up to date!');
}
if (callback) {
callback(err);
@@ -399,7 +456,7 @@ Upgrade.upgradeMongo = function(callback) {
process.exit();
}
} else {
winston.error('[upgrade] Could not update NodeBB schema date!');
winston.error('[upgrade] Could not update NodeBB schema data!');
process.exit();
}
});
@@ -408,6 +465,6 @@ Upgrade.upgradeMongo = function(callback) {
process.exit();
}
});
}
};
module.exports = Upgrade;

View File

@@ -6,6 +6,7 @@ var bcrypt = require('bcrypt'),
gravatar = require('gravatar'),
check = require('validator').check,
sanitize = require('validator').sanitize,
S = require('string'),
utils = require('./../public/src/utils'),
plugins = require('./plugins'),
@@ -266,7 +267,7 @@ var bcrypt = require('bcrypt'),
});
return;
} else if (field === 'signature') {
data[field] = utils.strip_tags(data[field]);
data[field] = S(data[field]).stripTags().s;
} else if (field === 'website') {
if(data[field].substr(0, 7) !== 'http://' && data[field].substr(0, 8) !== 'https://') {
data[field] = 'http://' + data[field];
@@ -432,8 +433,6 @@ var bcrypt = require('bcrypt'),
});
User.setUserField(uid, 'lastposttime', timestamp);
User.sendPostNotificationToFollowers(uid, tid, pid);
};
User.addPostIdToUser = function(uid, pid) {
@@ -756,7 +755,7 @@ var bcrypt = require('bcrypt'),
// Generate a new reset code
var reset_code = utils.generateUUID();
db.setObjectField('reset:uid', reset_code, uid);
db.setobjectField('reset:expiry', reset_code, (60 * 60) + new Date() / 1000 | 0); // Active for one hour
db.setObjectField('reset:expiry', reset_code, (60 * 60) + new Date() / 1000 | 0); // Active for one hour
var reset_link = nconf.get('url') + 'reset/' + reset_code,
reset_email = global.templates['emails/reset'].parse({

View File

@@ -9,6 +9,7 @@ var path = require('path'),
winston = require('winston'),
validator = require('validator'),
async = require('async'),
S = require('string'),
pkg = require('../package.json'),
@@ -54,7 +55,7 @@ var path = require('path'),
/**
* `options` object requires: req, res
* accepts: metaTags
* accepts: metaTags, linkTags
*/
app.build_header = function (options, callback) {
var custom_header = {
@@ -82,8 +83,6 @@ var path = require('path'),
rel: 'apple-touch-icon',
href: meta.config['brand:logo'] || nconf.get('relative_path') + '/logo.png'
}],
metaString = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || [])),
linkTags = utils.buildLinkTags(defaultLinkTags.concat(options.linkTags || [])),
templateValues = {
cssSrc: meta.config['theme:src'] || nconf.get('relative_path') + '/vendor/bootstrap/css/bootstrap.min.css',
pluginCSS: plugins.cssFiles.map(function(file) { return { path: file + (meta.config['cache-buster'] ? '?v=' + meta.config['cache-buster'] : '') }; }),
@@ -95,16 +94,30 @@ var path = require('path'),
browserTitle: meta.config.title || 'NodeBB',
csrf: options.res.locals.csrf_token,
relative_path: nconf.get('relative_path'),
meta_tags: metaString,
link_tags: linkTags,
clientScripts: clientScripts,
navigation: custom_header.navigation,
'cache-buster': meta.config['cache-buster'] ? 'v=' + meta.config['cache-buster'] : '',
allowRegistration: meta.config.allowRegistration === undefined || parseInt(meta.config.allowRegistration, 10) === 1
},
escapeList = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&apos;',
'"': '&quot;'
};
var uid = '0';
// Meta Tags
templateValues.meta_tags = utils.buildMetaTags(defaultMetaTags.concat(options.metaTags || []).map(function(tag) {
tag.content = tag.content.replace(/[&<>'"]/g, function(tag) {
return escapeList[tag] || tag;
});
return tag;
}));
templateValues.link_tags = utils.buildLinkTags(defaultLinkTags.concat(options.linkTags || []));
if(options.req.user && options.req.user.uid) {
uid = options.req.user.uid;
}
@@ -182,6 +195,13 @@ var path = require('path'),
// Authentication Routes
auth.initialize(app);
app.use(function(req, res, next) {
if(req.user) {
user.setUserField(req.user.uid, 'lastonline', Date.now());
}
next();
})
next();
},
function(next) {
@@ -507,8 +527,17 @@ var path = require('path'),
},
function (topicData, next) {
var lastMod = 0,
timestamp,
sanitize = validator.sanitize;
sanitize = validator.sanitize,
description = (function() {
var content = S(topicData.posts[0].content).stripTags().s;
if (content.length > 255) {
content = content.substr(0, 255) + '...';
}
return sanitize(content).escape();
})(),
timestamp;
for (var x = 0, numPosts = topicData.posts.length; x < numPosts; x++) {
timestamp = parseInt(topicData.posts[x].timestamp, 10);
@@ -520,34 +549,48 @@ var path = require('path'),
app.build_header({
req: req,
res: res,
metaTags: [{
name: "title",
content: topicData.topic_name
}, {
name: "description",
content: sanitize(topicData.posts[0].content.substr(0, 255)).escape().replace('\n', '')
}, {
property: 'og:title',
content: topicData.topic_name + ' | ' + (meta.config.title || 'NodeBB')
}, {
property: "og:type",
content: 'article'
}, {
property: "og:url",
content: nconf.get('url') + 'topic/' + topicData.slug
}, {
property: 'og:image',
content: topicData.posts[0].picture
}, {
property: "article:published_time",
content: new Date(parseInt(topicData.posts[0].timestamp, 10)).toISOString()
}, {
property: 'article:modified_time',
content: new Date(lastMod).toISOString()
}, {
property: 'article:section',
content: topicData.category_name
}],
metaTags: [
{
name: "title",
content: topicData.topic_name
},
{
name: "description",
content: description
},
{
property: 'og:title',
content: topicData.topic_name + ' | ' + (meta.config.title || 'NodeBB')
},
{
property: 'og:description',
content: description
},
{
property: "og:type",
content: 'article'
},
{
property: "og:url",
content: nconf.get('url') + 'topic/' + topicData.slug
},
{
property: 'og:image',
content: topicData.posts[0].picture
},
{
property: "article:published_time",
content: new Date(parseInt(topicData.posts[0].timestamp, 10)).toISOString()
},
{
property: 'article:modified_time',
content: new Date(lastMod).toISOString()
},
{
property: 'article:section',
content: topicData.category_name
}
],
linkTags: [
{
rel: 'alternate',
@@ -783,7 +826,8 @@ var path = require('path'),
var custom_routes = {
'routes': [],
'api': []
'api': [],
'templates': []
};
plugins.ready(function() {
@@ -819,6 +863,17 @@ var path = require('path'),
}
}
var templateRoutes = custom_routes.templates;
for (var route in templateRoutes) {
if (templateRoutes.hasOwnProperty(route)) {
(function(route) {
app.get('/templates/' + templateRoutes[route].template, function(req, res) {
res.send(templateRoutes[route].content);
});
}(route));
}
}
});
});

View File

@@ -8,6 +8,7 @@ var cookie = require('cookie'),
nconf = require('nconf'),
gravatar = require('gravatar'),
winston = require('winston'),
S = require('string'),
db = require('./database'),
@@ -105,12 +106,12 @@ websockets.init = function(io) {
socket.on('disconnect', function() {
var index = userSockets[uid].indexOf(socket);
var index = (userSockets[uid] || []).indexOf(socket);
if (index !== -1) {
userSockets[uid].splice(index, 1);
}
if (userSockets[uid].length === 0) {
if (userSockets[uid] && userSockets[uid].length === 0) {
delete users[sessionID];
delete userSockets[uid];
if (uid) {
@@ -361,6 +362,35 @@ websockets.init = function(io) {
}
});
function emitAlert(socket, title, message) {
socket.emit('event:alert', {
type: 'danger',
timeout: 2000,
title: title,
message: message,
alert_id: 'post_error'
});
}
function emitContentTooShortAlert(socket) {
socket.emit('event:alert', {
type: 'danger',
timeout: 2000,
title: 'Content too short',
message: "Please enter a longer post. At least " + meta.config.minimumPostLength + " characters.",
alert_id: 'post_error'
});
}
function emitTooManyPostsAlert(socket) {
socket.emit('event:alert', {
title: 'Too many posts!',
message: 'You can only post every ' + meta.config.postDelay + ' seconds.',
type: 'danger',
timeout: 2000
});
}
socket.on('api:topics.post', function(data) {
if (uid < 1 && parseInt(meta.config.allowGuestPosting, 10) === 0) {
socket.emit('event:alert', {
@@ -375,11 +405,13 @@ websockets.init = function(io) {
topics.post(uid, data.title, data.content, data.category_id, function(err, result) {
if(err) {
if (err.message === 'title-too-short') {
topics.emitTitleTooShortAlert(socket);
emitAlert(socket, 'Title too short', 'Please enter a longer title. At least ' + meta.config.minimumTitleLength + ' characters.');
} else if (err.message === 'title-too-long') {
emitAlert(socket, 'Title too long', 'Please enter a shorter title. Titles can\'t be longer than ' + meta.config.maximumTitleLength + ' characters.');
} else if (err.message === 'content-too-short') {
posts.emitContentTooShortAlert(socket);
emitContentTooShortAlert(socket);
} else if (err.message === 'too-many-posts') {
posts.emitTooManyPostsAlert(socket);
emitTooManyPostsAlert(socket);
} else if (err.message === 'no-privileges') {
socket.emit('event:alert', {
title: 'Unable to post',
@@ -444,16 +476,16 @@ websockets.init = function(io) {
}
if (Date.now() - lastPostTime < meta.config.postDelay * 1000) {
posts.emitTooManyPostsAlert(socket);
emitTooManyPostsAlert(socket);
return;
}
posts.reply(data.topic_id, uid, data.content, function(err, postData) {
topics.reply(data.topic_id, uid, data.content, function(err, postData) {
if(err) {
if (err.message === 'content-too-short') {
posts.emitContentTooShortAlert(socket);
emitContentTooShortAlert(socket);
} else if (err.message === 'too-many-posts') {
posts.emitTooManyPostsAlert(socket);
emitTooManyPostsAlert(socket);
} else if (err.message === 'reply-error') {
socket.emit('event:alert', {
title: 'Reply Unsuccessful',
@@ -530,7 +562,7 @@ websockets.init = function(io) {
socket.on('api:topic.delete', function(data) {
threadTools.privileges(data.tid, uid, function(err, privileges) {
if (!err && privileges.editable) {
threadTools.delete(data.tid, function(err) {
threadTools.delete(data.tid, uid, function(err) {
if (!err) {
emitTopicPostStats();
socket.emit('api:topic.delete', {
@@ -546,7 +578,7 @@ websockets.init = function(io) {
socket.on('api:topic.restore', function(data) {
threadTools.privileges(data.tid, uid, function(err, privileges) {
if (!err && privileges.editable) {
threadTools.restore(data.tid, socket, function(err) {
threadTools.restore(data.tid, uid, function(err) {
emitTopicPostStats();
socket.emit('api:topic.restore', {
@@ -590,6 +622,12 @@ websockets.init = function(io) {
});
});
socket.on('api:topic.createTopicFromPost', function(data, callback) {
topics.createTopicFromPost(data.pid, function(err, data) {
callback(err?{message:err.message}:null, data);
});
});
socket.on('api:topic.move', function(data) {
threadTools.move(data.tid, data.cid, socket);
});
@@ -606,6 +644,10 @@ websockets.init = function(io) {
posts.uploadPostImage(data, callback);
});
socket.on('api:posts.uploadFile', function(data, callback) {
posts.uploadPostFile(data, callback);
});
socket.on('api:posts.getRawPost', function(data, callback) {
posts.getPostField(data.pid, 'content', function(err, raw) {
callback({
@@ -627,7 +669,7 @@ websockets.init = function(io) {
topics.emitTitleTooShortAlert(socket);
return;
} else if (!data.content || data.content.length < parseInt(meta.config.minimumPostLength, 10)) {
posts.emitContentTooShortAlert(socket);
emitContentTooShortAlert(socket);
return;
}
@@ -712,7 +754,7 @@ websockets.init = function(io) {
return;
}
var msg = utils.strip_tags(data.message);
var msg = S(data.message).stripTags().s;
user.getMultipleUserFields([uid, touid], ['username'], function(err, usersData) {
if(err) {