diff --git a/.gitignore b/.gitignore
index 6ceac139f..a5f149548 100755
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,8 @@
*.rej
# OSX .DS_Store files
.DS_Store
+# version scripts (repo master only)
+.version*
Thumbs.db
diff --git a/CHANGELOG b/CHANGELOG
index cf8386317..7fc5835a7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,79 @@
+Hubzilla 1.8
+ Administration:
+ Cleanup and resolve some edge cases with addon repository manager
+ Provide sort field and direction on all fields of account and channel administration tables
+ Rename 'user' administration to account administration to reflect its true purpose
+ 'safemode' tool to quickly disable and re-enable addons during a hypothetical upgrade crisis
+ Security:
+ Edited comments to private posts could lose their privacy settings under some circumstances
+ Provide zot-finger signatures to prevent a possible but rare exploit involving DNS spoofing and phishing
+ ACL selections:
+ Various improvements to the ACL editor to further simplify the concepts and make it more intuitive
+ Chat:
+ Notifications of chatroom activity using standard browser notification interfaces.
+ Themes:
+ Allow a theme:schema string to represent a valid theme name. This fixes issues with setting schemas on site themes.
+ Pubsites:
+ Show server role (identify UNO or basic sites as opposed to hubzilla pro) and link to statistics
+ Documentation:
+ Clarify privacy rights of commenters w/r/t conversation owners, as this policy is network dependent.
+ Wiki (Git backed):
+ Brand new feature. We'll call it experimental until it has undergone a bit more testing.
+ Account Cloning:
+ Regression on clone channel creation created a new channel name each time.
+ New issue (fixed) with directory creation on cloned file content
+ Content Rendering:
+ Add inline code (in addition to the existing code blocks) to BBcode
+ Add emoji reactions
+ Add emojis as extended smilies with auto-complete support
+ Emoji added as feature so it can be enabled/disabled and locked
+ Ability to configure the standard reactions available on a site basis
+ Disable 'convenience' ajax autoload on pgdn key, as it could lead to premature memory exhaustion
+ Photos:
+ Change album sort ordering, allow widgets and plugins to define other orderings
+ Apps:
+ Synchronise app list with changes to system apps
+ Preserve existing app categories on app updates/edits
+ Regression: fixed translated system app names
+ Architecture:
+ Provide autoloaded class files and libraries for plugins.
+ Further refactoring of session driver to sort out some cookie anomolies
+ Experimental PDO database driver
+ Creation of Daemon Master class and port all daemon (background task) interfaces to use it
+ Create separate class for each of 'Cron', 'Cron daily', and 'Cron weekly'.
+ Always run a Cron maintenance task if not run in the last four hours
+ Refactor the template classes
+ Refactor the ConversationItem mess into ThreadItem and ThreadStream
+ Refactor Apps, Enotify, and Chat library code
+ Refactor the various Config libraries (Config, PConfig, XConfig, AConfig, AbConfig, and IConfig)
+ Created WebServer class for top level
+ Remove mcrypt dependencies (deprecated in PHP 7.1)
+ Remove all reserved (including merely 'not recommended') words as DB table column names
+ Provide mutex lock on DB logging to prevent recursion under rare failure modes.
+ Bugfixes:
+ Remove db_close function on page end - not needed and will not work with persistent DB connections.
+ Undefined ref_session_write
+ Some session functions needed to be static to work with CalDAV/CardDAV
+ CLI interface: argc and argv were reversed
+ HTML entities double encoded in edited titles
+ Prevent delivering to empty recipients
+ Sabre library setting some security headers for SAML after we've emitted HTML content
+ Always initialise miniApp (caused obscure warning message if not set)
+ Block 'sys' channels from being 'random profile' candidates
+ DB update failed email could be sent in the wrong language under rare circumstances
+ Openid remote authentication used incorrect namespace
+ URL attached to profile "things" was not linked, always showing the "thing" manage page
+ New connection wasn't added to default privacy group when "auto-accept" was enabled
+ Regression: iconfig sharing wasn't working properly
+ Plugins:
+ CalDAV/CardDAV plugin provided
+ Issue sending Diaspora 'like' activities from sources that did not propagate the DCV
+ Allow 'superblock' to work across API calls from third party clients
+ statistics.json: use 'zot' as protocol
+ Issues fixed during testing of ability to follow Diaspora tags
+ Parse issue with Diaspora reshare content
+ Chess: moved to main repo, ported to 1.8
+
Hubzilla 1.6
Cleanup and standardise the interfaces to the "jot" editor
Router re-written to support calling class object methods as controllers
diff --git a/LICENSE b/LICENSE
index a2c2d1599..ab37f5ba7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2010-2016 Hubzilla
+Copyright (c) 2010-2016 the Hubzilla Community
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/README.md b/README.md
index ad7a4a9ca..8a6c003fc 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,11 @@
Hubzilla - Community Server
===========================
-Connected and linked web communities.
--------------------------------------
+Groupware re-imagined and re-invented.
+--------------------------------------
+
+Connect and link decentralised web communities.
+-----------------------------------------------
Installing Hubzilla
diff --git a/Zotlabs/Daemon/Checksites.php b/Zotlabs/Daemon/Checksites.php
new file mode 100644
index 000000000..991456319
--- /dev/null
+++ b/Zotlabs/Daemon/Checksites.php
@@ -0,0 +1,55 @@
+ 1) && ($argv[1]))
+ $site_id = $argv[1];
+
+ if($site_id)
+ $sql_options = " and site_url = '" . dbesc($argv[1]) . "' ";
+
+ $days = intval(get_config('system','sitecheckdays'));
+ if($days < 1)
+ $days = 30;
+
+ $r = q("select * from site where site_dead = 0 and site_update < %s - INTERVAL %s and site_type = %d $sql_options ",
+ db_utcnow(), db_quoteinterval($days . ' DAY'),
+ intval(SITE_TYPE_ZOT)
+ );
+
+ if(! $r)
+ return;
+
+ foreach($r as $rr) {
+ if(! strcasecmp($rr['site_url'],z_root()))
+ continue;
+
+ $x = ping_site($rr['site_url']);
+ if($x['success']) {
+ logger('checksites: ' . $rr['site_url']);
+ q("update site set site_update = '%s' where site_url = '%s' ",
+ dbesc(datetime_convert()),
+ dbesc($rr['site_url'])
+ );
+ }
+ else {
+ logger('marking dead site: ' . $x['message']);
+ q("update site set site_dead = 1 where site_url = '%s' ",
+ dbesc($rr['site_url'])
+ );
+ }
+ }
+
+ return;
+ }
+}
diff --git a/Zotlabs/Daemon/Cli_suggest.php b/Zotlabs/Daemon/Cli_suggest.php
new file mode 100644
index 000000000..5dced462d
--- /dev/null
+++ b/Zotlabs/Daemon/Cli_suggest.php
@@ -0,0 +1,14 @@
+ $maxsysload) {
+ logger('system: load ' . $load . ' too high. Cron deferred to next scheduled run.');
+ return;
+ }
+ }
+
+ // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
+ $lockfile = 'store/[data]/cron';
+ if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
+ && (! get_config('system','override_cron_lockfile'))) {
+ logger("cron: Already running");
+ return;
+ }
+
+ // Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
+ file_put_contents($lockfile, $x);
+
+ logger('cron: start');
+
+ // run queue delivery process in the background
+
+ Master::Summon(array('Queue'));
+
+ Master::Summon(array('Poller'));
+
+ // maintenance for mod sharedwithme - check for updated items and remove them
+
+ require_once('include/sharedwithme.php');
+ apply_updates();
+
+
+ // expire any expired mail
+
+ q("delete from mail where expires != '%s' and expires < %s ",
+ dbesc(NULL_DATE),
+ db_utcnow()
+ );
+
+ // expire any expired items
+
+ $r = q("select id from item where expires != '%s' and expires < %s
+ and item_deleted = 0 ",
+ dbesc(NULL_DATE),
+ db_utcnow()
+ );
+ if($r) {
+ require_once('include/items.php');
+ foreach($r as $rr)
+ drop_item($rr['id'],false);
+ }
+
+
+ // Ensure that every channel pings a directory server once a month. This way we can discover
+ // channels and sites that quietly vanished and prevent the directory from accumulating stale
+ // or dead entries.
+
+ $r = q("select channel_id from channel where channel_dirdate < %s - INTERVAL %s",
+ db_utcnow(),
+ db_quoteinterval('30 DAY')
+ );
+ if($r) {
+ foreach($r as $rr) {
+ Master::Summon(array('Directory',$rr['channel_id'],'force'));
+ if($interval)
+ @time_sleep_until(microtime(true) + (float) $interval);
+ }
+ }
+
+ // publish any applicable items that were set to be published in the future
+ // (time travel posts). Restrict to items that have come of age in the last
+ // couple of days to limit the query to something reasonable.
+
+ $r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
+ db_utcnow(),
+ dbesc(datetime_convert('UTC','UTC','now - 2 days'))
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $x = q("update item set item_delayed = 0 where id = %d",
+ intval($rr['id'])
+ );
+ if($x) {
+ Master::Summon(array('Notifier','wall-new',$rr['id']));
+ }
+ }
+ }
+
+ $abandon_days = intval(get_config('system','account_abandon_days'));
+ if($abandon_days < 1)
+ $abandon_days = 0;
+
+
+ // once daily run birthday_updates and then expire in background
+
+ // FIXME: add birthday updates, both locally and for xprof for use
+ // by directory servers
+
+ $d1 = intval(get_config('system','last_expire_day'));
+ $d2 = intval(datetime_convert('UTC','UTC','now','d'));
+
+ // Allow somebody to staggger daily activities if they have more than one site on their server,
+ // or if it happens at an inconvenient (busy) hour.
+
+ $h1 = intval(get_config('system','cron_hour'));
+ $h2 = intval(datetime_convert('UTC','UTC','now','G'));
+
+
+ if(($d2 != $d1) && ($h1 == $h2)) {
+ Master::Summon(array('Cron_daily'));
+ }
+
+ // update any photos which didn't get imported properly
+ // This should be rare
+
+ $r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
+ and xchan_photo_date < %s - INTERVAL %s",
+ db_utcnow(),
+ db_quoteinterval('1 DAY')
+ );
+ if($r) {
+ require_once('include/photo/photo_driver.php');
+ foreach($r as $rr) {
+ $photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']);
+ $x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
+ where xchan_hash = '%s'",
+ dbesc($photos[0]),
+ dbesc($photos[1]),
+ dbesc($photos[2]),
+ dbesc($photos[3]),
+ dbesc($rr['xchan_hash'])
+ );
+ }
+ }
+
+
+ // pull in some public posts
+
+ if(! get_config('system','disable_discover_tab'))
+ Master::Summon(array('Externals'));
+
+ $generation = 0;
+
+ $restart = false;
+
+ if(($argc > 1) && ($argv[1] == 'restart')) {
+ $restart = true;
+ $generation = intval($argv[2]);
+ if(! $generation)
+ killme();
+ }
+
+ reload_plugins();
+
+ $d = datetime_convert();
+
+ // TODO check to see if there are any cronhooks before wasting a process
+
+ if(! $restart)
+ Master::Summon(array('Cronhooks'));
+
+ set_config('system','lastcron',datetime_convert());
+
+ //All done - clear the lockfile
+ @unlink($lockfile);
+
+ return;
+ }
+}
diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php
new file mode 100644
index 000000000..a16d49853
--- /dev/null
+++ b/Zotlabs/Daemon/Cron_daily.php
@@ -0,0 +1,90 @@
+ json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $mm)))));
+ zot_import($msg,z_root());
+ }
+ }
+ else {
+ $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $m)))));
+ $dresult = zot_import($msg,z_root());
+ }
+
+ remove_queue_item($r[0]['outq_hash']);
+
+ if($dresult && is_array($dresult)) {
+ foreach($dresult as $xx) {
+ if(is_array($xx) && array_key_exists('message_id',$xx)) {
+ if(delivery_report_is_storable($xx)) {
+ q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ",
+ dbesc($xx['message_id']),
+ dbesc($xx['location']),
+ dbesc($xx['recipient']),
+ dbesc($xx['status']),
+ dbesc(datetime_convert($xx['date'])),
+ dbesc($xx['sender'])
+ );
+ }
+ }
+ }
+ }
+
+ q("delete from dreport where dreport_queue = '%s'",
+ dbesc($argv[$x])
+ );
+ }
+ }
+
+ // otherwise it's a remote delivery - call queue_deliver() with the $immediate flag
+
+ queue_deliver($r[0],true);
+
+ }
+ }
+ }
+}
diff --git a/Zotlabs/Daemon/Deliver_hooks.php b/Zotlabs/Daemon/Deliver_hooks.php
new file mode 100644
index 000000000..e8b5acef0
--- /dev/null
+++ b/Zotlabs/Daemon/Deliver_hooks.php
@@ -0,0 +1,24 @@
+ 2) {
+ if($argv[2] === 'force')
+ $force = true;
+ if($argv[2] === 'nopush')
+ $pushall = false;
+ }
+
+ logger('directory update', LOGGER_DEBUG);
+
+ $dirmode = get_config('system','directory_mode');
+ if($dirmode === false)
+ $dirmode = DIRECTORY_MODE_NORMAL;
+
+ $x = q("select * from channel where channel_id = %d limit 1",
+ intval($argv[1])
+ );
+ if(! $x)
+ return;
+
+ $channel = $x[0];
+
+ if($dirmode != DIRECTORY_MODE_NORMAL) {
+
+ // this is an in-memory update and we don't need to send a network packet.
+
+ local_dir_update($argv[1],$force);
+
+ q("update channel set channel_dirdate = '%s' where channel_id = %d",
+ dbesc(datetime_convert()),
+ intval($channel['channel_id'])
+ );
+
+ // Now update all the connections
+ if($pushall)
+ Master::Summon(array('Notifier','refresh_all',$channel['channel_id']));
+
+ return;
+ }
+
+ // otherwise send the changes upstream
+
+ $directory = find_upstream_directory($dirmode);
+ $url = $directory['url'] . '/post';
+
+ // ensure the upstream directory is updated
+
+ $packet = zot_build_packet($channel,(($force) ? 'force_refresh' : 'refresh'));
+ $z = zot_zot($url,$packet);
+
+ // re-queue if unsuccessful
+
+ if(! $z['success']) {
+
+ /** @FIXME we aren't updating channel_dirdate if we have to queue
+ * the directory packet. That means we'll try again on the next poll run.
+ */
+
+ $hash = random_string();
+
+ queue_insert(array(
+ 'hash' => $hash,
+ 'account_id' => $channel['channel_account_id'],
+ 'channel_id' => $channel['channel_id'],
+ 'posturl' => $url,
+ 'notify' => $packet,
+ ));
+
+ }
+ else {
+ q("update channel set channel_dirdate = '%s' where channel_id = %d",
+ dbesc(datetime_convert()),
+ intval($channel['channel_id'])
+ );
+ }
+
+ // Now update all the connections
+ if($pushall)
+ Master::Summon(array('Notifier','refresh_all',$channel['channel_id']));
+
+ }
+}
diff --git a/Zotlabs/Daemon/Expire.php b/Zotlabs/Daemon/Expire.php
new file mode 100644
index 000000000..0ba83b240
--- /dev/null
+++ b/Zotlabs/Daemon/Expire.php
@@ -0,0 +1,93 @@
+ '');
+ call_hooks('externals_url_select',$arr);
+
+ if($arr['url']) {
+ $url = $arr['url'];
+ }
+ else {
+ $randfunc = db_getfunc('RAND');
+
+ // fixme this query does not deal with directory realms.
+
+ $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1",
+ dbesc(z_root()),
+ intval(DIRECTORY_MODE_STANDALONE),
+ intval(SITE_TYPE_ZOT)
+ );
+ if($r)
+ $url = $r[0]['site_url'];
+ }
+
+ $blacklisted = false;
+
+ if(! check_siteallowed($url)) {
+ logger('blacklisted site: ' . $url);
+ $blacklisted = true;
+ }
+
+ $attempts ++;
+
+ // make sure we can eventually break out if somebody blacklists all known sites
+
+ if($blacklisted) {
+ if($attempts > 20)
+ break;
+ $attempts --;
+ continue;
+ }
+
+ if($url) {
+ if($r[0]['site_pull'] !== NULL_DATE)
+ $mindate = urlencode(datetime_convert('','',$r[0]['site_pull'] . ' - 1 day'));
+ else {
+ $days = get_config('externals','since_days');
+ if($days === false)
+ $days = 15;
+ $mindate = urlencode(datetime_convert('','','now - ' . intval($days) . ' days'));
+ }
+
+ $feedurl = $url . '/zotfeed?f=&mindate=' . $mindate;
+
+ logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG);
+
+ $x = z_fetch_url($feedurl);
+ if(($x) && ($x['success'])) {
+
+ q("update site set site_pull = '%s' where site_url = '%s'",
+ dbesc(datetime_convert()),
+ dbesc($url)
+ );
+
+ $j = json_decode($x['body'],true);
+ if($j['success'] && $j['messages']) {
+ $sys = get_sys_channel();
+ foreach($j['messages'] as $message) {
+ // on these posts, clear any route info.
+ $message['route'] = '';
+ $results = process_delivery(array('hash' => 'undefined'), get_item_elements($message),
+ array(array('hash' => $sys['xchan_hash'])), false, true);
+ $total ++;
+ }
+ logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php
new file mode 100644
index 000000000..43cce93c3
--- /dev/null
+++ b/Zotlabs/Daemon/Gprobe.php
@@ -0,0 +1,33 @@
+ 3) ? $argv[3] : null);
+
+ if(! $item_id)
+ return;
+
+ $sys = get_sys_channel();
+
+ $deliveries = array();
+
+ $dead_hubs = array();
+
+ $dh = q("select site_url from site where site_dead = 1");
+ if($dh) {
+ foreach($dh as $dead) {
+ $dead_hubs[] = $dead['site_url'];
+ }
+ }
+
+
+ $request = false;
+ $mail = false;
+ $top_level = false;
+ $location = false;
+ $recipients = array();
+ $url_recipients = array();
+ $normal_mode = true;
+ $packet_type = 'undefined';
+
+ if($cmd === 'mail' || $cmd === 'single_mail') {
+ $normal_mode = false;
+ $mail = true;
+ $private = true;
+ $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
+ intval($item_id)
+ );
+ if(! $message) {
+ return;
+ }
+ xchan_mail_query($message[0]);
+ $uid = $message[0]['channel_id'];
+ $recipients[] = $message[0]['from_xchan']; // include clones
+ $recipients[] = $message[0]['to_xchan'];
+ $item = $message[0];
+
+ $encoded_item = encode_mail($item);
+
+ $s = q("select * from channel where channel_id = %d limit 1",
+ intval($item['channel_id'])
+ );
+ if($s)
+ $channel = $s[0];
+
+ }
+ elseif($cmd === 'request') {
+ $channel_id = $item_id;
+ $xchan = $argv[3];
+ $request_message_id = $argv[4];
+
+ $s = q("select * from channel where channel_id = %d limit 1",
+ intval($channel_id)
+ );
+ if($s)
+ $channel = $s[0];
+
+ $private = true;
+ $recipients[] = $xchan;
+ $packet_type = 'request';
+ $normal_mode = false;
+ }
+ elseif($cmd == 'permission_update' || $cmd == 'permission_create') {
+ // Get the (single) recipient
+ $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0",
+ intval($item_id)
+ );
+ if($r) {
+ $uid = $r[0]['abook_channel'];
+ // Get the sender
+ $channel = channelx_by_n($uid);
+ if($channel) {
+ $perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
+
+ if($cmd == 'permission_create')
+ call_hooks('permissions_create',$perm_update);
+ else
+ call_hooks('permissions_update',$perm_update);
+
+ if($perm_update['success']) {
+ if($perm_update['deliveries']) {
+ $deliveries[] = $perm_update['deliveries'];
+ do_delivery($deliveries);
+ }
+ return;
+ }
+ else {
+ $recipients[] = $r[0]['abook_xchan'];
+ $private = false;
+ $packet_type = 'refresh';
+ $packet_recips = array(array('guid' => $r[0]['xchan_guid'],'guid_sig' => $r[0]['xchan_guid_sig'],'hash' => $r[0]['xchan_hash']));
+ }
+ }
+ }
+ }
+ elseif($cmd === 'refresh_all') {
+ logger('notifier: refresh_all: ' . $item_id);
+ $uid = $item_id;
+ $channel = channelx_by_n($item_id);
+ $r = q("select abook_xchan from abook where abook_channel = %d",
+ intval($item_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $recipients[] = $rr['abook_xchan'];
+ }
+ }
+ $private = false;
+ $packet_type = 'refresh';
+ }
+ elseif($cmd === 'location') {
+ logger('notifier: location: ' . $item_id);
+ $s = q("select * from channel where channel_id = %d limit 1",
+ intval($item_id)
+ );
+ if($s)
+ $channel = $s[0];
+ $uid = $item_id;
+ $recipients = array();
+ $r = q("select abook_xchan from abook where abook_channel = %d",
+ intval($item_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $recipients[] = $rr['abook_xchan'];
+ }
+ }
+
+ $encoded_item = array('locations' => zot_encode_locations($channel),'type' => 'location', 'encoding' => 'zot');
+ $target_item = array('aid' => $channel['channel_account_id'],'uid' => $channel['channel_id']);
+ $private = false;
+ $packet_type = 'location';
+ $location = true;
+ }
+ elseif($cmd === 'purge_all') {
+ logger('notifier: purge_all: ' . $item_id);
+ $s = q("select * from channel where channel_id = %d limit 1",
+ intval($item_id)
+ );
+ if($s)
+ $channel = $s[0];
+ $uid = $item_id;
+ $recipients = array();
+ $r = q("select abook_xchan from abook where abook_channel = %d",
+ intval($item_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $recipients[] = $rr['abook_xchan'];
+ }
+ }
+ $private = false;
+ $packet_type = 'purge';
+ }
+ else {
+
+ // Normal items
+
+ // Fetch the target item
+
+ $r = q("SELECT * FROM item WHERE id = %d and parent != 0 LIMIT 1",
+ intval($item_id)
+ );
+
+ if(! $r)
+ return;
+
+ xchan_query($r);
+
+ $r = fetch_post_tags($r);
+
+ $target_item = $r[0];
+ $deleted_item = false;
+
+ if(intval($target_item['item_deleted'])) {
+ logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
+ $deleted_item = true;
+ }
+
+ if(intval($target_item['item_type']) != ITEM_TYPE_POST) {
+ logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
+ return;
+ }
+
+ // Check for non published items, but allow an exclusion for transmitting hidden file activities
+
+ if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) ||
+ ( intval($target_item['item_hidden']) && ($target_item['obj_type'] !== ACTIVITY_OBJ_FILE))) {
+ logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
+ return;
+ }
+
+ if(strpos($target_item['postopts'],'nodeliver') !== false) {
+ logger('notifier: target item is undeliverable', LOGGER_DEBUG);
+ return;
+ }
+
+ $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
+ intval($target_item['uid'])
+ );
+ if($s)
+ $channel = $s[0];
+
+ if($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) {
+ logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}", LOGGER_NORMAL, LOG_WARNING);
+ return;
+ }
+
+
+ if($target_item['id'] == $target_item['parent']) {
+ $parent_item = $target_item;
+ $top_level_post = true;
+ }
+ else {
+ // fetch the parent item
+ $r = q("SELECT * from item where id = %d order by id asc",
+ intval($target_item['parent'])
+ );
+
+ if(! $r)
+ return;
+
+ if(strpos($r[0]['postopts'],'nodeliver') !== false) {
+ logger('notifier: target item is undeliverable', LOGGER_DEBUG, LOG_NOTICE);
+ return;
+ }
+
+ xchan_query($r);
+ $r = fetch_post_tags($r);
+
+ $parent_item = $r[0];
+ $top_level_post = false;
+ }
+
+ // avoid looping of discover items 12/4/2014
+
+ if($sys && $parent_item['uid'] == $sys['channel_id'])
+ return;
+
+ $encoded_item = encode_item($target_item);
+
+ // Send comments to the owner to re-deliver to everybody in the conversation
+ // We only do this if the item in question originated on this site. This prevents looping.
+ // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
+ // Relaying should never be initiated on a post that arrived from elsewhere.
+
+ // We should normally be able to rely on ITEM_ORIGIN, but start_delivery_chain() incorrectly set this
+ // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at
+ // the hostname in the message_id and provides a second (fallback) opinion.
+
+ $relay_to_owner = (((! $top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item)) ? true : false);
+
+
+
+ $uplink = false;
+
+ // $cmd === 'relay' indicates the owner is sending it to the original recipients
+ // don't allow the item in the relay command to relay to owner under any circumstances, it will loop
+
+ logger('notifier: relay_to_owner: ' . (($relay_to_owner) ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
+ logger('notifier: top_level_post: ' . (($top_level_post) ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
+
+ // tag_deliver'd post which needs to be sent back to the original author
+
+ if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) {
+ logger('notifier: uplink');
+ $uplink = true;
+ }
+
+ if(($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
+ logger('notifier: followup relay', LOGGER_DEBUG);
+ $recipients = array(($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
+ $private = true;
+ if(! $encoded_item['flags'])
+ $encoded_item['flags'] = array();
+ $encoded_item['flags'][] = 'relay';
+ }
+ else {
+ logger('notifier: normal distribution', LOGGER_DEBUG);
+ if($cmd === 'relay')
+ logger('notifier: owner relay');
+
+ // if our parent is a tag_delivery recipient, uplink to the original author causing
+ // a delivery fork.
+
+ if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) {
+ // don't uplink a relayed post to the relay owner
+ if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
+ logger('notifier: uplinking this item');
+ Master::Summon(array('Notifier','uplink',$item_id));
+ }
+ }
+
+ $private = false;
+ $recipients = collect_recipients($parent_item,$private);
+
+ // FIXME add any additional recipients such as mentions, etc.
+
+ // don't send deletions onward for other people's stuff
+ // TODO verify this is needed - copied logic from same place in old code
+
+ if(intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) {
+ logger('notifier: ignoring delete notification for non-wall item', LOGGER_NORMAL, LOG_NOTICE);
+ return;
+ }
+ }
+
+ }
+
+ $walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false);
+
+ // Generic delivery section, we have an encoded item and recipients
+ // Now start the delivery process
+
+ $x = $encoded_item;
+ $x['title'] = 'private';
+ $x['body'] = 'private';
+ logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG);
+
+ stringify_array_elms($recipients);
+ if(! $recipients)
+ return;
+
+// logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG);
+
+ $env_recips = (($private) ? array() : null);
+
+ $details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . implode(',',$recipients) . ")");
+
+
+ $recip_list = array();
+
+ if($details) {
+ foreach($details as $d) {
+
+ $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
+ if($private)
+ $env_recips[] = array('guid' => $d['xchan_guid'],'guid_sig' => $d['xchan_guid_sig'],'hash' => $d['xchan_hash']);
+
+ if($d['xchan_network'] === 'mail' && $normal_mode) {
+ $delivery_options = get_xconfig($d['xchan_hash'],'system','delivery_mode');
+ if(! $delivery_options)
+ format_and_send_email($channel,$d,$target_item);
+ }
+ }
+ }
+
+
+ $narr = array(
+ 'channel' => $channel,
+ 'env_recips' => $env_recips,
+ 'packet_recips' => $packet_recips,
+ 'recipients' => $recipients,
+ 'item' => $item,
+ 'target_item' => $target_item,
+ 'top_level_post' => $top_level_post,
+ 'private' => $private,
+ 'relay_to_owner' => $relay_to_owner,
+ 'uplink' => $uplink,
+ 'cmd' => $cmd,
+ 'mail' => $mail,
+ 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
+ 'location' => $location,
+ 'request' => $request,
+ 'normal_mode' => $normal_mode,
+ 'packet_type' => $packet_type,
+ 'walltowall' => $walltowall,
+ 'queued' => array()
+ );
+
+ call_hooks('notifier_process', $narr);
+ if($narr['queued']) {
+ foreach($narr['queued'] as $pq)
+ $deliveries[] = $pq;
+ }
+
+ // notifier_process can alter the recipient list
+
+ $recipients = $narr['recipients'];
+ $env_recips = $narr['env_recips'];
+ $packet_recips = $narr['packet_recips'];
+
+ if(($private) && (! $env_recips)) {
+ // shouldn't happen
+ logger('notifier: private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE);
+ }
+
+ logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG);
+
+
+ // Now we have collected recipients (except for external mentions, FIXME)
+ // Let's reduce this to a set of hubs.
+
+ $r = q("select * from hubloc where hubloc_hash in (" . implode(',',$recipients) . ")
+ and hubloc_error = 0 and hubloc_deleted = 0"
+ );
+
+
+ if(! $r) {
+ logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
+ return;
+ }
+
+ $hubs = $r;
+
+
+
+ /**
+ * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, since it may have been
+ * a re-install which has not yet been detected and pruned.
+ * For other networks which don't have or require sitekeys, we'll have to use the URL
+ */
+
+
+ $hublist = array(); // this provides an easily printable list for the logs
+ $dhubs = array(); // delivery hubs where we store our resulting unique array
+ $keys = array(); // array of keys to check uniquness for zot hubs
+ $urls = array(); // array of urls to check uniqueness of hubs from other networks
+
+
+ foreach($hubs as $hub) {
+ if(in_array($hub['hubloc_url'],$dead_hubs)) {
+ logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG, LOG_INFO);
+ continue;
+ }
+
+ if($hub['hubloc_network'] == 'zot') {
+ if(! in_array($hub['hubloc_sitekey'],$keys)) {
+ $hublist[] = $hub['hubloc_host'];
+ $dhubs[] = $hub;
+ $keys[] = $hub['hubloc_sitekey'];
+ }
+ }
+ else {
+ if(! in_array($hub['hubloc_url'],$urls)) {
+ $hublist[] = $hub['hubloc_host'];
+ $dhubs[] = $hub;
+ $urls[] = $hub['hubloc_url'];
+ }
+ }
+ }
+
+ logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG);
+
+
+ foreach($dhubs as $hub) {
+
+ if($hub['hubloc_network'] !== 'zot') {
+
+ $narr = array(
+ 'channel' => $channel,
+ 'env_recips' => $env_recips,
+ 'packet_recips' => $packet_recips,
+ 'recipients' => $recipients,
+ 'item' => $item,
+ 'target_item' => $target_item,
+ 'hub' => $hub,
+ 'top_level_post' => $top_level_post,
+ 'private' => $private,
+ 'relay_to_owner' => $relay_to_owner,
+ 'uplink' => $uplink,
+ 'cmd' => $cmd,
+ 'mail' => $mail,
+ 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
+ 'location' => $location,
+ 'request' => $request,
+ 'normal_mode' => $normal_mode,
+ 'packet_type' => $packet_type,
+ 'walltowall' => $walltowall,
+ 'queued' => array()
+ );
+
+
+ call_hooks('notifier_hub',$narr);
+ if($narr['queued']) {
+ foreach($narr['queued'] as $pq)
+ $deliveries[] = $pq;
+ }
+ continue;
+
+ }
+
+ // singleton deliveries by definition 'not got zot'.
+ // Single deliveries are other federated networks (plugins) and we're essentially
+ // delivering only to those that have this site url in their abook_instance
+ // and only from within a sync operation. This means if you post from a clone,
+ // and a connection is connected to one of your other clones; assuming that hub
+ // is running it will receive a sync packet. On receipt of this sync packet it
+ // will invoke a delivery to those connections which are connected to just that
+ // hub instance.
+
+ if($cmd === 'single_mail' || $cmd === 'single_activity') {
+ continue;
+ }
+
+ // default: zot protocol
+
+ $hash = random_string();
+ $packet = null;
+
+ if($packet_type === 'refresh' || $packet_type === 'purge') {
+ $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
+ }
+ elseif($packet_type === 'request') {
+ $packet = zot_build_packet($channel,$packet_type,$env_recips,$hub['hubloc_sitekey'],$hash,
+ array('message_id' => $request_message_id)
+ );
+ }
+
+ if($packet) {
+ queue_insert(array(
+ 'hash' => $hash,
+ 'account_id' => $channel['channel_account_id'],
+ 'channel_id' => $channel['channel_id'],
+ 'posturl' => $hub['hubloc_callback'],
+ 'notify' => $packet
+ ));
+ }
+ else {
+ $packet = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash);
+ queue_insert(array(
+ 'hash' => $hash,
+ 'account_id' => $target_item['aid'],
+ 'channel_id' => $target_item['uid'],
+ 'posturl' => $hub['hubloc_callback'],
+ 'notify' => $packet,
+ 'msg' => json_encode($encoded_item)
+ ));
+
+ // only create delivery reports for normal undeleted items
+ if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
+ q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ",
+ dbesc($target_item['mid']),
+ dbesc($hub['hubloc_host']),
+ dbesc($hub['hubloc_host']),
+ dbesc('queued'),
+ dbesc(datetime_convert()),
+ dbesc($channel['channel_hash']),
+ dbesc($hash)
+ );
+ }
+ }
+
+ $deliveries[] = $hash;
+ }
+
+ if($normal_mode) {
+ $x = q("select * from hook where hook = 'notifier_normal'");
+ if($x)
+ Master::Summon(array('Deliver_hooks',$target_item['id']));
+
+ }
+
+ if($deliveries)
+ do_delivery($deliveries);
+
+ logger('notifier: basic loop complete.', LOGGER_DEBUG);
+
+ call_hooks('notifier_end',$target_item);
+
+ logger('notifer: complete.');
+ return;
+
+ }
+}
+
diff --git a/Zotlabs/Daemon/Onedirsync.php b/Zotlabs/Daemon/Onedirsync.php
new file mode 100644
index 000000000..cc16c0b58
--- /dev/null
+++ b/Zotlabs/Daemon/Onedirsync.php
@@ -0,0 +1,76 @@
+ 1) && (intval($argv[1])))
+ $update_id = intval($argv[1]);
+
+ if(! $update_id) {
+ logger('onedirsync: no update');
+ return;
+ }
+
+ $r = q("select * from updates where ud_id = %d limit 1",
+ intval($update_id)
+ );
+
+ if(! $r)
+ return;
+ if(($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (! $r[0]['ud_addr']))
+ return;
+
+ // Have we probed this channel more recently than the other directory server
+ // (where we received this update from) ?
+ // If we have, we don't need to do anything except mark any older entries updated
+
+ $x = q("select * from updates where ud_addr = '%s' and ud_date > '%s' and ( ud_flags & %d )>0 order by ud_date desc limit 1",
+ dbesc($r[0]['ud_addr']),
+ dbesc($r[0]['ud_date']),
+ intval(UPDATE_FLAGS_UPDATED)
+ );
+ if($x) {
+ $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
+ intval(UPDATE_FLAGS_UPDATED),
+ dbesc($r[0]['ud_addr']),
+ intval(UPDATE_FLAGS_UPDATED),
+ dbesc($x[0]['ud_date'])
+ );
+ return;
+ }
+
+ // ignore doing an update if this ud_addr refers to a known dead hubloc
+
+ $h = q("select * from hubloc where hubloc_addr = '%s' limit 1",
+ dbesc($r[0]['ud_addr'])
+ );
+ if(($h) && ($h[0]['hubloc_status'] & HUBLOC_OFFLINE)) {
+ $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
+ intval(UPDATE_FLAGS_UPDATED),
+ dbesc($r[0]['ud_addr']),
+ intval(UPDATE_FLAGS_UPDATED)
+ );
+
+ return;
+ }
+
+ // we might have to pull this out some day, but for now update_directory_entry()
+ // runs zot_finger() and is kind of zot specific
+
+ if($h && $h[0]['hubloc_network'] !== 'zot')
+ return;
+
+ update_directory_entry($r[0]);
+
+ return;
+ }
+}
diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php
new file mode 100644
index 000000000..036a4991b
--- /dev/null
+++ b/Zotlabs/Daemon/Onepoll.php
@@ -0,0 +1,152 @@
+ 1) && (intval($argv[1])))
+ $contact_id = intval($argv[1]);
+
+ if(! $contact_id) {
+ logger('onepoll: no contact');
+ return;
+ }
+
+ $d = datetime_convert();
+
+ $contacts = q("SELECT abook.*, xchan.*, account.*
+ FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan
+ where abook_id = %d
+ and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
+ AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1",
+ intval($contact_id),
+ intval(ACCOUNT_OK),
+ intval(ACCOUNT_UNVERIFIED)
+ );
+
+ if(! $contacts) {
+ logger('onepoll: abook_id not found: ' . $contact_id);
+ return;
+ }
+
+ $contact = $contacts[0];
+
+ $t = $contact['abook_updated'];
+
+ $importer_uid = $contact['abook_channel'];
+
+ $r = q("SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
+ intval($importer_uid)
+ );
+
+ if(! $r)
+ return;
+
+ $importer = $r[0];
+
+ logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
+
+ $last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] === NULL_DATE))
+ ? datetime_convert('UTC','UTC','now - 7 days')
+ : datetime_convert('UTC','UTC',$contact['abook_updated'] . ' - 2 days')
+ );
+
+ if($contact['xchan_network'] === 'rss') {
+ logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
+ handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
+ q("update abook set abook_connected = '%s' where abook_id = %d",
+ dbesc(datetime_convert()),
+ intval($contact['abook_id'])
+ );
+ return;
+ }
+
+ if($contact['xchan_network'] !== 'zot')
+ return;
+
+ // update permissions
+
+ $x = zot_refresh($contact,$importer);
+
+ $responded = false;
+ $updated = datetime_convert();
+ $connected = datetime_convert();
+ if(! $x) {
+ // mark for death by not updating abook_connected, this is caught in include/poller.php
+ q("update abook set abook_updated = '%s' where abook_id = %d",
+ dbesc($updated),
+ intval($contact['abook_id'])
+ );
+ }
+ else {
+ q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d",
+ dbesc($updated),
+ dbesc($connected),
+ intval($contact['abook_id'])
+ );
+ $responded = true;
+ }
+
+ if(! $responded)
+ return;
+
+ if($contact['xchan_connurl']) {
+ $fetch_feed = true;
+ $x = null;
+
+ if(! ($contact['abook_their_perms'] & PERMS_R_STREAM ))
+ $fetch_feed = false;
+
+ if($fetch_feed) {
+
+ $feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']);
+ $feedurl .= '?f=&mindate=' . urlencode($last_update);
+
+ $x = z_fetch_url($feedurl);
+
+ logger('feed_update: ' . print_r($x,true), LOGGER_DATA);
+
+ }
+
+ if(($x) && ($x['success'])) {
+ $total = 0;
+ logger('onepoll: feed update ' . $contact['xchan_name'] . ' ' . $feedurl);
+
+ $j = json_decode($x['body'],true);
+ if($j['success'] && $j['messages']) {
+ foreach($j['messages'] as $message) {
+ $results = process_delivery(array('hash' => $contact['xchan_hash']), get_item_elements($message),
+ array(array('hash' => $importer['xchan_hash'])), false);
+ logger('onepoll: feed_update: process_delivery: ' . print_r($results,true), LOGGER_DATA);
+ $total ++;
+ }
+ logger("onepoll: $total messages processed");
+ }
+ }
+ }
+
+
+ // update the poco details for this connection
+
+ if($contact['xchan_connurl']) {
+ $r = q("SELECT xlink_id from xlink
+ where xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1",
+ intval($contact['xchan_hash']),
+ db_utcnow(), db_quoteinterval('1 DAY')
+ );
+ if(! $r) {
+ poco_load($contact['xchan_hash'],$contact['xchan_connurl']);
+ }
+ }
+
+ return;
+ }
+}
diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php
new file mode 100644
index 000000000..75efbf8f7
--- /dev/null
+++ b/Zotlabs/Daemon/Poller.php
@@ -0,0 +1,202 @@
+ $maxsysload) {
+ logger('system: load ' . $load . ' too high. Poller deferred to next scheduled run.');
+ return;
+ }
+ }
+
+ $interval = intval(get_config('system','poll_interval'));
+ if(! $interval)
+ $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval')));
+
+ // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
+ $lockfile = 'store/[data]/poller';
+ if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
+ && (! get_config('system','override_poll_lockfile'))) {
+ logger("poller: Already running");
+ return;
+ }
+
+ // Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
+ file_put_contents($lockfile, $x);
+
+ logger('poller: start');
+
+ $manual_id = 0;
+ $generation = 0;
+
+ $force = false;
+ $restart = false;
+
+ if(($argc > 1) && ($argv[1] == 'force'))
+ $force = true;
+
+ if(($argc > 1) && ($argv[1] == 'restart')) {
+ $restart = true;
+ $generation = intval($argv[2]);
+ if(! $generation)
+ killme();
+ }
+
+ if(($argc > 1) && intval($argv[1])) {
+ $manual_id = intval($argv[1]);
+ $force = true;
+ }
+
+
+ $sql_extra = (($manual_id) ? " AND abook_id = " . intval($manual_id) . " " : "");
+
+ reload_plugins();
+
+ $d = datetime_convert();
+
+ // Only poll from those with suitable relationships
+
+ $abandon_sql = (($abandon_days)
+ ? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days).' DAY'))
+ : ''
+ );
+
+ $randfunc = db_getfunc('RAND');
+
+ $contacts = q("SELECT * FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
+ LEFT JOIN account on abook_account = account_id
+ where abook_self = 0
+ $sql_extra
+ AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc",
+ intval(ACCOUNT_OK),
+ intval(ACCOUNT_UNVERIFIED) // FIXME
+
+ );
+
+ if($contacts) {
+
+ foreach($contacts as $contact) {
+
+ $update = false;
+
+ $t = $contact['abook_updated'];
+ $c = $contact['abook_connected'];
+
+ if(intval($contact['abook_feed'])) {
+ $min = service_class_fetch($contact['abook_channel'],'minimum_feedcheck_minutes');
+ if(! $min)
+ $min = intval(get_config('system','minimum_feedcheck_minutes'));
+ if(! $min)
+ $min = 60;
+ $x = datetime_convert('UTC','UTC',"now - $min minutes");
+ if($c < $x) {
+ Master::Summon(array('Onepoll',$contact['abook_id']));
+ if($interval)
+ @time_sleep_until(microtime(true) + (float) $interval);
+ }
+ continue;
+ }
+
+
+ if($contact['xchan_network'] !== 'zot')
+ continue;
+
+ if($c == $t) {
+ if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day"))
+ $update = true;
+ }
+ else {
+
+ // if we've never connected with them, start the mark for death countdown from now
+
+ if($c == NULL_DATE) {
+ $r = q("update abook set abook_connected = '%s' where abook_id = %d",
+ dbesc(datetime_convert()),
+ intval($contact['abook_id'])
+ );
+ $c = datetime_convert();
+ $update = true;
+ }
+
+ // He's dead, Jim
+
+ if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) {
+ $r = q("update abook set abook_archived = 1 where abook_id = %d",
+ intval($contact['abook_id'])
+ );
+ $update = false;
+ continue;
+ }
+
+ if(intval($contact['abook_archived'])) {
+ $update = false;
+ continue;
+ }
+
+ // might be dead, so maybe don't poll quite so often
+
+ // recently deceased, so keep up the regular schedule for 3 days
+
+ if((strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 3 day")) > 0)
+ && (strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 1 day")) > 0))
+ $update = true;
+
+ // After that back off and put them on a morphine drip
+
+ if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 2 day")) > 0) {
+ $update = true;
+ }
+
+ }
+
+ if(intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked']))
+ continue;
+
+ if((! $update) && (! $force))
+ continue;
+
+ Master::Summon(array('Onepoll',$contact['abook_id']));
+ if($interval)
+ @time_sleep_until(microtime(true) + (float) $interval);
+
+ }
+ }
+
+ if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
+ $r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last = '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ",
+ intval(UPDATE_FLAGS_UPDATED),
+ dbesc(NULL_DATE),
+ db_utcnow(), db_quoteinterval('7 DAY')
+ );
+ if($r) {
+ foreach($r as $rr) {
+
+ // If they didn't respond when we attempted before, back off to once a day
+ // After 7 days we won't bother anymore
+
+ if($rr['ud_last'] != NULL_DATE)
+ if($rr['ud_last'] > datetime_convert('UTC','UTC', 'now - 1 day'))
+ continue;
+ Master::Summon(array('Onedirsync',$rr['ud_id']));
+ if($interval)
+ @time_sleep_until(microtime(true) + (float) $interval);
+ }
+ }
+ }
+
+ set_config('system','lastpoll',datetime_convert());
+
+ //All done - clear the lockfile
+ @unlink($lockfile);
+
+ return;
+ }
+}
diff --git a/Zotlabs/Daemon/Queue.php b/Zotlabs/Daemon/Queue.php
new file mode 100644
index 000000000..27306589d
--- /dev/null
+++ b/Zotlabs/Daemon/Queue.php
@@ -0,0 +1,90 @@
+ 1)
+ $queue_id = argv(1);
+ else
+ $queue_id = 0;
+
+ logger('queue: start');
+
+ // delete all queue items more than 3 days old
+ // but first mark these sites dead if we haven't heard from them in a month
+
+ $r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s",
+ db_utcnow(), db_quoteinterval('3 DAY')
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $site_url = '';
+ $h = parse_url($rr['outq_posturl']);
+ $desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
+ q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
+ dbesc($desturl),
+ db_utcnow(), db_quoteinterval('1 MONTH')
+ );
+ }
+ }
+
+ $r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
+ db_utcnow(), db_quoteinterval('3 DAY')
+ );
+
+ if($queue_id) {
+ $r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
+ dbesc($queue_id)
+ );
+ }
+ else {
+
+ // For the first 12 hours we'll try to deliver every 15 minutes
+ // After that, we'll only attempt delivery once per hour.
+ // This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
+ // so that we don't start off a thousand deliveries for a couple of dead hubs.
+ // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
+ // Other drivers will have to do something different here and may need their own query.
+
+ // Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
+ // "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
+ // or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
+ // the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
+ // or twice a day.
+
+ // FIXME: can we sort postgres on outq_priority and maintain the 'distinct' ?
+ // The order by max(outq_priority) might be a dodgy query because of the group by.
+ // The desired result is to return a sequence in the order most likely to be delivered in this run.
+ // If a hub has already been sitting in the queue for a few days, they should be delivered last;
+ // hence every failure should drop them further down the priority list.
+
+ if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
+ $prefix = 'DISTINCT ON (outq_posturl)';
+ $suffix = 'ORDER BY outq_posturl';
+ } else {
+ $prefix = '';
+ $suffix = 'GROUP BY outq_posturl ORDER BY max(outq_priority)';
+ }
+ $r = q("SELECT $prefix * FROM outq WHERE outq_delivered = 0 and (( outq_created > %s - INTERVAL %s and outq_updated < %s - INTERVAL %s ) OR ( outq_updated < %s - INTERVAL %s )) $suffix",
+ db_utcnow(), db_quoteinterval('12 HOUR'),
+ db_utcnow(), db_quoteinterval('15 MINUTE'),
+ db_utcnow(), db_quoteinterval('1 HOUR')
+ );
+ }
+ if(! $r)
+ return;
+
+ foreach($r as $rr) {
+ queue_deliver($rr);
+ }
+ }
+}
diff --git a/Zotlabs/Daemon/Ratenotif.php b/Zotlabs/Daemon/Ratenotif.php
new file mode 100644
index 000000000..1cba5e26d
--- /dev/null
+++ b/Zotlabs/Daemon/Ratenotif.php
@@ -0,0 +1,113 @@
+ 'rating',
+ 'encoding' => 'zot',
+ 'target' => $r[0]['xlink_link'],
+ 'rating' => intval($r[0]['xlink_rating']),
+ 'rating_text' => $r[0]['xlink_rating_text'],
+ 'signature' => $r[0]['xlink_sig'],
+ 'edited' => $r[0]['xlink_updated']
+ );
+ }
+
+ $channel = channelx_by_hash($r[0]['xlink_xchan']);
+ if(! $channel) {
+ logger('no channel');
+ return;
+ }
+
+
+ $primary = get_directory_primary();
+
+ if(! $primary)
+ return;
+
+
+ $interval = ((get_config('system','delivery_interval') !== false)
+ ? intval(get_config('system','delivery_interval')) : 2 );
+
+ $deliveries_per_process = intval(get_config('system','delivery_batch_count'));
+
+ if($deliveries_per_process <= 0)
+ $deliveries_per_process = 1;
+
+ $deliver = array();
+
+ $x = z_fetch_url($primary . '/regdir');
+ if($x['success']) {
+ $j = json_decode($x['body'],true);
+ if($j && $j['success'] && is_array($j['directories'])) {
+
+ foreach($j['directories'] as $h) {
+ if($h == z_root())
+ continue;
+
+ $hash = random_string();
+ $n = zot_build_packet($channel,'notify',null,null,$hash);
+
+ queue_insert(array(
+ 'hash' => $hash,
+ 'account_id' => $channel['channel_account_id'],
+ 'channel_id' => $channel['channel_id'],
+ 'posturl' => $h . '/post',
+ 'notify' => $n,
+ 'msg' => json_encode($encoded_item)
+ ));
+
+ $deliver[] = $hash;
+
+ if(count($deliver) >= $deliveries_per_process) {
+ Master::Summon(array('Deliver',$deliver));
+ $deliver = array();
+ if($interval)
+ @time_sleep_until(microtime(true) + (float) $interval);
+ }
+ }
+
+ // catch any stragglers
+
+ if(count($deliver)) {
+ Master::Summon(array('Deliver',$deliver));
+ }
+ }
+ }
+
+ logger('ratenotif: complete.');
+ return;
+
+ }
+}
diff --git a/Zotlabs/Extend/Hook.php b/Zotlabs/Extend/Hook.php
index 713165faf..fc1e95367 100644
--- a/Zotlabs/Extend/Hook.php
+++ b/Zotlabs/Extend/Hook.php
@@ -10,7 +10,7 @@ class Hook {
$function = serialize($function);
}
- $r = q("SELECT * FROM `hook` WHERE `hook` = '%s' AND `file` = '%s' AND `function` = '%s' and priority = %d and hook_version = %d LIMIT 1",
+ $r = q("SELECT * FROM `hook` WHERE `hook` = '%s' AND `file` = '%s' AND `fn` = '%s' and priority = %d and hook_version = %d LIMIT 1",
dbesc($hook),
dbesc($file),
dbesc($function),
@@ -23,13 +23,13 @@ class Hook {
// To aid in upgrade and transition, remove old settings for any registered hooks that match in all respects except
// for priority or hook_version
- $r = q("DELETE FROM `hook` where `hook` = '%s' and `file` = '%s' and `function` = '%s'",
+ $r = q("DELETE FROM `hook` where `hook` = '%s' and `file` = '%s' and `fn` = '%s'",
dbesc($hook),
dbesc($file),
dbesc($function)
);
- $r = q("INSERT INTO `hook` (`hook`, `file`, `function`, `priority`, `hook_version`) VALUES ( '%s', '%s', '%s', %d, %d )",
+ $r = q("INSERT INTO `hook` (`hook`, `file`, `fn`, `priority`, `hook_version`) VALUES ( '%s', '%s', '%s', %d, %d )",
dbesc($hook),
dbesc($file),
dbesc($function),
@@ -44,7 +44,7 @@ class Hook {
if(is_array($function)) {
$function = serialize($function);
}
- $r = q("DELETE FROM hook WHERE hook = '%s' AND `file` = '%s' AND `function` = '%s' and priority = %d and hook_version = %d",
+ $r = q("DELETE FROM hook WHERE hook = '%s' AND `file` = '%s' AND `fn` = '%s' and priority = %d and hook_version = %d",
dbesc($hook),
dbesc($file),
dbesc($function),
diff --git a/Zotlabs/Lib/AConfig.php b/Zotlabs/Lib/AConfig.php
new file mode 100644
index 000000000..24ec97dfa
--- /dev/null
+++ b/Zotlabs/Lib/AConfig.php
@@ -0,0 +1,25 @@
+ $v) {
+ if(strpos($v,'http') === 0)
+ $ret[$k] = zid($v);
+ }
+
+ if(array_key_exists('desc',$ret))
+ $ret['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['desc']);
+
+ if(array_key_exists('target',$ret))
+ $ret['target'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['target']);
+
+ if(array_key_exists('version',$ret))
+ $ret['version'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['version']);
+
+
+ if(array_key_exists('requires',$ret)) {
+ $requires = explode(',',$ret['requires']);
+ foreach($requires as $require) {
+ $require = trim(strtolower($require));
+ switch($require) {
+ case 'nologin':
+ if(local_channel())
+ unset($ret);
+ break;
+ case 'admin':
+ if(! is_site_admin())
+ unset($ret);
+ break;
+ case 'local_channel':
+ if(! local_channel())
+ unset($ret);
+ break;
+ case 'public_profile':
+ if(! is_public_profile())
+ unset($ret);
+ break;
+ case 'observer':
+ if(! $observer)
+ unset($ret);
+ break;
+ default:
+ if(! (local_channel() && feature_enabled(local_channel(),$require)))
+ unset($ret);
+ break;
+
+ }
+ }
+ }
+ if($ret) {
+ if($translate)
+ self::translate_system_apps($ret);
+ return $ret;
+ }
+ return false;
+ }
+
+
+ static public function translate_system_apps(&$arr) {
+ $apps = array(
+ 'Site Admin' => t('Site Admin'),
+ 'Bug Report' => t('Bug Report'),
+ 'View Bookmarks' => t('View Bookmarks'),
+ 'My Chatrooms' => t('My Chatrooms'),
+ 'Connections' => t('Connections'),
+ 'Firefox Share' => t('Firefox Share'),
+ 'Remote Diagnostics' => t('Remote Diagnostics'),
+ 'Suggest Channels' => t('Suggest Channels'),
+ 'Login' => t('Login'),
+ 'Channel Manager' => t('Channel Manager'),
+ 'Grid' => t('Grid'),
+ 'Settings' => t('Settings'),
+ 'Files' => t('Files'),
+ 'Webpages' => t('Webpages'),
+ 'Wiki' => t('Wiki'),
+ 'Channel Home' => t('Channel Home'),
+ 'View Profile' => t('View Profile'),
+ 'Photos' => t('Photos'),
+ 'Events' => t('Events'),
+ 'Directory' => t('Directory'),
+ 'Help' => t('Help'),
+ 'Mail' => t('Mail'),
+ 'Mood' => t('Mood'),
+ 'Poke' => t('Poke'),
+ 'Chat' => t('Chat'),
+ 'Search' => t('Search'),
+ 'Probe' => t('Probe'),
+ 'Suggest' => t('Suggest'),
+ 'Random Channel' => t('Random Channel'),
+ 'Invite' => t('Invite'),
+ 'Features' => t('Features'),
+ 'Language' => t('Language'),
+ 'Post' => t('Post'),
+ 'Profile Photo' => t('Profile Photo')
+ );
+
+ if(array_key_exists($arr['name'],$apps))
+ $arr['name'] = $apps[$arr['name']];
+
+ }
+
+
+ // papp is a portable app
+
+ static public function app_render($papp,$mode = 'view') {
+
+ /**
+ * modes:
+ * view: normal mode for viewing an app via bbcode from a conversation or page
+ * provides install/update button if you're logged in locally
+ * list: normal mode for viewing an app on the app page
+ * no buttons are shown
+ * edit: viewing the app page in editing mode provides a delete button
+ */
+
+ $installed = false;
+
+ if(! $papp)
+ return;
+
+ if(! $papp['photo'])
+ $papp['photo'] = z_root() . '/' . get_default_profile_photo(80);
+
+ self::translate_system_apps($papp);
+
+ $papp['papp'] = self::papp_encode($papp);
+
+ if(! strstr($papp['url'],'://'))
+ $papp['url'] = z_root() . ((strpos($papp['url'],'/') === 0) ? '' : '/') . $papp['url'];
+
+ foreach($papp as $k => $v) {
+ if(strpos($v,'http') === 0 && $k != 'papp')
+ $papp[$k] = zid($v);
+ if($k === 'desc')
+ $papp['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$papp['desc']);
+
+ if($k === 'requires') {
+ $requires = explode(',',$v);
+ foreach($requires as $require) {
+ $require = trim(strtolower($require));
+ switch($require) {
+ case 'nologin':
+ if(local_channel())
+ return '';
+ break;
+ case 'admin':
+ if(! is_site_admin())
+ return '';
+ break;
+ case 'local_channel':
+ if(! local_channel())
+ return '';
+ break;
+ case 'public_profile':
+ if(! is_public_profile())
+ return '';
+ break;
+ case 'observer':
+ $observer = \App::get_observer();
+ if(! $observer)
+ return '';
+ break;
+ default:
+ if(! (local_channel() && feature_enabled(local_channel(),$require)))
+ return '';
+ break;
+
+ }
+ }
+ }
+ }
+
+ $hosturl = '';
+
+ if(local_channel()) {
+ $installed = self::app_installed(local_channel(),$papp);
+ $hosturl = z_root() . '/';
+ }
+ elseif(remote_channel()) {
+ $observer = \App::get_observer();
+ if($observer && $observer['xchan_network'] === 'zot') {
+ // some folks might have xchan_url redirected offsite, use the connurl
+ $x = parse_url($observer['xchan_connurl']);
+ if($x) {
+ $hosturl = $x['scheme'] . '://' . $x['host'] . '/';
+ }
+ }
+ }
+
+ $install_action = (($installed) ? t('Update') : t('Install'));
+
+ return replace_macros(get_markup_template('app.tpl'),array(
+ '$app' => $papp,
+ '$hosturl' => $hosturl,
+ '$purchase' => (($papp['page'] && (! $installed)) ? t('Purchase') : ''),
+ '$install' => (($hosturl && $mode == 'view') ? $install_action : ''),
+ '$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
+ '$delete' => ((local_channel() && $installed && $mode == 'edit') ? t('Delete') : '')
+ ));
+ }
+
+ static public function app_install($uid,$app) {
+ $app['uid'] = $uid;
+
+ if(self::app_installed($uid,$app))
+ $x = self::app_update($app);
+ else
+ $x = self::app_store($app);
+
+ if($x['success']) {
+ $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
+ dbesc($x['app_id']),
+ intval($uid)
+ );
+ if($r) {
+ if(! $r[0]['app_system']) {
+ if($app['categories'] && (! $app['term'])) {
+ $r[0]['term'] = q("select * from term where otype = %d and oid = d",
+ intval(TERM_OBJ_APP),
+ intval($r[0]['id'])
+ );
+ build_sync_packet($uid,array('app' => $r[0]));
+ }
+ }
+ }
+ return $x['app_id'];
+ }
+ return false;
+ }
+
+ static public function app_destroy($uid,$app) {
+
+
+ if($uid && $app['guid']) {
+
+ $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
+ dbesc($app['guid']),
+ intval($uid)
+ );
+ if($x) {
+ $x[0]['app_deleted'] = 1;
+ q("delete from term where otype = %d and oid = %d",
+ intval(TERM_OBJ_APP),
+ intval($x[0]['id'])
+ );
+ if($x[0]['app_system']) {
+ $r = q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
+ dbesc($app['guid']),
+ intval($uid)
+ );
+ }
+ else {
+ $r = q("delete from app where app_id = '%s' and app_channel = %d",
+ dbesc($app['guid']),
+ intval($uid)
+ );
+
+ // we don't sync system apps - they may be completely different on the other system
+ build_sync_packet($uid,array('app' => $x));
+ }
+ }
+ }
+ }
+
+
+ static public function app_installed($uid,$app) {
+
+ $r = q("select id from app where app_id = '%s' and app_version = '%s' and app_channel = %d limit 1",
+ dbesc((array_key_exists('guid',$app)) ? $app['guid'] : ''),
+ dbesc((array_key_exists('version',$app)) ? $app['version'] : ''),
+ intval($uid)
+ );
+ return(($r) ? true : false);
+
+ }
+
+
+ static public function app_list($uid, $deleted = false, $cat = '') {
+ if($deleted)
+ $sql_extra = " and app_deleted = 1 ";
+ else
+ $sql_extra = " and app_deleted = 0 ";
+
+ if($cat) {
+ $r = q("select oid from term where otype = %d and term = '%s'",
+ intval(TERM_OBJ_APP),
+ dbesc($cat)
+ );
+ if(! $r)
+ return $r;
+ $sql_extra .= " and app.id in ( ";
+ $s = '';
+ foreach($r as $rr) {
+ if($s)
+ $s .= ',';
+ $s .= intval($rr['oid']);
+ }
+ $sql_extra .= $s . ') ';
+ }
+
+ $r = q("select * from app where app_channel = %d $sql_extra order by app_name asc",
+ intval($uid)
+ );
+ if($r) {
+ for($x = 0; $x < count($r); $x ++) {
+ if(! $r[$x]['app_system'])
+ $r[$x]['type'] = 'personal';
+ $r[$x]['term'] = q("select * from term where otype = %d and oid = %d",
+ intval(TERM_OBJ_APP),
+ intval($r[$x]['id'])
+ );
+ }
+ }
+ return($r);
+ }
+
+
+ static public function app_decode($s) {
+ $x = base64_decode(str_replace(array(' ',"\r","\n",' '),array('','','',''),$s));
+ return json_decode($x,true);
+ }
+
+
+ static public function app_store($arr) {
+
+ // logger('app_store: ' . print_r($arr,true));
+
+ $darray = array();
+ $ret = array('success' => false);
+
+ $darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : '');
+ $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0);
+
+ if((! $darray['app_url']) || (! $darray['app_channel']))
+ return $ret;
+
+ if($arr['photo'] && ! strstr($arr['photo'],z_root())) {
+ $x = import_xchan_photo($arr['photo'],get_observer_hash(),true);
+ $arr['photo'] = $x[1];
+ }
+
+
+ $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : random_string(). '.' . \App::get_hostname());
+ $darray['app_sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
+ $darray['app_author'] = ((x($arr,'author')) ? $arr['author'] : get_observer_hash());
+ $darray['app_name'] = ((x($arr,'name')) ? escape_tags($arr['name']) : t('Unknown'));
+ $darray['app_desc'] = ((x($arr,'desc')) ? escape_tags($arr['desc']) : '');
+ $darray['app_photo'] = ((x($arr,'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80));
+ $darray['app_version'] = ((x($arr,'version')) ? escape_tags($arr['version']) : '');
+ $darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : '');
+ $darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : '');
+ $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : '');
+ $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : '');
+ $darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0);
+ $darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0);
+
+ $created = datetime_convert();
+
+ $r = q("insert into app ( app_id, app_sig, app_author, app_name, app_desc, app_url, app_photo, app_version, app_channel, app_addr, app_price, app_page, app_requires, app_created, app_edited, app_system, app_deleted ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d )",
+ dbesc($darray['app_id']),
+ dbesc($darray['app_sig']),
+ dbesc($darray['app_author']),
+ dbesc($darray['app_name']),
+ dbesc($darray['app_desc']),
+ dbesc($darray['app_url']),
+ dbesc($darray['app_photo']),
+ dbesc($darray['app_version']),
+ intval($darray['app_channel']),
+ dbesc($darray['app_addr']),
+ dbesc($darray['app_price']),
+ dbesc($darray['app_page']),
+ dbesc($darray['app_requires']),
+ dbesc($created),
+ dbesc($created),
+ intval($darray['app_system']),
+ intval($darray['app_deleted'])
+ );
+ if($r) {
+ $ret['success'] = true;
+ $ret['app_id'] = $darray['app_id'];
+ }
+ if($arr['categories']) {
+ $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
+ dbesc($darray['app_id']),
+ intval($darray['app_channel'])
+ );
+ $y = explode(',',$arr['categories']);
+ if($y) {
+ foreach($y as $t) {
+ $t = trim($t);
+ if($t) {
+ store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t)));
+ }
+ }
+ }
+ }
+
+ return $ret;
+ }
+
+
+ static public function app_update($arr) {
+
+ $darray = array();
+ $ret = array('success' => false);
+
+ $darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : '');
+ $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0);
+ $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : 0);
+
+ if((! $darray['app_url']) || (! $darray['app_channel']) || (! $darray['app_id']))
+ return $ret;
+
+ if($arr['photo'] && ! strstr($arr['photo'],z_root())) {
+ $x = import_xchan_photo($arr['photo'],get_observer_hash(),true);
+ $arr['photo'] = $x[1];
+ }
+
+ $darray['app_sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
+ $darray['app_author'] = ((x($arr,'author')) ? $arr['author'] : get_observer_hash());
+ $darray['app_name'] = ((x($arr,'name')) ? escape_tags($arr['name']) : t('Unknown'));
+ $darray['app_desc'] = ((x($arr,'desc')) ? escape_tags($arr['desc']) : '');
+ $darray['app_photo'] = ((x($arr,'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80));
+ $darray['app_version'] = ((x($arr,'version')) ? escape_tags($arr['version']) : '');
+ $darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : '');
+ $darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : '');
+ $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : '');
+ $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : '');
+ $darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0);
+ $darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0);
+
+ $edited = datetime_convert();
+
+ $r = q("update app set app_sig = '%s', app_author = '%s', app_name = '%s', app_desc = '%s', app_url = '%s', app_photo = '%s', app_version = '%s', app_addr = '%s', app_price = '%s', app_page = '%s', app_requires = '%s', app_edited = '%s', app_system = %d, app_deleted = %d where app_id = '%s' and app_channel = %d",
+ dbesc($darray['app_sig']),
+ dbesc($darray['app_author']),
+ dbesc($darray['app_name']),
+ dbesc($darray['app_desc']),
+ dbesc($darray['app_url']),
+ dbesc($darray['app_photo']),
+ dbesc($darray['app_version']),
+ dbesc($darray['app_addr']),
+ dbesc($darray['app_price']),
+ dbesc($darray['app_page']),
+ dbesc($darray['app_requires']),
+ dbesc($edited),
+ intval($darray['app_system']),
+ intval($darray['app_deleted']),
+ dbesc($darray['app_id']),
+ intval($darray['app_channel'])
+ );
+ if($r) {
+ $ret['success'] = true;
+ $ret['app_id'] = $darray['app_id'];
+ }
+
+ $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
+ dbesc($darray['app_id']),
+ intval($darray['app_channel'])
+ );
+ if($x) {
+ q("delete from term where otype = %d and oid = %d",
+ intval(TERM_OBJ_APP),
+ intval($x[0]['id'])
+ );
+ if($arr['categories']) {
+ $y = explode(',',$arr['categories']);
+ if($y) {
+ foreach($y as $t) {
+ $t = trim($t);
+ if($t) {
+ store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t)));
+ }
+ }
+ }
+ }
+ }
+
+ return $ret;
+
+ }
+
+
+ static public function app_encode($app,$embed = false) {
+
+ $ret = array();
+
+ $ret['type'] = 'personal';
+
+ if($app['app_id'])
+ $ret['guid'] = $app['app_id'];
+
+ if($app['app_id'])
+ $ret['guid'] = $app['app_id'];
+
+ if($app['app_sig'])
+ $ret['sig'] = $app['app_sig'];
+
+ if($app['app_author'])
+ $ret['author'] = $app['app_author'];
+
+ if($app['app_name'])
+ $ret['name'] = $app['app_name'];
+
+ if($app['app_desc'])
+ $ret['desc'] = $app['app_desc'];
+
+ if($app['app_url'])
+ $ret['url'] = $app['app_url'];
+
+ if($app['app_photo'])
+ $ret['photo'] = $app['app_photo'];
+
+ if($app['app_version'])
+ $ret['version'] = $app['app_version'];
+
+ if($app['app_addr'])
+ $ret['addr'] = $app['app_addr'];
+
+ if($app['app_price'])
+ $ret['price'] = $app['app_price'];
+
+ if($app['app_page'])
+ $ret['page'] = $app['app_page'];
+
+ if($app['app_requires'])
+ $ret['requires'] = $app['app_requires'];
+
+ if($app['app_system'])
+ $ret['system'] = $app['app_system'];
+
+ if($app['app_deleted'])
+ $ret['deleted'] = $app['app_deleted'];
+
+ if($app['term']) {
+ $s = '';
+ foreach($app['term'] as $t) {
+ if($s)
+ $s .= ',';
+ $s .= $t['term'];
+ }
+ $ret['categories'] = $s;
+ }
+
+
+ if(! $embed)
+ return $ret;
+
+ if(array_key_exists('categories',$ret))
+ unset($ret['categories']);
+
+ $j = json_encode($ret);
+ return '[app]' . chunk_split(base64_encode($j),72,"\n") . '[/app]';
+
+ }
+
+
+ static public function papp_encode($papp) {
+ return chunk_split(base64_encode(json_encode($papp)),72,"\n");
+
+ }
+
+}
+
+
diff --git a/Zotlabs/Lib/Chatroom.php b/Zotlabs/Lib/Chatroom.php
new file mode 100644
index 000000000..e1a9a10b3
--- /dev/null
+++ b/Zotlabs/Lib/Chatroom.php
@@ -0,0 +1,267 @@
+ false);
+
+ $name = trim($arr['name']);
+ if(! $name) {
+ $ret['message'] = t('Missing room name');
+ return $ret;
+ }
+
+ $r = q("select cr_id from chatroom where cr_uid = %d and cr_name = '%s' limit 1",
+ intval($channel['channel_id']),
+ dbesc($name)
+ );
+ if($r) {
+ $ret['message'] = t('Duplicate room name');
+ return $ret;
+ }
+
+ $r = q("select count(cr_id) as total from chatroom where cr_aid = %d",
+ intval($channel['channel_account_id'])
+ );
+ if($r)
+ $limit = service_class_fetch($channel['channel_id'], 'chatrooms');
+
+ if(($r) && ($limit !== false) && ($r[0]['total'] >= $limit)) {
+ $ret['message'] = upgrade_message();
+ return $ret;
+ }
+
+ if(! array_key_exists('expire', $arr))
+ $arr['expire'] = 120; // minutes, e.g. 2 hours
+
+ $created = datetime_convert();
+
+ $x = q("insert into chatroom ( cr_aid, cr_uid, cr_name, cr_created, cr_edited, cr_expire, allow_cid, allow_gid, deny_cid, deny_gid )
+ values ( %d, %d , '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s' ) ",
+ intval($channel['channel_account_id']),
+ intval($channel['channel_id']),
+ dbesc($name),
+ dbesc($created),
+ dbesc($created),
+ intval($arr['expire']),
+ dbesc($arr['allow_cid']),
+ dbesc($arr['allow_gid']),
+ dbesc($arr['deny_cid']),
+ dbesc($arr['deny_gid'])
+ );
+
+ if($x)
+ $ret['success'] = true;
+
+ return $ret;
+ }
+
+
+ static public function destroy($channel,$arr) {
+
+ $ret = array('success' => false);
+
+ if(intval($arr['cr_id']))
+ $sql_extra = " and cr_id = " . intval($arr['cr_id']) . " ";
+ elseif(trim($arr['cr_name']))
+ $sql_extra = " and cr_name = '" . protect_sprintf(dbesc(trim($arr['cr_name']))) . "' ";
+ else {
+ $ret['message'] = t('Invalid room specifier.');
+ return $ret;
+ }
+
+ $r = q("select * from chatroom where cr_uid = %d $sql_extra limit 1",
+ intval($channel['channel_id'])
+ );
+ if(! $r) {
+ $ret['message'] = t('Invalid room specifier.');
+ return $ret;
+ }
+
+ build_sync_packet($channel['channel_id'],array('chatroom' => $r));
+
+ q("delete from chatroom where cr_id = %d",
+ intval($r[0]['cr_id'])
+ );
+ if($r[0]['cr_id']) {
+ q("delete from chatpresence where cp_room = %d",
+ intval($r[0]['cr_id'])
+ );
+ q("delete from chat where chat_room = %d",
+ intval($r[0]['cr_id'])
+ );
+ }
+
+ $ret['success'] = true;
+ return $ret;
+ }
+
+
+ static public function enter($observer_xchan, $room_id, $status, $client) {
+
+ if(! $room_id || ! $observer_xchan)
+ return;
+
+ $r = q("select * from chatroom where cr_id = %d limit 1",
+ intval($room_id)
+ );
+ if(! $r) {
+ notice( t('Room not found.') . EOL);
+ return false;
+ }
+ require_once('include/security.php');
+ $sql_extra = permissions_sql($r[0]['cr_uid']);
+
+ $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1",
+ intval($room_id),
+ intval($r[0]['cr_uid'])
+ );
+ if(! $x) {
+ notice( t('Permission denied.') . EOL);
+ return false;
+ }
+
+ $limit = service_class_fetch($r[0]['cr_uid'], 'chatters_inroom');
+ if($limit !== false) {
+ $y = q("select count(*) as total from chatpresence where cp_room = %d",
+ intval($room_id)
+ );
+ if($y && $y[0]['total'] > $limit) {
+ notice( t('Room is full') . EOL);
+ return false;
+ }
+ }
+
+ if(intval($x[0]['cr_expire'])) {
+ $r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d",
+ db_utcnow(),
+ db_quoteinterval( intval($x[0]['cr_expire']) . ' MINUTE' ),
+ intval($x[0]['cr_id'])
+ );
+ }
+
+ $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d limit 1",
+ dbesc($observer_xchan),
+ intval($room_id)
+ );
+ if($r) {
+ q("update chatpresence set cp_last = '%s' where cp_id = %d and cp_client = '%s'",
+ dbesc(datetime_convert()),
+ intval($r[0]['cp_id']),
+ dbesc($client)
+ );
+ return true;
+ }
+
+ $r = q("insert into chatpresence ( cp_room, cp_xchan, cp_last, cp_status, cp_client )
+ values ( %d, '%s', '%s', '%s', '%s' )",
+ intval($room_id),
+ dbesc($observer_xchan),
+ dbesc(datetime_convert()),
+ dbesc($status),
+ dbesc($client)
+ );
+
+ return $r;
+ }
+
+
+ function leave($observer_xchan, $room_id, $client) {
+ if(! $room_id || ! $observer_xchan)
+ return;
+
+ $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d and cp_client = '%s' limit 1",
+ dbesc($observer_xchan),
+ intval($room_id),
+ dbesc($client)
+ );
+ if($r) {
+ q("delete from chatpresence where cp_id = %d",
+ intval($r[0]['cp_id'])
+ );
+ }
+
+ return true;
+ }
+
+
+ static public function roomlist($uid) {
+ require_once('include/security.php');
+ $sql_extra = permissions_sql($uid);
+
+ $r = q("select allow_cid, allow_gid, deny_cid, deny_gid, cr_name, cr_expire, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name",
+ intval($uid)
+ );
+
+ return $r;
+ }
+
+ static public function list_count($uid) {
+ require_once('include/security.php');
+ $sql_extra = permissions_sql($uid);
+
+ $r = q("select count(*) as total from chatroom where cr_uid = %d $sql_extra",
+ intval($uid)
+ );
+
+ return $r[0]['total'];
+ }
+
+ /**
+ * create a chat message via API.
+ * It is the caller's responsibility to enter the room.
+ */
+
+ static public function message($uid, $room_id, $xchan, $text) {
+
+ $ret = array('success' => false);
+
+ if(! $text)
+ return;
+
+ $sql_extra = permissions_sql($uid);
+
+ $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra",
+ intval($uid),
+ intval($room_id)
+ );
+ if(! $r)
+ return $ret;
+
+ $arr = array(
+ 'chat_room' => $room_id,
+ 'chat_xchan' => $xchan,
+ 'chat_text' => $text
+ );
+
+ call_hooks('chat_message', $arr);
+
+ $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text )
+ values( %d, '%s', '%s', '%s' )",
+ intval($room_id),
+ dbesc($xchan),
+ dbesc(datetime_convert()),
+ dbesc($arr['chat_text'])
+ );
+
+ $ret['success'] = true;
+ return $ret;
+ }
+}
diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php
new file mode 100644
index 000000000..d4ee1aeda
--- /dev/null
+++ b/Zotlabs/Lib/Config.php
@@ -0,0 +1,166 @@
+ $datarray['banner'],
- '$notify_icon' => Zotlabs\Project\System::get_notify_icon(),
+ '$notify_icon' => \Zotlabs\Lib\System::get_notify_icon(),
'$product' => $datarray['product'],
'$preamble' => $datarray['preamble'],
'$sitename' => $datarray['sitename'],
@@ -570,7 +574,7 @@ function notification($params) {
// use the EmailNotification library to send the message
- enotify::send(array(
+ self::send(array(
'fromName' => $sender_name,
'fromEmail' => $sender_email,
'replyTo' => $sender_email,
@@ -587,12 +591,6 @@ function notification($params) {
}
-/**
- * @brief A class for sending email notifications.
- *
- * @fixme Class names start mostly with capital letter to distinguish them easier.
- */
-class enotify {
/**
* @brief Send a multipart/alternative message with Text and HTML versions.
*
@@ -649,4 +647,39 @@ class enotify {
);
logger("notification: enotify::send returns " . $res, LOGGER_DEBUG);
}
+
+ static public function format($item) {
+
+ $ret = '';
+
+ require_once('include/conversation.php');
+
+ // Call localize_item with the "brief" flag to get a one line status for activities.
+ // This should set $item['localized'] to indicate we have a brief summary.
+
+ localize_item($item);
+
+ if($item_localize) {
+ $itemem_text = $item['localize'];
+ }
+ else {
+ $itemem_text = (($item['item_thread_top'])
+ ? t('created a new post')
+ : sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name']));
+ }
+
+ // convert this logic into a json array just like the system notifications
+
+ return array(
+ 'notify_link' => $item['llink'],
+ 'name' => $item['author']['xchan_name'],
+ 'url' => $item['author']['xchan_url'],
+ 'photo' => $item['author']['xchan_photo_s'],
+ 'when' => relative_date($item['created']),
+ 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
+ 'message' => strip_tags(bbcode($itemem_text))
+ );
+
+ }
+
}
diff --git a/Zotlabs/Lib/IConfig.php b/Zotlabs/Lib/IConfig.php
new file mode 100644
index 000000000..28c9ab58e
--- /dev/null
+++ b/Zotlabs/Lib/IConfig.php
@@ -0,0 +1,165 @@
+ $family, 'k' => $key, 'v' => $value, 'sharing' => $sharing);
+
+ if(is_null($idx))
+ $item['iconfig'][] = $entry;
+ else
+ $item['iconfig'][$idx] = $entry;
+ return $value;
+ }
+
+ if(intval($item))
+ $iid = intval($item);
+
+ if(! $iid)
+ return false;
+
+ if(self::Get($item, $family, $key) === false) {
+ $r = q("insert into iconfig( iid, cat, k, v, sharing ) values ( %d, '%s', '%s', '%s', %d ) ",
+ intval($iid),
+ dbesc($family),
+ dbesc($key),
+ dbesc($dbvalue),
+ intval($sharing)
+ );
+ }
+ else {
+ $r = q("update iconfig set v = '%s', sharing = %d where iid = %d and cat = '%s' and k = '%s' ",
+ dbesc($dbvalue),
+ intval($sharing),
+ intval($iid),
+ dbesc($family),
+ dbesc($key)
+ );
+ }
+
+ if(! $r)
+ return false;
+
+ return $value;
+ }
+
+
+
+ static public function Delete(&$item, $family, $key) {
+
+
+ $is_item = false;
+ $idx = null;
+
+ if(is_array($item)) {
+ $is_item = true;
+ if(is_array($item['iconfig'])) {
+ for($x = 0; $x < count($item['iconfig']); $x ++) {
+ if($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
+ unset($item['iconfig'][$x]);
+ }
+ }
+ }
+ return true;
+ }
+
+ if(intval($item))
+ $iid = intval($item);
+
+ if(! $iid)
+ return false;
+
+ return q("delete from iconfig where iid = %d and cat = '%s' and k = '%s' ",
+ intval($iid),
+ dbesc($family),
+ dbesc($key)
+ );
+
+ }
+
+}
\ No newline at end of file
diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php
new file mode 100644
index 000000000..195321375
--- /dev/null
+++ b/Zotlabs/Lib/PConfig.php
@@ -0,0 +1,189 @@
+get_app();
$this->data = $data;
$this->toplevel = ($this->get_id() == $this->get_data_value('parent'));
@@ -49,10 +48,18 @@ class Item extends BaseObject {
continue;
}
- $child = new Item($item);
+ $child = new ThreadItem($item);
$this->add_child($child);
}
}
+
+ // allow a site to configure the order and content of the reaction emoji list
+ if($this->toplevel) {
+ $x = get_config('system','reactions');
+ if($x && is_array($x) && count($x)) {
+ $this->reactions = $x;
+ }
+ }
}
/**
@@ -67,7 +74,6 @@ class Item extends BaseObject {
$result = array();
- $a = $this->get_app();
$item = $this->get_data();
$commentww = '';
@@ -219,7 +225,8 @@ class Item extends BaseObject {
);
}
- } else {
+ }
+ else {
$indent = 'comment';
}
@@ -348,8 +355,9 @@ class Item extends BaseObject {
'photo' => $body['photo'],
'event' => $body['event'],
'has_tags' => $has_tags,
-
+ 'reactions' => $this->reactions,
// Item toolbar buttons
+ 'emojis' => (($this->is_toplevel() && $this->is_commentable() && feature_enabled($conv->get_profile_owner(),'emojis')) ? '1' : ''),
'like' => $like,
'dislike' => ((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike : ''),
'share' => $share,
@@ -675,7 +683,6 @@ class Item extends BaseObject {
$template = get_markup_template($this->get_comment_box_template());
- $a = $this->get_app();
$observer = $conv->get_observer();
$qc = ((local_channel()) ? get_pconfig(local_channel(),'system','qcomment') : null);
@@ -714,7 +721,7 @@ class Item extends BaseObject {
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
'$cipher' => $conv->get_cipher(),
- '$sourceapp' => App::$sourcename
+ '$sourceapp' => \App::$sourcename
));
diff --git a/include/ConversationObject.php b/Zotlabs/Lib/ThreadStream.php
similarity index 93%
rename from include/ConversationObject.php
rename to Zotlabs/Lib/ThreadStream.php
index 82f381b0c..a6d4f8517 100644
--- a/include/ConversationObject.php
+++ b/Zotlabs/Lib/ThreadStream.php
@@ -1,11 +1,8 @@
get_mode() == $mode)
return;
- $a = $this->get_app();
-
- $this->observer = App::get_observer();
+ $this->observer = \App::get_observer();
$ob_hash = (($this->observer) ? $this->observer['xchan_hash'] : '');
switch($mode) {
@@ -57,7 +52,7 @@ class Conversation extends BaseObject {
$this->writable = true;
break;
case 'channel':
- $this->profile_owner = App::$profile['profile_uid'];
+ $this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
break;
case 'display':
@@ -67,7 +62,7 @@ class Conversation extends BaseObject {
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
break;
case 'page':
- $this->profile_owner = App::$profile['uid'];
+ $this->profile_owner = \App::$profile['uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
break;
default:
@@ -170,7 +165,7 @@ class Conversation extends BaseObject {
$item->set_commentable(can_comment_on_post($this->observer['xchan_hash'],$item->data));
}
}
- require_once('include/identity.php');
+ require_once('include/channel.php');
$item->set_conversation($this);
$this->threads[] = $item;
diff --git a/Zotlabs/Lib/XConfig.php b/Zotlabs/Lib/XConfig.php
new file mode 100644
index 000000000..e28dcf559
--- /dev/null
+++ b/Zotlabs/Lib/XConfig.php
@@ -0,0 +1,160 @@
+ "g",
- "photo" => "images/twopeople.png",
- "name" => $g['name'],
- "id" => $g['id'],
- "xid" => $g['hash'],
- "uids" => group_get_members_xchan($g['id']),
- "link" => ''
- );
+
+ if($r) {
+ foreach($r as $g){
+ // logger('acl: group: ' . $g['gname'] . ' members: ' . group_get_members_xchan($g['id']));
+ $groups[] = array(
+ "type" => "g",
+ "photo" => "images/twopeople.png",
+ "name" => $g['gname'],
+ "id" => $g['id'],
+ "xid" => $g['hash'],
+ "uids" => group_get_members_xchan($g['id']),
+ "link" => ''
+ );
+ }
}
}
@@ -204,7 +206,7 @@ class Acl extends \Zotlabs\Web\Controller {
else
$r = array();
- if(count($r)) {
+ if($r) {
foreach($r as $g){
// remove RSS feeds from ACLs - they are inaccessible
@@ -260,7 +262,7 @@ class Acl extends \Zotlabs\Web\Controller {
// logger('navbar_complete');
- if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
return;
}
diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php
index e2e6146f8..085d13fd7 100644
--- a/Zotlabs/Module/Admin.php
+++ b/Zotlabs/Module/Admin.php
@@ -32,8 +32,8 @@ class Admin extends \Zotlabs\Web\Controller {
case 'site':
$this->admin_page_site_post($a);
break;
- case 'users':
- $this->admin_page_users_post($a);
+ case 'accounts':
+ $this->admin_page_accounts_post($a);
break;
case 'channels':
$this->admin_page_channels_post($a);
@@ -127,8 +127,8 @@ class Admin extends \Zotlabs\Web\Controller {
case 'site':
$o = $this->admin_page_site($a);
break;
- case 'users':
- $o = $this->admin_page_users($a);
+ case 'accounts':
+ $o = $this->admin_page_accounts($a);
break;
case 'channels':
$o = $this->admin_page_channels($a);
@@ -872,20 +872,20 @@ class Admin extends \Zotlabs\Web\Controller {
}
/**
- * @brief Handle POST actions on users admin page.
+ * @brief Handle POST actions on accounts admin page.
*
* This function is called when on the admin user/account page the form was
* submitted to handle multiple operations at once. If one of the icons next
- * to an entry are pressed the function admin_page_users() will handle this.
+ * to an entry are pressed the function admin_page_accounts() will handle this.
*
* @param App $a
*/
- function admin_page_users_post($a) {
+ function admin_page_accounts_post($a) {
$pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
$users = ( x($_POST, 'user') ? $_POST['user'] : array() );
$blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : array() );
- check_form_security_token_redirectOnErr('/admin/users', 'admin_users');
+ check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
// change to switch structure?
// account block/unblock button was submitted
@@ -901,8 +901,7 @@ class Admin extends \Zotlabs\Web\Controller {
notice( sprintf( tt("%s account blocked/unblocked", "%s account blocked/unblocked", count($users)), count($users)) );
}
// account delete button was submitted
- if (x($_POST, 'page_users_delete')) {
- require_once('include/Contact.php');
+ if (x($_POST, 'page_accounts_delete')) {
foreach ($users as $uid){
account_remove($uid, true, false);
}
@@ -921,20 +920,20 @@ class Admin extends \Zotlabs\Web\Controller {
}
}
- goaway(z_root() . '/admin/users' );
+ goaway(z_root() . '/admin/accounts' );
}
/**
- * @brief Generate users admin page and handle single item operations.
+ * @brief Generate accounts admin page and handle single item operations.
*
- * This function generates the users/account admin page and handles the actions
+ * This function generates the accounts/account admin page and handles the actions
* if an icon next to an entry was clicked. If several items were selected and
- * the form was submitted it is handled by the function admin_page_users_post().
+ * the form was submitted it is handled by the function admin_page_accounts_post().
*
* @param App &$a
* @return string
*/
- function admin_page_users(&$a){
+ function admin_page_accounts(&$a){
if (argc() > 2) {
$uid = argv(3);
$account = q("SELECT * FROM account WHERE account_id = %d",
@@ -943,15 +942,14 @@ class Admin extends \Zotlabs\Web\Controller {
if (! $account) {
notice( t('Account not found') . EOL);
- goaway(z_root() . '/admin/users' );
+ goaway(z_root() . '/admin/accounts' );
}
- check_form_security_token_redirectOnErr('/admin/users', 'admin_users', 't');
+ check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't');
switch (argv(2)){
case 'delete':
// delete user
- require_once('include/Contact.php');
account_remove($uid,true,false);
notice( sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL);
@@ -974,7 +972,7 @@ class Admin extends \Zotlabs\Web\Controller {
break;
}
- goaway(z_root() . '/admin/users' );
+ goaway(z_root() . '/admin/accounts' );
}
/* get pending */
@@ -982,7 +980,7 @@ class Admin extends \Zotlabs\Web\Controller {
intval(ACCOUNT_PENDING)
);
- /* get users */
+ /* get accounts */
$total = q("SELECT count(*) as total FROM account");
if (count($total)) {
@@ -990,22 +988,20 @@ class Admin extends \Zotlabs\Web\Controller {
\App::set_pager_itemspage(100);
}
-
- // We'll still need to link email addresses to admin/users/channels or some such, but this bit doesn't exist yet.
- // That's where we need to be doing last post/channel flags/etc, not here.
-
$serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : '');
+
+ $key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id');
+ $dir = 'asc';
+ if(array_key_exists('dir',$_REQUEST))
+ $dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');
+
+ $base = z_root() . '/admin/accounts?f=';
+ $odir = (($dir === 'asc') ? '0' : '1');
- $order = " order by account_email asc ";
- if($_REQUEST['order'] === 'expires')
- $order = " order by account_expires desc ";
- if($_REQUEST['order'] === 'created')
- $order = " order by account_created desc ";
-
- $users = q("SELECT `account_id` , `account_email`, `account_lastlog`, `account_created`, `account_expires`, " . "`account_service_class`, ( account_flags & %d )>0 as `blocked`, " .
+ $users = q("SELECT `account_id` , `account_email`, `account_lastlog`, `account_created`, `account_expires`, " . "`account_service_class`, ( account_flags & %d ) > 0 as `blocked`, " .
"(SELECT %s FROM channel as ch " .
"WHERE ch.channel_account_id = ac.account_id and ch.channel_removed = 0 ) as `channels` " .
- "FROM account as ac where true $serviceclass $order limit %d offset %d ",
+ "FROM account as ac where true $serviceclass order by $key $dir limit %d offset %d ",
intval(ACCOUNT_BLOCKED),
db_concat('ch.channel_address', ' '),
intval(\App::$pager['itemspage']),
@@ -1028,14 +1024,14 @@ class Admin extends \Zotlabs\Web\Controller {
// }
// $users = array_map("_setup_users", $users);
- $t = get_markup_template('admin_users.tpl');
+ $t = get_markup_template('admin_accounts.tpl');
$o = replace_macros($t, array(
// strings //
'$title' => t('Administration'),
- '$page' => t('Users'),
+ '$page' => t('Accounts'),
'$submit' => t('Submit'),
'$select_all' => t('select all'),
- '$h_pending' => t('User registrations waiting for confirm'),
+ '$h_pending' => t('Registrations waiting for confirm'),
'$th_pending' => array( t('Request date'), t('Email') ),
'$no_pending' => t('No registrations.'),
'$approve' => t('Approve'),
@@ -1043,14 +1039,22 @@ class Admin extends \Zotlabs\Web\Controller {
'$delete' => t('Delete'),
'$block' => t('Block'),
'$unblock' => t('Unblock'),
-
- '$h_users' => t('Users'),
- '$th_users' => array( t('ID'), t('Email'), t('All Channels'), t('Register date'), t('Last login'), t('Expires'), t('Service Class')),
+ '$odir' => $odir,
+ '$base' => $base,
+ '$h_users' => t('Accounts'),
+ '$th_users' => array(
+ [ t('ID'), 'account_id' ],
+ [ t('Email'), 'account_email' ],
+ [ t('All Channels'), 'channels' ],
+ [ t('Register date'), 'account_created' ],
+ [ t('Last login'), 'account_lastlog' ],
+ [ t('Expires'), 'account_expires' ],
+ [ t('Service Class'), 'account_service_class'] ),
'$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
- '$form_security_token' => get_form_security_token("admin_users"),
+ '$form_security_token' => get_form_security_token("admin_accounts"),
// values //
'$baseurl' => z_root(),
@@ -1082,7 +1086,7 @@ class Admin extends \Zotlabs\Web\Controller {
intval(PAGE_CENSORED),
intval( $uid )
);
- proc_run('php','include/directory.php',$uid,'nopush');
+ \Zotlabs\Daemon\Master::Summon(array('Directory',$uid,'nopush'));
}
notice( sprintf( tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels)) );
}
@@ -1096,7 +1100,6 @@ class Admin extends \Zotlabs\Web\Controller {
notice( sprintf( tt("%s channel code allowed/disallowed", "%s channels code allowed/disallowed", count($channels)), count($channels)) );
}
if (x($_POST,'page_channels_delete')){
- require_once("include/Contact.php");
foreach($channels as $uid){
channel_remove($uid,true);
}
@@ -1128,7 +1131,6 @@ class Admin extends \Zotlabs\Web\Controller {
case "delete":{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
// delete channel
- require_once("include/Contact.php");
channel_remove($uid,true);
notice( sprintf(t("Channel '%s' deleted"), $channel[0]['channel_name']) . EOL);
@@ -1141,7 +1143,7 @@ class Admin extends \Zotlabs\Web\Controller {
intval($pflags),
intval( $uid )
);
- proc_run('php','include/directory.php',$uid,'nopush');
+ \Zotlabs\Daemon\Master::Summon(array('Directory',$uid,'nopush'));
notice( sprintf( (($pflags & PAGE_CENSORED) ? t("Channel '%s' censored"): t("Channel '%s' uncensored")) , $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')' ) . EOL);
}; break;
@@ -1162,6 +1164,17 @@ class Admin extends \Zotlabs\Web\Controller {
}
goaway(z_root() . '/admin/channels' );
}
+
+
+ $key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'channel_id');
+ $dir = 'asc';
+ if(array_key_exists('dir',$_REQUEST))
+ $dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc');
+
+ $base = z_root() . '/admin/channels?f=';
+ $odir = (($dir === 'asc') ? '0' : '1');
+
+
/* get channels */
@@ -1170,14 +1183,12 @@ class Admin extends \Zotlabs\Web\Controller {
\App::set_pager_total($total[0]['total']);
\App::set_pager_itemspage(100);
}
-
- $order = " order by channel_name asc ";
-
- $channels = q("SELECT * from channel where channel_removed = 0 and channel_system = 0 $order limit %d offset %d ",
+
+ $channels = q("SELECT * from channel where channel_removed = 0 and channel_system = 0 order by $key $dir limit %d offset %d ",
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
);
-
+
if($channels) {
for($x = 0; $x < count($channels); $x ++) {
if($channels[$x]['channel_pageflags'] & PAGE_CENSORED)
@@ -1205,7 +1216,12 @@ class Admin extends \Zotlabs\Web\Controller {
'$code' => t('Allow Code'),
'$uncode' => t('Disallow Code'),
'$h_channels' => t('Channel'),
- '$th_channels' => array( t('UID'), t('Name'), t('Address')),
+ '$base' => $base,
+ '$odir' => $odir,
+ '$th_channels' => array(
+ [ t('UID'), 'channel_id' ],
+ [ t('Name'), 'channel_name' ],
+ [ t('Address'), 'channel_address' ]),
'$confirm_delete_multi' => t('Selected channels will be deleted!\n\nEverything that was posted in these channels on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The channel {0} will be deleted!\n\nEverything that was posted in this channel on this site will be permanently deleted!\n\nAre you sure?'),
@@ -1295,7 +1311,7 @@ class Admin extends \Zotlabs\Web\Controller {
$admin_form = '';
- $r = q("select * from addon where plugin_admin = 1 and name = '%s' limit 1",
+ $r = q("select * from addon where plugin_admin = 1 and aname = '%s' limit 1",
dbesc($plugin)
);
@@ -1408,7 +1424,9 @@ class Admin extends \Zotlabs\Web\Controller {
'$plugins' => $plugins,
'$disabled' => t('Disabled - version incompatibility'),
'$form_security_token' => get_form_security_token('admin_plugins'),
- '$addrepo' => t('Add Plugin Repo'),
+ '$managerepos' => t('Manage Repos'),
+ '$installedtitle' => t('Installed Plugin Repositories'),
+ '$addnewrepotitle' => t('Install a New Plugin Repository'),
'$expandform' => false,
'$form' => $admin_plugins_add_repo_form,
'$newRepoModal' => $newRepoModal,
@@ -1423,13 +1441,15 @@ class Admin extends \Zotlabs\Web\Controller {
function listAddonRepos() {
$addonrepos = [];
$addonDir = __DIR__ . '/../../extend/addon/';
- if ($handle = opendir($addonDir)) {
- while (false !== ($entry = readdir($handle))) {
- if ($entry != "." && $entry != "..") {
- $addonrepos[] = $entry;
+ if(is_dir($addonDir)) {
+ if ($handle = opendir($addonDir)) {
+ while (false !== ($entry = readdir($handle))) {
+ if ($entry != "." && $entry != "..") {
+ $addonrepos[] = $entry;
+ }
}
+ closedir($handle);
}
- closedir($handle);
}
return $addonrepos;
}
@@ -1718,7 +1738,7 @@ class Admin extends \Zotlabs\Web\Controller {
// name, label, value, help string, extra data...
'$debugging' => array('debugging', t("Debugging"),get_config('system','debugging'), ""),
- '$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your Red top-level directory.")),
+ '$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your top-level webserver directory.")),
'$loglevel' => array('loglevel', t("Log level"), get_config('system','loglevel'), "", $log_choices),
'$form_security_token' => get_form_security_token('admin_logs'),
@@ -1733,7 +1753,7 @@ class Admin extends \Zotlabs\Web\Controller {
} else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
- $extendDir = __DIR__ . '/../../store/git/sys/extend';
+ $extendDir = __DIR__ . '/../../store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
@@ -1746,7 +1766,7 @@ class Admin extends \Zotlabs\Web\Controller {
}
}
}
- $repoDir = __DIR__ . '/../../store/git/sys/extend/addon/' . $repoName;
+ $repoDir = __DIR__ . '/../../store/[data]/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
@@ -1758,6 +1778,18 @@ class Admin extends \Zotlabs\Web\Controller {
$git = new GitRepo('sys', null, false, $repoName, $repoDir);
try {
if ($git->pull()) {
+ $files = array_diff(scandir($repoDir), array('.', '..'));
+ foreach ($files as $file) {
+ if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
+ $source = '../extend/addon/' . $repoName . '/' . $file;
+ $target = realpath(__DIR__ . '/../../addon/') . '/' . $file;
+ unlink($target);
+ if (!symlink($source, $target)) {
+ logger('Error linking addons to /addon');
+ json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
+ }
+ }
+ }
json_return_and_die(array('message' => 'Repo updated.', 'success' => true));
} else {
json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
@@ -1771,7 +1803,7 @@ class Admin extends \Zotlabs\Web\Controller {
} else {
json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
}
- $extendDir = __DIR__ . '/../../store/git/sys/extend';
+ $extendDir = __DIR__ . '/../../store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
@@ -1784,7 +1816,7 @@ class Admin extends \Zotlabs\Web\Controller {
}
}
}
- $repoDir = __DIR__ . '/../../store/git/sys/extend/addon/' . $repoName;
+ $repoDir = __DIR__ . '/../../store/[data]/git/sys/extend/addon/' . $repoName;
if (!is_dir($repoDir)) {
logger('Repo directory does not exist: ' . $repoDir);
json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
@@ -1804,7 +1836,7 @@ class Admin extends \Zotlabs\Web\Controller {
if (array_key_exists('repoURL', $_REQUEST)) {
require __DIR__ . '/../../library/PHPGit.autoload.php'; // Load PHPGit dependencies
$repoURL = $_REQUEST['repoURL'];
- $extendDir = __DIR__ . '/../../store/git/sys/extend';
+ $extendDir = __DIR__ . '/../../store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
@@ -1832,7 +1864,7 @@ class Admin extends \Zotlabs\Web\Controller {
json_return_and_die(array('message' => 'Invalid git repo', 'success' => false));
}
$repoDir = $addonDir . '/' . $repoName;
- $tempRepoBaseDir = __DIR__ . '/../../store/git/sys/temp/';
+ $tempRepoBaseDir = __DIR__ . '/../../store/[data]/git/sys/temp/';
$tempAddonDir = $tempRepoBaseDir . $repoName;
if (!is_writable($addonDir) || !is_writable($tempAddonDir)) {
@@ -1866,9 +1898,9 @@ class Admin extends \Zotlabs\Web\Controller {
if (array_key_exists('repoURL', $_REQUEST)) {
require __DIR__ . '/../../library/PHPGit.autoload.php'; // Load PHPGit dependencies
$repoURL = $_REQUEST['repoURL'];
- $extendDir = __DIR__ . '/../../store/git/sys/extend';
+ $extendDir = __DIR__ . '/../../store/[data]/git/sys/extend';
$addonDir = $extendDir . '/addon';
- $tempAddonDir = __DIR__ . '/../../store/git/sys/temp';
+ $tempAddonDir = __DIR__ . '/../../store/[data]/git/sys/temp';
if (!file_exists($extendDir)) {
if (!mkdir($extendDir, 0770, true)) {
logger('Error creating extend folder: ' . $extendDir);
@@ -1880,6 +1912,12 @@ class Admin extends \Zotlabs\Web\Controller {
}
}
}
+ if (!is_dir($tempAddonDir)) {
+ if (!mkdir($tempAddonDir, 0770, true)) {
+ logger('Error creating temp plugin repo folder: ' . $tempAddonDir);
+ json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false));
+ }
+ }
$repoName = null;
if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
$repoName = $_REQUEST['repoName'];
diff --git a/Zotlabs/Module/Api.php b/Zotlabs/Module/Api.php
index 3e7f23b6c..e4744c29f 100644
--- a/Zotlabs/Module/Api.php
+++ b/Zotlabs/Module/Api.php
@@ -107,7 +107,7 @@ class Api extends \Zotlabs\Web\Controller {
$r = q("SELECT `clients`.*
FROM `clients`, `tokens`
WHERE `clients`.`client_id`=`tokens`.`client_id`
- AND `tokens`.`id`='%s' AND `tokens`.`scope`='request'",
+ AND `tokens`.`id`='%s' AND `tokens`.`auth_scope`='request'",
dbesc($token));
if (!count($r))
diff --git a/Zotlabs/Module/Appman.php b/Zotlabs/Module/Appman.php
index ba2a64f35..a200e986a 100644
--- a/Zotlabs/Module/Appman.php
+++ b/Zotlabs/Module/Appman.php
@@ -2,8 +2,9 @@
namespace Zotlabs\Module;
-require_once('include/apps.php');
+//require_once('include/apps.php');
+use \Zotlabs\Lib as Zlib;
class Appman extends \Zotlabs\Web\Controller {
@@ -30,16 +31,16 @@ class Appman extends \Zotlabs\Web\Controller {
'categories' => escape_tags($_REQUEST['categories'])
);
- $_REQUEST['appid'] = app_install(local_channel(),$arr);
+ $_REQUEST['appid'] = Zlib\Apps::app_install(local_channel(),$arr);
- if(app_installed(local_channel(),$arr))
+ if(Zlib\Apps::app_installed(local_channel(),$arr))
info( t('App installed.') . EOL);
return;
}
- $papp = app_decode($_POST['papp']);
+ $papp = Zlib\Apps::app_decode($_POST['papp']);
if(! is_array($papp)) {
notice( t('Malformed app.') . EOL);
@@ -47,13 +48,13 @@ class Appman extends \Zotlabs\Web\Controller {
}
if($_POST['install']) {
- app_install(local_channel(),$papp);
- if(app_installed(local_channel(),$papp))
+ Zlib\Apps::app_install(local_channel(),$papp);
+ if(Zlib\Apps::app_installed(local_channel(),$papp))
info( t('App installed.') . EOL);
}
if($_POST['delete']) {
- app_destroy(local_channel(),$papp);
+ Zlib\Apps::app_destroy(local_channel(),$papp);
}
if($_POST['edit']) {
@@ -100,7 +101,7 @@ class Appman extends \Zotlabs\Web\Controller {
}
}
- $embed = array('embed', t('Embed code'), app_encode($app,true),'', 'onclick="this.select();"');
+ $embed = array('embed', t('Embed code'), Zlib\Apps::app_encode($app,true),'', 'onclick="this.select();"');
}
diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php
index 33259b319..4bdec4573 100644
--- a/Zotlabs/Module/Apps.php
+++ b/Zotlabs/Module/Apps.php
@@ -1,8 +1,9 @@
1) {
@@ -94,7 +91,7 @@ class Cal extends \Zotlabs\Web\Controller {
$mode = 'view';
$y = 0;
$m = 0;
- $ignored = ((x($_REQUEST,'ignored')) ? " and ignored = " . intval($_REQUEST['ignored']) . " " : '');
+ $ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
// logger('args: ' . print_r(\App::$argv,true));
@@ -149,7 +146,7 @@ class Cal extends \Zotlabs\Web\Controller {
$ftext = datetime_convert('UTC',$tz,$fdt);
$ftext = substr($ftext,0,14) . "00:00";
- $type = ((x($orig_event)) ? $orig_event['type'] : 'event');
+ $type = ((x($orig_event)) ? $orig_event['etype'] : 'event');
$f = get_config('system','event_input_format');
if(! $f)
@@ -160,7 +157,7 @@ class Cal extends \Zotlabs\Web\Controller {
$show_bd = perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts');
if(! $show_bd) {
- $sql_extra .= " and event.type != 'birthday' ";
+ $sql_extra .= " and event.etype != 'birthday' ";
}
@@ -228,8 +225,8 @@ class Cal extends \Zotlabs\Web\Controller {
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
from event left join item on event_hash = resource_id
where resource_type = 'event' and event.uid = %d $ignored
- AND (( adjust = 0 AND ( finish >= '%s' or nofinish = 1 ) AND start <= '%s' )
- OR ( adjust = 1 AND ( finish >= '%s' or nofinish = 1 ) AND start <= '%s' )) $sql_extra ",
+ AND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )
+ OR ( adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) $sql_extra ",
intval($channel['channel_id']),
dbesc($start),
dbesc($finish),
@@ -250,7 +247,7 @@ class Cal extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $rr) {
- $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
+ $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
if(! x($links,$j))
$links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j;
}
@@ -265,15 +262,15 @@ class Cal extends \Zotlabs\Web\Controller {
foreach($r as $rr) {
- $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
- $d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], $fmt) : datetime_convert('UTC','UTC',$rr['start'],$fmt));
+ $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
+ $d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
$d = day_translate($d);
- $start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'c') : datetime_convert('UTC','UTC',$rr['start'],'c'));
+ $start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
if ($rr['nofinish']){
$end = null;
} else {
- $end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['finish'], 'c') : datetime_convert('UTC','UTC',$rr['finish'],'c'));
+ $end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
}
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index f55705442..29bfcbc3c 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -13,353 +13,355 @@ require_once('include/PermissionDescription.php');
class Channel extends \Zotlabs\Web\Controller {
-function init() {
+ function init() {
- $which = null;
- if(argc() > 1)
- $which = argv(1);
- if(! $which) {
- if(local_channel()) {
- $channel = \App::get_channel();
- if($channel && $channel['channel_address'])
+ $which = null;
+ if(argc() > 1)
+ $which = argv(1);
+ if(! $which) {
+ if(local_channel()) {
+ $channel = \App::get_channel();
+ if($channel && $channel['channel_address'])
+ $which = $channel['channel_address'];
+ }
+ }
+ if(! $which) {
+ notice( t('You must be logged in to see this page.') . EOL );
+ return;
+ }
+
+ $profile = 0;
+ $channel = \App::get_channel();
+
+ if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
$which = $channel['channel_address'];
+ $profile = argv(1);
}
- }
- if(! $which) {
- notice( t('You must be logged in to see this page.') . EOL );
- return;
+
+ \App::$page['htmlhead'] .= ' ' . "\r\n" ;
+ \App::$page['htmlhead'] .= ' ' . "\r\n" ;
+
+ // Not yet ready for prime time
+ // \App::$page['htmlhead'] .= ' ' . "\r\n" ;
+ // \App::$page['htmlhead'] .= ' ' . "\r\n" ;
+
+ // Run profile_load() here to make sure the theme is set before
+ // we start loading content
+
+ profile_load($a,$which,$profile);
+
}
- $profile = 0;
- $channel = \App::get_channel();
-
- if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
- $which = $channel['channel_address'];
- $profile = argv(1);
- }
-
- \App::$page['htmlhead'] .= ' ' . "\r\n" ;
- \App::$page['htmlhead'] .= ' ' . "\r\n" ;
-
-// Not yet ready for prime time
-// \App::$page['htmlhead'] .= ' ' . "\r\n" ;
-// \App::$page['htmlhead'] .= ' ' . "\r\n" ;
-
- // Run profile_load() here to make sure the theme is set before
- // we start loading content
-
- profile_load($a,$which,$profile);
-
-}
-
-function get($update = 0, $load = false) {
+ function get($update = 0, $load = false) {
- if($load)
- $_SESSION['loadtime'] = datetime_convert();
+ if($load)
+ $_SESSION['loadtime'] = datetime_convert();
- $checkjs = new \Zotlabs\Web\CheckJS(1);
+ $checkjs = new \Zotlabs\Web\CheckJS(1);
- $category = $datequery = $datequery2 = '';
+ $category = $datequery = $datequery2 = '';
- $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
+ $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
- $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : '');
- $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : '');
+ $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : '');
+ $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : '');
- if(get_config('system','block_public') && (! get_account_id()) && (! remote_channel())) {
+ if(observer_prohibited(true)) {
return login();
- }
-
- $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
- $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
-
- $groups = array();
-
- $o = '';
-
- if($update) {
- // Ensure we've got a profile owner if updating.
- \App::$profile['profile_uid'] = \App::$profile_uid = $update;
- }
- else {
- if(\App::$profile['profile_uid'] == local_channel()) {
- nav_set_selected('home');
}
- }
- $is_owner = (((local_channel()) && (\App::$profile['profile_uid'] == local_channel())) ? true : false);
+ $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : '');
+ $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : '');
- $channel = \App::get_channel();
- $observer = \App::get_observer();
- $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+ $groups = array();
- $perms = get_all_perms(\App::$profile['profile_uid'],$ob_hash);
+ $o = '';
- if(! $perms['view_stream']) {
+ if($update) {
+ // Ensure we've got a profile owner if updating.
+ \App::$profile['profile_uid'] = \App::$profile_uid = $update;
+ }
+ else {
+ if(\App::$profile['profile_uid'] == local_channel()) {
+ nav_set_selected('home');
+ }
+ }
+
+ $is_owner = (((local_channel()) && (\App::$profile['profile_uid'] == local_channel())) ? true : false);
+
+ $channel = \App::get_channel();
+ $observer = \App::get_observer();
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ $perms = get_all_perms(\App::$profile['profile_uid'],$ob_hash);
+
+ if(! $perms['view_stream']) {
// We may want to make the target of this redirect configurable
if($perms['view_profile']) {
notice( t('Insufficient permissions. Request redirected to profile page.') . EOL);
goaway (z_root() . "/profile/" . \App::$profile['channel_address']);
}
- notice( t('Permission denied.') . EOL);
- return;
- }
-
-
- if(! $update) {
-
- $o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
-
- $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
-
- if($channel && $is_owner) {
- $channel_acl = array(
- 'allow_cid' => $channel['channel_allow_cid'],
- 'allow_gid' => $channel['channel_allow_gid'],
- 'deny_cid' => $channel['channel_deny_cid'],
- 'deny_gid' => $channel['channel_deny_gid']
- );
+ notice( t('Permission denied.') . EOL);
+ return;
}
+
+
+ if(! $update) {
+
+ $o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
+
+ $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
+
+ if($channel && $is_owner) {
+ $channel_acl = array(
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
+ );
+ }
+ else
+ $channel_acl = array();
+
+
+ if($perms['post_wall']) {
+
+ $x = array(
+ 'is_owner' => $is_owner,
+ 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(\App::$profile['profile_uid'],'system','use_browser_location')))) ? true : false),
+ 'default_location' => (($is_owner) ? \App::$profile['channel_location'] : ''),
+ 'nickname' => \App::$profile['channel_address'],
+ 'lockstate' => (((strlen(\App::$profile['channel_allow_cid'])) || (strlen(\App::$profile['channel_allow_gid'])) || (strlen(\App::$profile['channel_deny_cid'])) || (strlen(\App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'),
+ 'acl' => (($is_owner) ? populate_acl($channel_acl,true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''),
+ 'showacl' => (($is_owner) ? 'yes' : ''),
+ 'bang' => '',
+ 'visitor' => (($is_owner || $observer) ? true : false),
+ 'profile_uid' => \App::$profile['profile_uid'],
+ 'editor_autocomplete' => true,
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true
+ );
+
+ $o .= status_editor($a,$x);
+ }
+
+ }
+
+
+ /**
+ * Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups
+ */
+
+ $item_normal = item_normal();
+ $sql_extra = item_permissions_sql(\App::$profile['profile_uid']);
+
+ if(get_pconfig(\App::$profile['profile_uid'],'system','channel_list_mode') && (! $mid))
+ $page_mode = 'list';
else
- $channel_acl = array();
+ $page_mode = 'client';
+ $abook_uids = " and abook.abook_channel = " . intval(\App::$profile['profile_uid']) . " ";
- if($perms['post_wall']) {
+ $simple_update = (($update) ? " AND item_unseen = 1 " : '');
- $x = array(
- 'is_owner' => $is_owner,
- 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(\App::$profile['profile_uid'],'system','use_browser_location')))) ? true : false),
- 'default_location' => (($is_owner) ? \App::$profile['channel_location'] : ''),
- 'nickname' => \App::$profile['channel_address'],
- 'lockstate' => (((strlen(\App::$profile['channel_allow_cid'])) || (strlen(\App::$profile['channel_allow_gid'])) || (strlen(\App::$profile['channel_deny_cid'])) || (strlen(\App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'),
- 'acl' => (($is_owner) ? populate_acl($channel_acl,true, \PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''),
- 'showacl' => (($is_owner) ? 'yes' : ''),
- 'bang' => '',
- 'visitor' => (($is_owner || $observer) ? true : false),
- 'profile_uid' => \App::$profile['profile_uid'],
- 'editor_autocomplete' => true,
- 'bbco_autocomplete' => 'bbcode',
- 'bbcode' => true
- );
-
- $o .= status_editor($a,$x);
- }
-
- }
-
-
- /**
- * Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups
- */
-
- $item_normal = item_normal();
- $sql_extra = item_permissions_sql(\App::$profile['profile_uid']);
-
- if(get_pconfig(\App::$profile['profile_uid'],'system','channel_list_mode') && (! $mid))
- $page_mode = 'list';
- else
- $page_mode = 'client';
-
- $abook_uids = " and abook.abook_channel = " . intval(\App::$profile['profile_uid']) . " ";
-
- $simple_update = (($update) ? " AND item_unseen = 1 " : '');
-
- \App::$page['htmlhead'] .= "\r\n" . ' ' . "\r\n";
+ \App::$page['htmlhead'] .= "\r\n" . ' ' . "\r\n";
- if($update && $_SESSION['loadtime'])
- $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
- if($load)
- $simple_update = '';
+ if($update && $_SESSION['loadtime'])
+ $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
+ if($load)
+ $simple_update = '';
- if(($update) && (! $load)) {
+ if(($update) && (! $load)) {
- if ($mid) {
- $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal
- AND item_wall = 1 AND item_unseen = 1 $sql_extra limit 1",
- dbesc($mid . '%'),
- intval(\App::$profile['profile_uid'])
- );
- } else {
- $r = q("SELECT distinct parent AS `item_id`, created from item
- left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
- WHERE uid = %d $item_normal
- AND item_wall = 1 $simple_update
- AND (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra
- ORDER BY created DESC",
- intval(\App::$profile['profile_uid'])
- );
- $_SESSION['loadtime'] = datetime_convert();
- }
-
- }
- else {
-
- if(x($category)) {
- $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY));
- }
- if(x($hashtags)) {
- $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
- }
-
- if($datequery) {
- $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery))));
- }
- if($datequery2) {
- $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
- }
-
- $itemspage = get_pconfig(local_channel(),'system','itemspage');
- \App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
- $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
-
- if($load || ($checkjs->disabled())) {
- if ($mid) {
- $r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal
- AND item_wall = 1 $sql_extra limit 1",
- dbesc($mid),
+ if($mid) {
+ $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal
+ AND item_wall = 1 AND item_unseen = 1 $sql_extra limit 1",
+ dbesc($mid . '%'),
intval(\App::$profile['profile_uid'])
);
- if (! $r) {
- notice( t('Permission denied.') . EOL);
- }
-
- } else {
- $r = q("SELECT distinct id AS item_id, created FROM item
- left join abook on item.author_xchan = abook.abook_xchan
+ }
+ else {
+ $r = q("SELECT distinct parent AS `item_id`, created from item
+ left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
WHERE uid = %d $item_normal
- AND item_wall = 1 and item_thread_top = 1
- AND (abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra $sql_extra2
- ORDER BY created DESC $pager_sql ",
+ AND item_wall = 1 $simple_update
+ AND (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra
+ ORDER BY created DESC",
intval(\App::$profile['profile_uid'])
);
+ $_SESSION['loadtime'] = datetime_convert();
+ }
+
+ }
+ else {
+
+ if(x($category)) {
+ $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY));
+ }
+ if(x($hashtags)) {
+ $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG));
+ }
+
+ if($datequery) {
+ $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery))));
+ }
+ if($datequery2) {
+ $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2))));
+ }
+
+ $itemspage = get_pconfig(local_channel(),'system','itemspage');
+ \App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
+ $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
+
+ if($load || ($checkjs->disabled())) {
+ if($mid) {
+ $r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal
+ AND item_wall = 1 $sql_extra limit 1",
+ dbesc($mid),
+ intval(\App::$profile['profile_uid'])
+ );
+ if (! $r) {
+ notice( t('Permission denied.') . EOL);
+ }
+
+ }
+ else {
+ $r = q("SELECT distinct id AS item_id, created FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE uid = %d $item_normal
+ AND item_wall = 1 and item_thread_top = 1
+ AND (abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra $sql_extra2
+ ORDER BY created DESC $pager_sql ",
+ intval(\App::$profile['profile_uid'])
+ );
+ }
+ }
+ else {
+ $r = array();
+ }
+ }
+
+ if($r) {
+
+ $parents_str = ids_to_querystr($r,'item_id');
+
+ $items = q("SELECT `item`.*, `item`.`id` AS `item_id`
+ FROM `item`
+ WHERE `item`.`uid` = %d $item_normal
+ AND `item`.`parent` IN ( %s )
+ $sql_extra ",
+ intval(\App::$profile['profile_uid']),
+ dbesc($parents_str)
+ );
+
+ xchan_query($items);
+ $items = fetch_post_tags($items, true);
+ $items = conv_sort($items,'created');
+
+ if($load && $mid && (! count($items))) {
+ // This will happen if we don't have sufficient permissions
+ // to view the parent item (or the item itself if it is toplevel)
+ notice( t('Permission denied.') . EOL);
+ }
+
+ }
+ else {
+ $items = array();
+ }
+
+ if((! $update) && (! $load)) {
+
+ // This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
+ // because browser prefetching might change it on us. We have to deliver it with the page.
+
+ $maxheight = get_pconfig(\App::$profile['profile_uid'],'system','channel_divmore_height');
+ if(! $maxheight)
+ $maxheight = 400;
+
+ $o .= '
' . "\r\n";
+ $o .= "\r\n";
+
+ \App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
+ '$baseurl' => z_root(),
+ '$pgtype' => 'channel',
+ '$uid' => ((\App::$profile['profile_uid']) ? \App::$profile['profile_uid'] : '0'),
+ '$gid' => '0',
+ '$cid' => '0',
+ '$cmin' => '0',
+ '$cmax' => '0',
+ '$star' => '0',
+ '$liked' => '0',
+ '$conv' => '0',
+ '$spam' => '0',
+ '$nouveau' => '0',
+ '$wall' => '1',
+ '$fh' => '0',
+ '$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
+ '$search' => '',
+ '$order' => '',
+ '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
+ '$file' => '',
+ '$cats' => (($category) ? $category : ''),
+ '$tags' => (($hashtags) ? $hashtags : ''),
+ '$mid' => $mid,
+ '$verb' => '',
+ '$dend' => $datequery,
+ '$dbegin' => $datequery2
+ ));
+
+
+ }
+
+ $update_unseen = '';
+
+ if($page_mode === 'list') {
+
+ /**
+ * in "list mode", only mark the parent item and any like activities as "seen".
+ * We won't distinguish between comment likes and post likes. The important thing
+ * is that the number of unseen comments will be accurate. The SQL to separate the
+ * comment likes could also get somewhat hairy.
+ */
+
+ if($parents_str) {
+ $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
+ $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
}
}
else {
- $r = array();
- }
- }
-
- if($r) {
-
- $parents_str = ids_to_querystr($r,'item_id');
-
- $items = q("SELECT `item`.*, `item`.`id` AS `item_id`
- FROM `item`
- WHERE `item`.`uid` = %d $item_normal
- AND `item`.`parent` IN ( %s )
- $sql_extra ",
- intval(\App::$profile['profile_uid']),
- dbesc($parents_str)
- );
-
- xchan_query($items);
- $items = fetch_post_tags($items, true);
- $items = conv_sort($items,'created');
-
- if ($load && $mid && (! count($items))) {
- // This will happen if we don't have sufficient permissions
- // to view the parent item (or the item itself if it is toplevel)
- notice( t('Permission denied.') . EOL);
+ if($parents_str) {
+ $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
+ }
}
- } else {
- $items = array();
- }
-
- if((! $update) && (! $load)) {
-
- // This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
- // because browser prefetching might change it on us. We have to deliver it with the page.
-
- $maxheight = get_pconfig(\App::$profile['profile_uid'],'system','channel_divmore_height');
- if(! $maxheight)
- $maxheight = 400;
-
- $o .= '
' . "\r\n";
- $o .= "\r\n";
-
- \App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
- '$baseurl' => z_root(),
- '$pgtype' => 'channel',
- '$uid' => ((\App::$profile['profile_uid']) ? \App::$profile['profile_uid'] : '0'),
- '$gid' => '0',
- '$cid' => '0',
- '$cmin' => '0',
- '$cmax' => '0',
- '$star' => '0',
- '$liked' => '0',
- '$conv' => '0',
- '$spam' => '0',
- '$nouveau' => '0',
- '$wall' => '1',
- '$fh' => '0',
- '$page' => ((\App::$pager['page'] != 1) ? \App::$pager['page'] : 1),
- '$search' => '',
- '$order' => '',
- '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0),
- '$file' => '',
- '$cats' => (($category) ? $category : ''),
- '$tags' => (($hashtags) ? $hashtags : ''),
- '$mid' => $mid,
- '$verb' => '',
- '$dend' => $datequery,
- '$dbegin' => $datequery2
- ));
-
-
- }
-
- $update_unseen = '';
-
- if($page_mode === 'list') {
-
- /**
- * in "list mode", only mark the parent item and any like activities as "seen".
- * We won't distinguish between comment likes and post likes. The important thing
- * is that the number of unseen comments will be accurate. The SQL to separate the
- * comment likes could also get somewhat hairy.
- */
-
- if($parents_str) {
- $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
- $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
+ if($is_owner && $update_unseen) {
+ $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
+ intval(local_channel())
+ );
}
- }
- else {
- if($parents_str) {
- $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
+
+
+ if($checkjs->disabled()) {
+ $o .= conversation($a,$items,'channel',$update,'traditional');
+ }
+ else {
+ $o .= conversation($a,$items,'channel',$update,$page_mode);
}
+
+ if((! $update) || ($checkjs->disabled())) {
+ $o .= alt_pager($a,count($items));
+ if ($mid && $items[0]['title'])
+ \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title'];
+ }
+
+ if($mid)
+ $o .= '
';
+
+ return $o;
}
-
- if($is_owner && $update_unseen) {
- $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
- intval(local_channel())
- );
- }
-
-
- if($checkjs->disabled()) {
- $o .= conversation($a,$items,'channel',$update,'traditional');
- } else {
- $o .= conversation($a,$items,'channel',$update,$page_mode);
- }
-
- if((! $update) || ($checkjs->disabled())) {
- $o .= alt_pager($a,count($items));
- if ($mid && $items[0]['title'])
- \App::$page['title'] = $items[0]['title'] . " - " . \App::$page['title'];
- }
-
- if($mid)
- $o .= '
';
-
- return $o;
-}
-
-
}
\ No newline at end of file
diff --git a/Zotlabs/Module/Chanview.php b/Zotlabs/Module/Chanview.php
index f70444816..c6dd07eb7 100644
--- a/Zotlabs/Module/Chanview.php
+++ b/Zotlabs/Module/Chanview.php
@@ -1,10 +1,8 @@
$room));
+ Zlib\Chatroom::destroy($channel,array('cr_name' => $room));
goaway(z_root() . '/chat/' . $channel['channel_address']);
}
@@ -67,7 +69,7 @@ class Chat extends \Zotlabs\Web\Controller {
if(intval($arr['expire']) < 0)
$arr['expire'] = 0;
- chatroom_create($channel,$arr);
+ Zlib\Chatroom::create($channel,$arr);
$x = q("select * from chatroom where cr_name = '%s' and cr_uid = %d limit 1",
dbesc($room),
@@ -87,7 +89,7 @@ class Chat extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
if(local_channel())
$channel = \App::get_channel();
@@ -105,7 +107,7 @@ class Chat extends \Zotlabs\Web\Controller {
}
if((argc() > 3) && intval(argv(2)) && (argv(3) === 'leave')) {
- chatroom_leave($observer,argv(2),$_SERVER['REMOTE_ADDR']);
+ Zlib\Chatroom::leave($observer,argv(2),$_SERVER['REMOTE_ADDR']);
goaway(z_root() . '/channel/' . argv(1));
}
@@ -158,7 +160,7 @@ class Chat extends \Zotlabs\Web\Controller {
$room_id = intval(argv(2));
$bookmark_link = get_bookmark_link($ob);
- $x = chatroom_enter($observer,$room_id,'online',$_SERVER['REMOTE_ADDR']);
+ $x = Zlib\Chatroom::enter($observer,$room_id,'online',$_SERVER['REMOTE_ADDR']);
if(! $x)
return;
$x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1",
@@ -238,10 +240,10 @@ class Chat extends \Zotlabs\Web\Controller {
));
}
- $rooms = chatroom_list(\App::$profile['profile_uid']);
+ $rooms = Zlib\Chatroom::roomlist(\App::$profile['profile_uid']);
$o .= replace_macros(get_markup_template('chatrooms.tpl'), array(
- '$header' => sprintf( t('%1$s\'s Chatrooms'), \App::$profile['name']),
+ '$header' => sprintf( t('%1$s\'s Chatrooms'), \App::$profile['fullname']),
'$name' => t('Name'),
'$baseurl' => z_root(),
'$nickname' => \App::$profile['channel_address'],
diff --git a/Zotlabs/Module/Chatsvc.php b/Zotlabs/Module/Chatsvc.php
index a9bc97301..6a28a7c4d 100644
--- a/Zotlabs/Module/Chatsvc.php
+++ b/Zotlabs/Module/Chatsvc.php
@@ -1,14 +1,16 @@
- false);
@@ -27,7 +29,7 @@ class Chatsvc extends \Zotlabs\Web\Controller {
}
- function post() {
+ function post() {
$ret = array('success' => false);
@@ -65,7 +67,7 @@ class Chatsvc extends \Zotlabs\Web\Controller {
json_return_and_die($ret);
}
- function get() {
+ function get() {
$status = strip_tags($_REQUEST['status']);
$room_id = intval(\App::$data['chat']['room_id']);
diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php
index f3767e3f0..b691475ce 100644
--- a/Zotlabs/Module/Cloud.php
+++ b/Zotlabs/Module/Cloud.php
@@ -100,9 +100,12 @@ class Cloud extends \Zotlabs\Web\Controller {
// require_once('\Zotlabs\Storage/QuotaPlugin.php');
// $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth));
+ ob_start();
// All we need to do now, is to fire up the server
$server->exec();
-
+
+ ob_end_flush();
+
killme();
}
diff --git a/Zotlabs/Module/Connect.php b/Zotlabs/Module/Connect.php
index 6ef3577d7..f68e0baac 100644
--- a/Zotlabs/Module/Connect.php
+++ b/Zotlabs/Module/Connect.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module; /** @file */
-require_once('include/Contact.php');
+
require_once('include/contact_widgets.php');
require_once('include/items.php');
@@ -47,7 +47,8 @@ class Connect extends \Zotlabs\Web\Controller {
intval(PAGE_PREMIUM),
intval(local_channel())
);
- proc_run('php','include/notifier.php','refresh_all',\App::$data['channel']['channel_id']);
+
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','refresh_all',\App::$data['channel']['channel_id']));
}
set_pconfig(\App::$data['channel']['channel_id'],'system','selltext',$text);
// reload the page completely to get fresh data
diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php
index 564f4e527..a412d16ae 100644
--- a/Zotlabs/Module/Connections.php
+++ b/Zotlabs/Module/Connections.php
@@ -1,9 +1,9 @@
'photo', 'type' => \App::$poi['xchan_photo_mimetype'], 'href' => \App::$poi['xchan_photo_l'])
),
);
- $xarr['object'] = json_encode($obj);
+ $xarr['obj'] = json_encode($obj);
$xarr['obj_type'] = ACTIVITY_OBJ_PERSON;
$xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . \App::$poi['xchan_url'] . ']' . \App::$poi['xchan_name'] . '[/zrl]';
@@ -283,7 +283,7 @@ class Connedit extends \Zotlabs\Web\Controller {
// pull in a bit of content if there is any to pull in
- proc_run('php','include/onepoll.php',$contact_id);
+ \Zotlabs\Daemon\Master::Summon(array('Onepoll',$contact_id));
}
@@ -414,7 +414,7 @@ class Connedit extends \Zotlabs\Web\Controller {
if($cmd === 'update') {
// pull feed and consume it, which should subscribe to the hub.
- proc_run('php',"include/poller.php","$contact_id");
+ \Zotlabs\Daemon\Master::Summon(array('Poller',$contact_id));
goaway(z_root() . '/connedit/' . $contact_id);
}
@@ -427,7 +427,7 @@ class Connedit extends \Zotlabs\Web\Controller {
else {
// if you are on a different network we'll force a refresh of the connection basic info
- proc_run('php','include/notifier.php','permission_update',$contact_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','permission_update',$contact_id));
}
goaway(z_root() . '/connedit/' . $contact_id);
}
@@ -485,7 +485,6 @@ class Connedit extends \Zotlabs\Web\Controller {
if($cmd === 'drop') {
- require_once('include/Contact.php');
// FIXME
// We need to send either a purge or a refresh packet to the other side (the channel being unfriended).
@@ -583,8 +582,6 @@ class Connedit extends \Zotlabs\Web\Controller {
if(intval($contact['abook_self']))
$self = true;
- require_once('include/contact_selectors.php');
-
$tpl = get_markup_template("abook_edit.tpl");
if(feature_enabled(local_channel(),'affinity')) {
diff --git a/Zotlabs/Module/Contactgroup.php b/Zotlabs/Module/Contactgroup.php
index 497442ff4..bbe56b4ad 100644
--- a/Zotlabs/Module/Contactgroup.php
+++ b/Zotlabs/Module/Contactgroup.php
@@ -41,10 +41,10 @@ class Contactgroup extends \Zotlabs\Web\Controller {
if($change) {
if(in_array($change,$preselected)) {
- group_rmv_member(local_channel(),$group['name'],$change);
+ group_rmv_member(local_channel(),$group['gname'],$change);
}
else {
- group_add_member(local_channel(),$group['name'],$change);
+ group_add_member(local_channel(),$group['gname'],$change);
}
}
}
diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php
index be27a99ef..a72c3389f 100644
--- a/Zotlabs/Module/Cover_photo.php
+++ b/Zotlabs/Module/Cover_photo.php
@@ -8,7 +8,7 @@ namespace Zotlabs\Module;
*/
require_once('include/photo/photo_driver.php');
-require_once('include/identity.php');
+require_once('include/channel.php');
@@ -80,7 +80,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$profile = $r[0];
}
- $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND scale = 0 LIMIT 1",
+ $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = 0 LIMIT 1",
dbesc($image_id),
intval(local_channel())
);
@@ -88,9 +88,9 @@ class Cover_photo extends \Zotlabs\Web\Controller {
if($r) {
$base_image = $r[0];
- $base_image['data'] = (($r[0]['os_storage']) ? @file_get_contents($base_image['data']) : dbunescbin($base_image['data']));
+ $base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents($base_image['content']) : dbunescbin($base_image['content']));
- $im = photo_factory($base_image['data'], $base_image['type']);
+ $im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
// We are scaling and cropping the relative pixel locations to the original photo instead of the
@@ -99,7 +99,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
// First load the scaled photo to check its size. (Should probably pass this in the post form and save
// a query.)
- $g = q("select width, height from photo where resource_id = '%s' and uid = %d and scale = 3",
+ $g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3",
dbesc($image_id),
intval(local_channel())
);
@@ -133,26 +133,26 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$p = array('aid' => $aid, 'uid' => local_channel(), 'resource_id' => $base_image['resource_id'],
'filename' => $base_image['filename'], 'album' => t('Cover Photos'));
- $p['scale'] = 7;
+ $p['imgscale'] = 7;
$p['photo_usage'] = PHOTO_COVER;
$r1 = $im->save($p);
$im->doScaleImage(850,310);
- $p['scale'] = 8;
+ $p['imgscale'] = 8;
$r2 = $im->save($p);
$im->doScaleImage(425,160);
- $p['scale'] = 9;
+ $p['imgscale'] = 9;
$r3 = $im->save($p);
if($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
- $x = q("delete from photo where resource_id = '%s' and uid = %d and scale >= 7 ",
+ $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ",
dbesc($base_image['resource_id']),
local_channel()
);
@@ -183,7 +183,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
logger('attach_store: ' . print_r($res,true));
if($res && intval($res['data']['is_photo'])) {
- $i = q("select * from photo where resource_id = '%s' and uid = %d and scale = 0",
+ $i = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = 0",
dbesc($hash),
intval(local_channel())
);
@@ -195,10 +195,10 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$os_storage = false;
foreach($i as $ii) {
- $smallest = intval($ii['scale']);
+ $smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']);
- $imagedata = $ii['data'];
- $filetype = $ii['type'];
+ $imagedata = $ii['content'];
+ $filetype = $ii['mimetype'];
}
}
@@ -224,10 +224,10 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
$arr['verb'] = ACTIVITY_UPDATE;
- $arr['object'] = json_encode(array(
+ $arr['obj'] = json_encode(array(
'type' => $arr['obj_type'],
'id' => z_root() . '/photo/' . $photo['resource_id'] . '-7',
- 'link' => array('rel' => 'photo', 'type' => $photo['type'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7')
+ 'link' => array('rel' => 'photo', 'type' => $photo['mimetype'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7')
));
if($profile && stripos($profile['gender'],t('female')) !== false)
@@ -295,7 +295,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
$resource_id = argv(2);
- $r = q("SELECT id, album, scale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY scale ASC",
+ $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC",
intval(local_channel()),
dbesc($resource_id)
);
@@ -305,11 +305,11 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
$havescale = false;
foreach($r as $rr) {
- if($rr['scale'] == 7)
+ if($rr['imgscale'] == 7)
$havescale = true;
}
- $r = q("SELECT `data`, `type`, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
+ $r = q("SELECT `content`, `mimetype`, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
intval($r[0]['id']),
intval(local_channel())
@@ -320,15 +320,15 @@ class Cover_photo extends \Zotlabs\Web\Controller {
}
if(intval($r[0]['os_storage']))
- $data = @file_get_contents($r[0]['data']);
+ $data = @file_get_contents($r[0]['content']);
else
- $data = dbunescbin($r[0]['data']);
+ $data = dbunescbin($r[0]['content']);
- $ph = photo_factory($data, $r[0]['type']);
+ $ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
- $i = q("select resource_id, scale from photo where resource_id = '%s' and uid = %d and scale = 0",
+ $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0",
dbesc($r[0]['resource_id']),
intval(local_channel())
);
@@ -336,7 +336,7 @@ class Cover_photo extends \Zotlabs\Web\Controller {
if($i) {
$hash = $i[0]['resource_id'];
foreach($i as $ii) {
- $smallest = intval($ii['scale']);
+ $smallest = intval($ii['imgscale']);
}
}
}
diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php
index 549c992cc..2fddabe19 100644
--- a/Zotlabs/Module/Dav.php
+++ b/Zotlabs/Module/Dav.php
@@ -64,6 +64,7 @@ class Dav extends \Zotlabs\Web\Controller {
$auth = new \Zotlabs\Storage\BasicAuth();
+ $auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'WebDAV');
// $authBackend = new \Sabre\DAV\Auth\Backend\BasicCallBack(function($userName,$password) {
// if(account_verify_password($userName,$password))
diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php
index b8bac53bb..560038ffc 100644
--- a/Zotlabs/Module/Directory.php
+++ b/Zotlabs/Module/Directory.php
@@ -57,9 +57,9 @@ class Directory extends \Zotlabs\Web\Controller {
}
}
- function get() {
+ function get() {
- if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index 2a5a04a2a..c1a0d84bc 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -7,17 +7,13 @@ class Display extends \Zotlabs\Web\Controller {
function get($update = 0, $load = false) {
- // logger("mod-display: update = $update load = $load");
-
-
$checkjs = new \Zotlabs\Web\CheckJS(1);
-
if($load)
$_SESSION['loadtime'] = datetime_convert();
- if(intval(get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
@@ -185,7 +181,7 @@ class Display extends \Zotlabs\Web\Controller {
if($load || ($checkjs->disabled())) {
$r = null;
- require_once('include/identity.php');
+ require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
@@ -233,7 +229,7 @@ class Display extends \Zotlabs\Web\Controller {
elseif($update && !$load) {
$r = null;
- require_once('include/identity.php');
+ require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
diff --git a/Zotlabs/Module/Editblock.php b/Zotlabs/Module/Editblock.php
index a79962033..fb86557f2 100644
--- a/Zotlabs/Module/Editblock.php
+++ b/Zotlabs/Module/Editblock.php
@@ -1,7 +1,7 @@
true,
'mimetype' => $itm[0]['mimetype'],
'ptyp' => $itm[0]['obj_type'],
- 'body' => undo_post_tagging($itm[0]['body']),
+ 'body' => htmlspecialchars_decode(undo_post_tagging($itm[0]['body']),ENT_COMPAT),
'post_id' => $post_id,
'defloc' => $channel['channel_location'],
'visitor' => true,
- 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
+ 'title' => htmlspecialchars_decode($itm[0]['title'],ENT_COMPAT),
'category' => $category,
'showacl' => false,
'profile_uid' => $owner_uid,
diff --git a/Zotlabs/Module/Editwebpage.php b/Zotlabs/Module/Editwebpage.php
index c2346c53b..1b5c320a0 100644
--- a/Zotlabs/Module/Editwebpage.php
+++ b/Zotlabs/Module/Editwebpage.php
@@ -1,7 +1,7 @@
$profile_uid,
- 'type' => TERM_CATEGORY,
+ 'ttype' => TERM_CATEGORY,
'otype' => TERM_OBJ_POST,
'term' => trim($cat),
'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
@@ -180,12 +180,12 @@ class Events extends \Zotlabs\Web\Controller {
}
$datarray = array();
- $datarray['start'] = $start;
- $datarray['finish'] = $finish;
+ $datarray['dtstart'] = $start;
+ $datarray['dtend'] = $finish;
$datarray['summary'] = $summary;
$datarray['description'] = $desc;
$datarray['location'] = $location;
- $datarray['type'] = $type;
+ $datarray['etype'] = $type;
$datarray['adjust'] = $adjust;
$datarray['nofinish'] = $nofinish;
$datarray['uid'] = local_channel();
@@ -232,7 +232,7 @@ class Events extends \Zotlabs\Web\Controller {
}
if($share)
- proc_run('php',"include/notifier.php","event","$item_id");
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','event',$item_id));
}
@@ -269,14 +269,14 @@ class Events extends \Zotlabs\Web\Controller {
nav_set_selected('all_events');
if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
- $r = q("update event set ignore = 1 where id = %d and uid = %d",
+ $r = q("update event set dismissed = 1 where id = %d and uid = %d",
intval(argv(2)),
intval(local_channel())
);
}
if((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) {
- $r = q("update event set ignore = 0 where id = %d and uid = %d",
+ $r = q("update event set dismissed = 0 where id = %d and uid = %d",
intval(argv(2)),
intval(local_channel())
);
@@ -301,7 +301,7 @@ class Events extends \Zotlabs\Web\Controller {
$mode = 'view';
$y = 0;
$m = 0;
- $ignored = ((x($_REQUEST,'ignored')) ? " and ignored = " . intval($_REQUEST['ignored']) . " " : '');
+ $ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
// logger('args: ' . print_r(\App::$argv,true));
@@ -358,9 +358,9 @@ class Events extends \Zotlabs\Web\Controller {
if(x($_REQUEST,'summary')) $orig_event['summary'] = $_REQUEST['summary'];
if(x($_REQUEST,'description')) $orig_event['description'] = $_REQUEST['description'];
if(x($_REQUEST,'location')) $orig_event['location'] = $_REQUEST['location'];
- if(x($_REQUEST,'start')) $orig_event['start'] = $_REQUEST['start'];
- if(x($_REQUEST,'finish')) $orig_event['finish'] = $_REQUEST['finish'];
- if(x($_REQUEST,'type')) $orig_event['type'] = $_REQUEST['type'];
+ if(x($_REQUEST,'start')) $orig_event['dtstart'] = $_REQUEST['start'];
+ if(x($_REQUEST,'finish')) $orig_event['dtend'] = $_REQUEST['finish'];
+ if(x($_REQUEST,'type')) $orig_event['etype'] = $_REQUEST['type'];
*/
$n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : '');
@@ -380,9 +380,9 @@ class Events extends \Zotlabs\Web\Controller {
if($orig_event['event_xchan'])
$sh_checked .= ' disabled="disabled" ';
- $sdt = ((x($orig_event)) ? $orig_event['start'] : 'now');
+ $sdt = ((x($orig_event)) ? $orig_event['dtstart'] : 'now');
- $fdt = ((x($orig_event)) ? $orig_event['finish'] : '+1 hour');
+ $fdt = ((x($orig_event)) ? $orig_event['dtend'] : '+1 hour');
$tz = date_default_timezone_get();
if(x($orig_event))
@@ -406,7 +406,7 @@ class Events extends \Zotlabs\Web\Controller {
$ftext = datetime_convert('UTC',$tz,$fdt);
$ftext = substr($ftext,0,14) . "00:00";
- $type = ((x($orig_event)) ? $orig_event['type'] : 'event');
+ $type = ((x($orig_event)) ? $orig_event['etype'] : 'event');
$f = get_config('system','event_input_format');
if(! $f)
@@ -536,8 +536,8 @@ class Events extends \Zotlabs\Web\Controller {
);
} elseif($export) {
$r = q("SELECT * from event where uid = %d
- AND (( `adjust` = 0 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' )
- OR ( `adjust` = 1 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' )) ",
+ AND (( `adjust` = 0 AND ( `dtend` >= '%s' or nofinish = 1 ) AND `dtstart` <= '%s' )
+ OR ( `adjust` = 1 AND ( `dtend` >= '%s' or nofinish = 1 ) AND `dtstart` <= '%s' )) ",
intval(local_channel()),
dbesc($start),
dbesc($finish),
@@ -554,8 +554,8 @@ class Events extends \Zotlabs\Web\Controller {
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
from event left join item on event_hash = resource_id
where resource_type = 'event' and event.uid = %d $ignored
- AND (( adjust = 0 AND ( finish >= '%s' or nofinish = 1 ) AND start <= '%s' )
- OR ( adjust = 1 AND ( finish >= '%s' or nofinish = 1 ) AND start <= '%s' )) ",
+ AND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )
+ OR ( adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) ",
intval(local_channel()),
dbesc($start),
dbesc($finish),
@@ -576,7 +576,7 @@ class Events extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $rr) {
- $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
+ $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
if(! x($links,$j))
$links[$j] = z_root() . '/' . \App::$cmd . '#link-' . $j;
}
@@ -591,15 +591,15 @@ class Events extends \Zotlabs\Web\Controller {
foreach($r as $rr) {
- $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j'));
- $d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], $fmt) : datetime_convert('UTC','UTC',$rr['start'],$fmt));
+ $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
+ $d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
$d = day_translate($d);
- $start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'c') : datetime_convert('UTC','UTC',$rr['start'],'c'));
+ $start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
if ($rr['nofinish']){
$end = null;
} else {
- $end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['finish'], 'c') : datetime_convert('UTC','UTC',$rr['finish'],'c'));
+ $end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
}
diff --git a/Zotlabs/Module/Fbrowser.php b/Zotlabs/Module/Fbrowser.php
index eef3cb67d..c534e8f72 100644
--- a/Zotlabs/Module/Fbrowser.php
+++ b/Zotlabs/Module/Fbrowser.php
@@ -45,10 +45,10 @@ class Fbrowser extends \Zotlabs\Web\Controller {
$album = hex2bin(\App::$argv[2]);
$sql_extra = sprintf("AND `album` = '%s' ",dbesc($album));
$sql_extra2 = "";
- $path[]=array(z_root()."/fbrowser/image/".\App::$argv[2]."/", $album);
+ $path[]=array(z_root() . "/fbrowser/image/" . \App::$argv[2] . "/", $album);
}
- $r = q("SELECT `resource_id`, `id`, `filename`, type, min(`scale`) AS `hiq`,max(`scale`) AS `loq`, `description`
+ $r = q("SELECT `resource_id`, `id`, `filename`, type, min(`imgscale`) AS `hiq`,max(`imgscale`) AS `loq`, `description`
FROM `photo` WHERE `uid` = %d $sql_extra
GROUP BY `resource_id` $sql_extra2",
intval(local_channel())
diff --git a/Zotlabs/Module/Feed.php b/Zotlabs/Module/Feed.php
index 9d33ba2c3..47871eafb 100644
--- a/Zotlabs/Module/Feed.php
+++ b/Zotlabs/Module/Feed.php
@@ -31,7 +31,7 @@ class Feed extends \Zotlabs\Web\Controller {
$channel = $r[0];
- if((intval(get_config('system','block_public'))) && (! get_account_id()))
+ if(observer_prohibited(true))
killme();
logger('mod_feed: public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
diff --git a/Zotlabs/Module/Filer.php b/Zotlabs/Module/Filer.php
index 607d088db..6a57cdb2a 100644
--- a/Zotlabs/Module/Filer.php
+++ b/Zotlabs/Module/Filer.php
@@ -39,7 +39,7 @@ class Filer extends \Zotlabs\Web\Controller {
}
else {
$filetags = array();
- $r = q("select distinct(term) from term where uid = %d and type = %d order by term asc",
+ $r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
intval(local_channel()),
intval(TERM_FILE)
);
diff --git a/Zotlabs/Module/Filerm.php b/Zotlabs/Module/Filerm.php
index eb9a42c1e..cbf6a118d 100644
--- a/Zotlabs/Module/Filerm.php
+++ b/Zotlabs/Module/Filerm.php
@@ -22,7 +22,7 @@ class Filerm extends \Zotlabs\Web\Controller {
logger('filerm: tag ' . $term . ' item ' . $item_id);
if($item_id && strlen($term)) {
- $r = q("delete from term where uid = %d and type = %d and oid = %d and term = '%s'",
+ $r = q("delete from term where uid = %d and ttype = %d and oid = %d and term = '%s'",
intval(local_channel()),
intval(($category) ? TERM_CATEGORY : TERM_FILE),
intval($item_id),
diff --git a/Zotlabs/Module/Follow.php b/Zotlabs/Module/Follow.php
index 1701328bf..1df382a89 100644
--- a/Zotlabs/Module/Follow.php
+++ b/Zotlabs/Module/Follow.php
@@ -53,14 +53,13 @@ class Follow extends \Zotlabs\Web\Controller {
// If we can view their stream, pull in some posts
if(($result['abook']['abook_their_perms'] & PERMS_R_STREAM) || ($result['abook']['xchan_network'] === 'rss'))
- proc_run('php','include/onepoll.php',$result['abook']['abook_id']);
+ \Zotlabs\Daemon\Master::Summon(array('Onepoll',$result['abook']['abook_id']));
goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1');
}
- function get() {
-
+ function get() {
if(! local_channel()) {
return login();
}
diff --git a/Zotlabs/Module/Fsuggest.php b/Zotlabs/Module/Fsuggest.php
deleted file mode 100644
index 143fd34e1..000000000
--- a/Zotlabs/Module/Fsuggest.php
+++ /dev/null
@@ -1,117 +0,0 @@
-' . t('Suggest Friends') . '';
-
- $o .= '' . sprintf( t('Suggest a friend for %s'), $contact['name']) . '
';
-
- $o .= '';
-
- return $o;
- }
-}
diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php
index 6999e77e8..09d761887 100644
--- a/Zotlabs/Module/Getfile.php
+++ b/Zotlabs/Module/Getfile.php
@@ -21,7 +21,6 @@ namespace Zotlabs\Module;
-require_once('include/Contact.php');
require_once('include/attach.php');
diff --git a/Zotlabs/Module/Group.php b/Zotlabs/Module/Group.php
index 144797baf..254ee6ef2 100644
--- a/Zotlabs/Module/Group.php
+++ b/Zotlabs/Module/Group.php
@@ -47,8 +47,8 @@ class Group extends \Zotlabs\Web\Controller {
$groupname = notags(trim($_POST['groupname']));
$public = intval($_POST['public']);
- if((strlen($groupname)) && (($groupname != $group['name']) || ($public != $group['visible']))) {
- $r = q("UPDATE `groups` SET `name` = '%s', visible = %d WHERE `uid` = %d AND `id` = %d",
+ if((strlen($groupname)) && (($groupname != $group['gname']) || ($public != $group['visible']))) {
+ $r = q("UPDATE `groups` SET `gname` = '%s', visible = %d WHERE `uid` = %d AND `id` = %d",
dbesc($groupname),
intval($public),
intval(local_channel()),
@@ -106,7 +106,7 @@ class Group extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if($r)
- $result = group_rmv(local_channel(),$r[0]['name']);
+ $result = group_rmv(local_channel(),$r[0]['gname']);
if($result)
info( t('Privacy group removed.') . EOL);
else
@@ -156,10 +156,10 @@ class Group extends \Zotlabs\Web\Controller {
if($change) {
if(in_array($change,$preselected)) {
- group_rmv_member(local_channel(),$group['name'],$change);
+ group_rmv_member(local_channel(),$group['gname'],$change);
}
else {
- group_add_member(local_channel(),$group['name'],$change);
+ group_add_member(local_channel(),$group['gname'],$change);
}
$members = group_get_members($group['id']);
@@ -181,7 +181,7 @@ class Group extends \Zotlabs\Web\Controller {
$context = $context + array(
'$title' => t('Privacy group editor'),
- '$gname' => array('groupname',t('Privacy group name: '),$group['name'], ''),
+ '$gname' => array('groupname',t('Privacy group name: '),$group['gname'], ''),
'$gid' => $group['id'],
'$drop' => $drop_txt,
'$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''),
@@ -209,7 +209,7 @@ class Group extends \Zotlabs\Web\Controller {
$groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode);
}
else
- group_rmv_member(local_channel(),$group['name'],$member['xchan_hash']);
+ group_rmv_member(local_channel(),$group['gname'],$member['xchan_hash']);
}
$r = q("SELECT abook.*, xchan.* FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE `abook_channel` = %d AND abook_self = 0 and abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc",
diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php
index 4842c56c6..cc46c550b 100644
--- a/Zotlabs/Module/Help.php
+++ b/Zotlabs/Module/Help.php
@@ -37,7 +37,7 @@ class Help extends \Zotlabs\Web\Controller {
$path = trim(substr($dirname,4),'/');
$o .= '' . ucwords(str_replace('_',' ',notags($fname))) . ' ' .
- str_replace('$Projectname',\Zotlabs\Project\System::get_platform_name(),substr($rr['text'],0,200)) . '... ';
+ str_replace('$Projectname',\Zotlabs\Lib\System::get_platform_name(),substr($rr['text'],0,200)) . '... ';
}
$o .= '';
diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php
index dadbf8ff1..122e27e90 100644
--- a/Zotlabs/Module/Import.php
+++ b/Zotlabs/Module/Import.php
@@ -4,9 +4,9 @@ namespace Zotlabs\Module;
// Import a channel, either by direct file upload or via
// connection to original server.
-require_once('include/Contact.php');
+
require_once('include/zot.php');
-require_once('include/identity.php');
+require_once('include/channel.php');
require_once('include/import.php');
@@ -408,8 +408,12 @@ class Import extends \Zotlabs\Web\Controller {
$saved = array();
foreach($groups as $group) {
$saved[$group['hash']] = array('old' => $group['id']);
+ if(array_key_exists('name',$group)) {
+ $group['gname'] = $group['name'];
+ unset($group['name']);
+ }
unset($group['id']);
- $group['uid'] = $channel['channel_id'];
+ $group['uid'] = $channel['channel_id'];
dbesc_array($group);
$r = dbq("INSERT INTO groups (`"
. implode("`, `", array_keys($group))
@@ -496,11 +500,11 @@ class Import extends \Zotlabs\Web\Controller {
// send out refresh requests
// notify old server that it may no longer be primary.
- proc_run('php','include/notifier.php','location',$channel['channel_id']);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
// This will indirectly perform a refresh_all *and* update the directory
- proc_run('php', 'include/directory.php', $channel['channel_id']);
+ \Zotlabs\Daemon\Master::Summon(array('Directory', $channel['channel_id']));
notice( t('Import completed.') . EOL);
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index 93570fdec..2601feb0a 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -17,10 +17,10 @@ namespace Zotlabs\Module;
*/
require_once('include/crypto.php');
-require_once('include/enotify.php');
require_once('include/items.php');
require_once('include/attach.php');
+use \Zotlabs\Lib as Zlib;
class Item extends \Zotlabs\Web\Controller {
@@ -56,7 +56,7 @@ class Item extends \Zotlabs\Web\Controller {
$remote_xchan = $remote_observer = false;
$profile_uid = ((x($_REQUEST,'profile_uid')) ? intval($_REQUEST['profile_uid']) : 0);
- require_once('include/identity.php');
+ require_once('include/channel.php');
$sys = get_sys_channel();
if($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin()) {
$uid = intval($sys['channel_id']);
@@ -581,7 +581,7 @@ class Item extends \Zotlabs\Web\Controller {
if($success['replaced']) {
$post_tags[] = array(
'uid' => $profile_uid,
- 'type' => $success['termtype'],
+ 'ttype' => $success['termtype'],
'otype' => TERM_OBJ_POST,
'term' => $success['term'],
'url' => $success['url']
@@ -666,7 +666,7 @@ class Item extends \Zotlabs\Web\Controller {
foreach($cats as $cat) {
$post_tags[] = array(
'uid' => $profile_uid,
- 'type' => TERM_CATEGORY,
+ 'ttype' => TERM_CATEGORY,
'otype' => TERM_OBJ_POST,
'term' => trim($cat),
'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
@@ -676,7 +676,7 @@ class Item extends \Zotlabs\Web\Controller {
if($orig_post) {
// preserve original tags
- $t = q("select * from term where oid = %d and otype = %d and uid = %d and type in ( %d, %d, %d )",
+ $t = q("select * from term where oid = %d and otype = %d and uid = %d and ttype in ( %d, %d, %d )",
intval($orig_post['id']),
intval(TERM_OBJ_POST),
intval($profile_uid),
@@ -688,7 +688,7 @@ class Item extends \Zotlabs\Web\Controller {
foreach($t as $t1) {
$post_tags[] = array(
'uid' => $profile_uid,
- 'type' => $t1['type'],
+ 'ttype' => $t1['type'],
'otype' => TERM_OBJ_POST,
'term' => $t1['term'],
'url' => $t1['url'],
@@ -901,7 +901,7 @@ class Item extends \Zotlabs\Web\Controller {
}
}
if(! $nopush)
- proc_run('php', "include/notifier.php", 'edit_post', $post_id);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier', 'edit_post', $post_id));
if((x($_REQUEST,'return')) && strlen($return_path)) {
logger('return: ' . $return_path);
@@ -925,7 +925,7 @@ class Item extends \Zotlabs\Web\Controller {
// otherwise it will happen during delivery
if(($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall']))) {
- notification(array(
+ Zlib\Enotify::submit(array(
'type' => NOTIFY_COMMENT,
'from_xchan' => $datarray['author_xchan'],
'to_xchan' => $datarray['owner_xchan'],
@@ -943,7 +943,7 @@ class Item extends \Zotlabs\Web\Controller {
$parent = $post_id;
if(($datarray['owner_xchan'] != $datarray['author_xchan']) && ($datarray['item_type'] == ITEM_TYPE_POST)) {
- notification(array(
+ Zlib\Enotify::submit(array(
'type' => NOTIFY_WALL,
'from_xchan' => $datarray['author_xchan'],
'to_xchan' => $datarray['owner_xchan'],
@@ -1008,7 +1008,7 @@ class Item extends \Zotlabs\Web\Controller {
call_hooks('post_local_end', $datarray);
if(! $nopush)
- proc_run('php', 'include/notifier.php', $notify_type, $post_id);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier', $notify_type, $post_id));
logger('post_complete');
diff --git a/Zotlabs/Module/Layouts.php b/Zotlabs/Module/Layouts.php
index 8a7207fc2..9b9fc22f3 100644
--- a/Zotlabs/Module/Layouts.php
+++ b/Zotlabs/Module/Layouts.php
@@ -1,7 +1,7 @@
' . $rr['name'] . ' ';
+ $l[] = '' . $rr['gname'] . ' ';
}
if(count($allowed_users)) {
$r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )");
@@ -100,10 +100,10 @@ class Lockview extends \Zotlabs\Web\Controller {
$l[] = '' . $rr['xchan_name'] . ' ';
}
if(count($deny_groups)) {
- $r = q("SELECT name FROM `groups` WHERE hash IN ( " . implode(', ', $deny_groups) . " )");
+ $r = q("SELECT gname FROM `groups` WHERE hash IN ( " . implode(', ', $deny_groups) . " )");
if($r)
foreach($r as $rr)
- $l[] = '' . $rr['name'] . ' ';
+ $l[] = '' . $rr['gname'] . ' ';
}
if(count($deny_users)) {
$r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )");
diff --git a/Zotlabs/Module/Locs.php b/Zotlabs/Module/Locs.php
index 4b5d58df5..4b1e3ffe2 100644
--- a/Zotlabs/Module/Locs.php
+++ b/Zotlabs/Module/Locs.php
@@ -34,7 +34,7 @@ class Locs extends \Zotlabs\Web\Controller {
dbesc($channel['channel_hash'])
);
- proc_run('php','include/notifier.php','location',$channel['channel_id']);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
return;
}
}
@@ -72,7 +72,7 @@ class Locs extends \Zotlabs\Web\Controller {
intval($hubloc_id),
dbesc($channel['channel_hash'])
);
- proc_run('php','include/notifier.php','location',$channel['channel_id']);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
return;
}
}
@@ -91,7 +91,7 @@ class Locs extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
if($_REQUEST['sync']) {
- proc_run('php','include/notifier.php','location',$channel['channel_id']);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','location',$channel['channel_id']));
info( t('Syncing locations') . EOL);
goaway(z_root() . '/locs');
}
diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php
index 63db4a317..6798f72a9 100644
--- a/Zotlabs/Module/Magic.php
+++ b/Zotlabs/Module/Magic.php
@@ -47,11 +47,9 @@ class Magic extends \Zotlabs\Web\Controller {
*
*/
- $ret = zot_finger((($addr) ? $addr : '[system]@' . $parsed['host']),null);
- if($ret['success']) {
- $j = json_decode($ret['body'],true);
- if($j)
- import_xchan($j);
+ $j = \Zotlabs\Zot\Finger::run((($addr) ? $addr : '[system]@' . $parsed['host']),null);
+ if($j['success']) {
+ import_xchan($j);
// Now try again
diff --git a/Zotlabs/Module/Mail.php b/Zotlabs/Module/Mail.php
index 35cb3b9bf..aae7585c4 100644
--- a/Zotlabs/Module/Mail.php
+++ b/Zotlabs/Module/Mail.php
@@ -5,7 +5,7 @@ require_once('include/acl_selectors.php');
require_once('include/message.php');
require_once('include/zot.php');
require_once("include/bbcode.php");
-require_once('include/Contact.php');
+
@@ -32,17 +32,16 @@ class Mail extends \Zotlabs\Web\Controller {
if(! $recipient) {
$channel = \App::get_channel();
- $ret = zot_finger($rstr,$channel);
+ $j = \Zotlabs\Zot\Finger::run($rstr,$channel);
- if(! $ret['success']) {
+ if(! $j['success']) {
notice( t('Unable to lookup recipient.') . EOL);
return;
}
- $j = json_decode($ret['body'],true);
logger('message_post: lookup: ' . $url . ' ' . print_r($j,true));
- if(! ($j['success'] && $j['guid'])) {
+ if(! $j['guid']) {
notice( t('Unable to communicate with requested channel.'));
return;
}
@@ -173,7 +172,7 @@ class Mail extends \Zotlabs\Web\Controller {
build_sync_packet(local_channel(),array('mail' => encode_mail($x[0],true)));
}
- proc_run('php','include/notifier.php','mail',intval(argv(3)));
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','mail',intval(argv(3))));
if($r) {
info( t('Message recalled.') . EOL );
@@ -306,11 +305,6 @@ class Mail extends \Zotlabs\Web\Controller {
else
\App::$poi = $messages[0]['to'];
- // require_once('include/Contact.php');
-
- // \App::set_widget('mail_conversant',vcard_from_xchan(\App::$poi,$get_observer_hash,'mail'));
-
-
$tpl = get_markup_template('msg-header.tpl');
\App::$page['htmlhead'] .= replace_macros($tpl, array(
diff --git a/Zotlabs/Module/Manage.php b/Zotlabs/Module/Manage.php
index 5ae79dbb2..4ca044c4a 100644
--- a/Zotlabs/Module/Manage.php
+++ b/Zotlabs/Module/Manage.php
@@ -93,9 +93,9 @@ class Manage extends \Zotlabs\Web\Controller {
$channels[$x]['mail'] = intval($mails[0]['total']);
- $events = q("SELECT type, start, adjust FROM `event`
- WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0
- ORDER BY `start` ASC ",
+ $events = q("SELECT etype, dtstart, adjust FROM `event`
+ WHERE `event`.`uid` = %d AND dtstart < '%s' AND dtstart > '%s' and `dismissed` = 0
+ ORDER BY `dtstart` ASC ",
intval($channels[$x]['channel_id']),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
@@ -108,14 +108,14 @@ class Manage extends \Zotlabs\Web\Controller {
$str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d');
foreach($events as $e) {
$bd = false;
- if($e['type'] === 'birthday') {
+ if($e['etype'] === 'birthday') {
$channels[$x]['birthdays'] ++;
$bd = true;
}
else {
$channels[$x]['events'] ++;
}
- if(datetime_convert('UTC', ((intval($e['adjust'])) ? date_default_timezone_get() : 'UTC'), $e['start'], 'Y-m-d') === $str_now) {
+ if(datetime_convert('UTC', ((intval($e['adjust'])) ? date_default_timezone_get() : 'UTC'), $e['dtstart'], 'Y-m-d') === $str_now) {
$channels[$x]['all_events_today'] ++;
if($bd)
$channels[$x]['birthdays_today'] ++;
diff --git a/Zotlabs/Module/Menu.php b/Zotlabs/Module/Menu.php
index 9ada63911..e98053f8c 100644
--- a/Zotlabs/Module/Menu.php
+++ b/Zotlabs/Module/Menu.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
require_once('include/menu.php');
-require_once('include/identity.php');
+require_once('include/channel.php');
class Menu extends \Zotlabs\Web\Controller {
diff --git a/Zotlabs/Module/Message.php b/Zotlabs/Module/Message.php
index 58a138899..ea2127a1d 100644
--- a/Zotlabs/Module/Message.php
+++ b/Zotlabs/Module/Message.php
@@ -5,8 +5,6 @@ require_once('include/acl_selectors.php');
require_once('include/message.php');
require_once('include/zot.php');
require_once("include/bbcode.php");
-require_once('include/Contact.php');
-
class Message extends \Zotlabs\Web\Controller {
diff --git a/Zotlabs/Module/Mood.php b/Zotlabs/Module/Mood.php
index b1007fd06..d1bd44526 100644
--- a/Zotlabs/Module/Mood.php
+++ b/Zotlabs/Module/Mood.php
@@ -97,7 +97,7 @@ class Mood extends \Zotlabs\Web\Controller {
$item_id = $post['item_id'];
if($item_id) {
- proc_run('php',"include/notifier.php","activity", $item_id);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','activity', $item_id));
}
call_hooks('post_local_end', $arr);
diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php
index c88258a78..87ed326e2 100644
--- a/Zotlabs/Module/Network.php
+++ b/Zotlabs/Module/Network.php
@@ -223,7 +223,7 @@ class Network extends \Zotlabs\Web\Controller {
if($x) {
$title = replace_macros(get_markup_template("section_title.tpl"),array(
- '$title' => t('Privacy group: ') . $x['name']
+ '$title' => t('Privacy group: ') . $x['gname']
));
}
@@ -385,7 +385,7 @@ class Network extends \Zotlabs\Web\Controller {
$abook_uids = " and abook.abook_channel = " . local_channel() . " ";
if($firehose && (! get_config('system','disable_discover_tab'))) {
- require_once('include/identity.php');
+ require_once('include/channel.php');
$sys = get_sys_channel();
$uids = " and item.uid = " . intval($sys['channel_id']) . " ";
\App::$data['firehose'] = intval($sys['channel_id']);
diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php
index 3dca1b0b4..30d7c83c6 100644
--- a/Zotlabs/Module/New_channel.php
+++ b/Zotlabs/Module/New_channel.php
@@ -1,7 +1,7 @@
0) {
+ if ($r > 0) {
$notifications_available =1;
foreach ($r as $it) {
$notif_content .= replace_macros($not_tpl,array(
'$item_link' => z_root().'/notify/view/'. $it['id'],
'$item_image' => $it['photo'],
'$item_text' => strip_tags(bbcode($it['msg'])),
- '$item_when' => relative_date($it['date'])
+ '$item_when' => relative_date($it['created'])
));
}
} else {
diff --git a/Zotlabs/Module/Notify.php b/Zotlabs/Module/Notify.php
index 227491145..f592f6f37 100644
--- a/Zotlabs/Module/Notify.php
+++ b/Zotlabs/Module/Notify.php
@@ -39,7 +39,7 @@ class Notify extends \Zotlabs\Web\Controller {
$not_tpl = get_markup_template('notify.tpl');
require_once('include/bbcode.php');
- $r = q("SELECT * from notify where uid = %d and seen = 0 order by date desc",
+ $r = q("SELECT * from notify where uid = %d and seen = 0 order by created desc",
intval(local_channel())
);
@@ -49,7 +49,7 @@ class Notify extends \Zotlabs\Web\Controller {
'$item_link' => z_root().'/notify/view/'. $it['id'],
'$item_image' => $it['photo'],
'$item_text' => strip_tags(bbcode($it['msg'])),
- '$item_when' => relative_date($it['date'])
+ '$item_when' => relative_date($it['created'])
));
}
}
diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php
index 638ea7e2d..dc0547a42 100644
--- a/Zotlabs/Module/Oep.php
+++ b/Zotlabs/Module/Oep.php
@@ -181,8 +181,8 @@ class Oep extends \Zotlabs\Web\Controller {
function oep_profile_reply($args) {
- require_once('include/identity.php');
- require_once('include/Contact.php');
+ require_once('include/channel.php');
+
$url = $args['url'];
if(preg_match('#//(.*?)/(.*?)/(.*?)(/|\?|&|$)#',$url,$matches)) {
@@ -249,7 +249,7 @@ class Oep extends \Zotlabs\Web\Controller {
$sql_extra = permissions_sql($c[0]['channel_id']);
- $p = q("select resource_id from photo where album = '%s' and uid = %d and scale = 0 $sql_extra order by created desc limit 1",
+ $p = q("select resource_id from photo where album = '%s' and uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
dbesc($res),
intval($c[0]['channel_id'])
);
@@ -258,7 +258,7 @@ class Oep extends \Zotlabs\Web\Controller {
$res = $p[0]['resource_id'];
- $r = q("select height, width, scale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by scale asc",
+ $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc",
intval($c[0]['channel_id']),
dbesc($res)
);
@@ -276,7 +276,7 @@ class Oep extends \Zotlabs\Web\Controller {
if($foundres) {
$ret['type'] = 'link';
- $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['scale'];
+ $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale'];
$ret['thumbnail_width'] = $rr['width'];
$ret['thumbnail_height'] = $rr['height'];
}
@@ -310,7 +310,7 @@ class Oep extends \Zotlabs\Web\Controller {
$sql_extra = permissions_sql($c[0]['channel_id']);
- $p = q("select resource_id from photo where uid = %d and scale = 0 $sql_extra order by created desc limit 1",
+ $p = q("select resource_id from photo where uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
intval($c[0]['channel_id'])
);
if(! $p)
@@ -318,7 +318,7 @@ class Oep extends \Zotlabs\Web\Controller {
$res = $p[0]['resource_id'];
- $r = q("select height, width, scale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by scale asc",
+ $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc",
intval($c[0]['channel_id']),
dbesc($res)
);
@@ -336,7 +336,7 @@ class Oep extends \Zotlabs\Web\Controller {
if($foundres) {
$ret['type'] = 'link';
- $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['scale'];
+ $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale'];
$ret['thumbnail_width'] = $rr['width'];
$ret['thumbnail_height'] = $rr['height'];
}
@@ -372,7 +372,7 @@ class Oep extends \Zotlabs\Web\Controller {
$sql_extra = permissions_sql($c[0]['channel_id']);
- $r = q("select height, width, scale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by scale asc",
+ $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc",
intval($c[0]['channel_id']),
dbesc($res)
);
@@ -390,7 +390,7 @@ class Oep extends \Zotlabs\Web\Controller {
if($foundres) {
$ret['type'] = 'link';
- $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['scale'];
+ $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale'];
$ret['thumbnail_width'] = $rr['width'];
$ret['thumbnail_height'] = $rr['height'];
}
diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php
index 408688886..92c9ac3c0 100644
--- a/Zotlabs/Module/Photo.php
+++ b/Zotlabs/Module/Photo.php
@@ -57,14 +57,14 @@ class Photo extends \Zotlabs\Web\Controller {
$uid = $person;
- $r = q("SELECT * FROM photo WHERE scale = %d AND uid = %d AND photo_usage = %d LIMIT 1",
+ $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1",
intval($resolution),
intval($uid),
intval(PHOTO_PROFILE)
);
if(count($r)) {
- $data = dbunescbin($r[0]['data']);
- $mimetype = $r[0]['type'];
+ $data = dbunescbin($r[0]['content']);
+ $mimetype = $r[0]['mimetype'];
}
if(intval($r[0]['os_storage']))
$data = file_get_contents($data);
@@ -113,7 +113,7 @@ class Photo extends \Zotlabs\Web\Controller {
// If using resolution 1, make sure it exists before proceeding:
if ($resolution == 1)
{
- $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND scale = %d LIMIT 1",
+ $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo),
intval($resolution)
);
@@ -121,7 +121,7 @@ class Photo extends \Zotlabs\Web\Controller {
$resolution = 2;
}
- $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND scale = %d LIMIT 1",
+ $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo),
intval($resolution)
);
@@ -133,14 +133,14 @@ class Photo extends \Zotlabs\Web\Controller {
// Now we'll see if we can access the photo
- $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND scale = %d $sql_extra LIMIT 1",
+ $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d $sql_extra LIMIT 1",
dbesc($photo),
intval($resolution)
);
if($r && $allowed) {
- $data = dbunescbin($r[0]['data']);
- $mimetype = $r[0]['type'];
+ $data = dbunescbin($r[0]['content']);
+ $mimetype = $r[0]['mimetype'];
if(intval($r[0]['os_storage']))
$data = file_get_contents($data);
}
@@ -154,7 +154,7 @@ class Photo extends \Zotlabs\Web\Controller {
// they won't have the photo link, so there's a reasonable chance that the person
// might be able to obtain permission to view it.
- $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `scale` = %d LIMIT 1",
+ $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `imgscale` = %d LIMIT 1",
dbesc($photo),
intval($resolution)
);
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 1659350a5..1bdc23897 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -1,12 +1,12 @@
is_valid()) {
$rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 );
$ph->rotate($rotate_deg);
@@ -270,9 +270,9 @@ class Photos extends \Zotlabs\Web\Controller {
$height = $ph->getHeight();
if(intval($r[0]['os_storage'])) {
- @file_put_contents($r[0]['data'],$ph->imageString());
- $data = $r[0]['data'];
- $fsize = @filesize($r[0]['data']);
+ @file_put_contents($r[0]['content'],$ph->imageString());
+ $data = $r[0]['content'];
+ $fsize = @filesize($r[0]['content']);
q("update attach set filesize = %d where hash = '%s' and uid = %d limit 1",
intval($fsize),
dbesc($resource_id),
@@ -284,7 +284,7 @@ class Photos extends \Zotlabs\Web\Controller {
$fsize = strlen($data);
}
- $x = q("update photo set data = '%s', `size` = %d, height = %d, width = %d where `resource_id` = '%s' and uid = %d and scale = 0",
+ $x = q("update photo set content = '%s', filesize = %d, height = %d, width = %d where `resource_id` = '%s' and uid = %d and imgscale = 0",
dbescbin($data),
intval($fsize),
intval($height),
@@ -299,7 +299,7 @@ class Photos extends \Zotlabs\Web\Controller {
$width = $ph->getWidth();
$height = $ph->getHeight();
- $x = q("update photo set data = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and scale = 1",
+ $x = q("update photo set content = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and imgscale = 1",
dbescbin($ph->imageString()),
intval($height),
intval($width),
@@ -314,7 +314,7 @@ class Photos extends \Zotlabs\Web\Controller {
$width = $ph->getWidth();
$height = $ph->getHeight();
- $x = q("update photo set data = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and scale = 2",
+ $x = q("update photo set content = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and imgscale = 2",
dbescbin($ph->imageString()),
intval($height),
intval($width),
@@ -329,7 +329,7 @@ class Photos extends \Zotlabs\Web\Controller {
$width = $ph->getWidth();
$height = $ph->getHeight();
- $x = q("update photo set data = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and scale = 3",
+ $x = q("update photo set content = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and imgscale = 3",
dbescbin($ph->imageString()),
intval($height),
intval($width),
@@ -340,12 +340,12 @@ class Photos extends \Zotlabs\Web\Controller {
}
}
- $p = q("SELECT type, is_nsfw, description, resource_id, scale, allow_cid, allow_gid, deny_cid, deny_gid FROM photo WHERE resource_id = '%s' AND uid = %d ORDER BY scale DESC",
+ $p = q("SELECT mimetype, is_nsfw, description, resource_id, imgscale, allow_cid, allow_gid, deny_cid, deny_gid FROM photo WHERE resource_id = '%s' AND uid = %d ORDER BY imgscale DESC",
dbesc($resource_id),
intval($page_owner_uid)
);
if($p) {
- $ext = $phototypes[$p[0]['type']];
+ $ext = $phototypes[$p[0]['mimetype']];
$r = q("UPDATE `photo` SET `description` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s' WHERE `resource_id` = '%s' AND `uid` = %d",
dbesc($desc),
@@ -440,7 +440,7 @@ class Photos extends \Zotlabs\Web\Controller {
if($success['replaced']) {
$post_tags[] = array(
'uid' => $profile_uid,
- 'type' => $success['termtype'],
+ 'ttype' => $success['termtype'],
'otype' => TERM_OBJ_POST,
'term' => $success['term'],
'url' => $success['url']
@@ -510,7 +510,7 @@ class Photos extends \Zotlabs\Web\Controller {
- function get() {
+ function get() {
// URLs:
// photos/name
@@ -518,7 +518,7 @@ class Photos extends \Zotlabs\Web\Controller {
// photos/name/image/xxxxx
- if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
@@ -611,7 +611,7 @@ class Photos extends \Zotlabs\Web\Controller {
/* Show space usage */
- $r = q("select sum(size) as total from photo where aid = %d and scale = 0 ",
+ $r = q("select sum(filesize) as total from photo where aid = %d and imgscale = 0 ",
intval(\App::$data['channel']['channel_account_id'])
);
@@ -704,8 +704,8 @@ class Photos extends \Zotlabs\Web\Controller {
\App::$page['htmlhead'] .= "\r\n" . ' ' . "\r\n";
- $r = q("SELECT `resource_id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` = '%s'
- AND `scale` <= 4 and photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY `resource_id`",
+ $r = q("SELECT `resource_id`, max(`imgscale`) AS `imgscale` FROM `photo` WHERE `uid` = %d AND `album` = '%s'
+ AND `imgscale` <= 4 and photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY `resource_id`",
intval($owner_uid),
dbesc($album),
intval(PHOTO_NORMAL),
@@ -725,9 +725,9 @@ class Photos extends \Zotlabs\Web\Controller {
$order = 'DESC';
- $r = q("SELECT p.resource_id, p.id, p.filename, p.type, p.scale, p.description, p.created FROM photo p INNER JOIN
- (SELECT resource_id, max(scale) scale FROM photo WHERE uid = %d AND album = '%s' AND scale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph
- ON (p.resource_id = ph.resource_id AND p.scale = ph.scale)
+ $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN
+ (SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph
+ ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)
ORDER BY created $order LIMIT %d OFFSET %d",
intval($owner_uid),
dbesc($album),
@@ -777,7 +777,7 @@ class Photos extends \Zotlabs\Web\Controller {
else
$twist = 'rotright';
- $ext = $phototypes[$rr['type']];
+ $ext = $phototypes[$rr['mimetype']];
$imgalt_e = $rr['filename'];
$desc_e = $rr['description'];
@@ -790,7 +790,7 @@ class Photos extends \Zotlabs\Web\Controller {
'twist' => ' ' . $twist . rand(2,4),
'link' => $imagelink,
'title' => t('View Photo'),
- 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['scale'] . '.' .$ext,
+ 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext,
'alt' => $imgalt_e,
'desc'=> $desc_e,
'ext' => $ext,
@@ -852,8 +852,8 @@ class Photos extends \Zotlabs\Web\Controller {
// fetch image, item containing image, then comments
- $ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,`description`,album,filename,`type`,height,width,`size`,scale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s'
- $sql_extra ORDER BY `scale` ASC ",
+ $ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,`description`,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s'
+ $sql_extra ORDER BY `imgscale` ASC ",
intval($owner_uid),
dbesc($datum)
);
@@ -884,7 +884,7 @@ class Photos extends \Zotlabs\Web\Controller {
$order = 'DESC';
- $prvnxt = q("SELECT `resource_id` FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `scale` = 0
+ $prvnxt = q("SELECT `resource_id` FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `imgscale` = 0
$sql_extra ORDER BY `created` $order ",
dbesc($ph[0]['album']),
intval($owner_uid)
@@ -911,7 +911,7 @@ class Photos extends \Zotlabs\Web\Controller {
if(count($ph) == 1)
$hires = $lores = $ph[0];
if(count($ph) > 1) {
- if($ph[1]['scale'] == 2) {
+ if($ph[1]['imgscale'] == 2) {
// original is 640 or less, we can display it directly
$hires = $lores = $ph[0];
}
@@ -949,9 +949,9 @@ class Photos extends \Zotlabs\Web\Controller {
$prevlink = array($prevlink, t('Previous'));
$photo = array(
- 'href' => z_root() . '/photo/' . $hires['resource_id'] . '-' . $hires['scale'] . '.' . $phototypes[$hires['type']],
+ 'href' => z_root() . '/photo/' . $hires['resource_id'] . '-' . $hires['imgscale'] . '.' . $phototypes[$hires['mimetype']],
'title'=> t('View Full Size'),
- 'src' => z_root() . '/photo/' . $lores['resource_id'] . '-' . $lores['scale'] . '.' . $phototypes[$lores['type']] . '?f=&_u=' . datetime_convert('','','','ymdhis')
+ 'src' => z_root() . '/photo/' . $lores['resource_id'] . '-' . $lores['imgscale'] . '.' . $phototypes[$lores['mimetype']] . '?f=&_u=' . datetime_convert('','','','ymdhis')
);
if($nextlink)
@@ -1277,28 +1277,25 @@ class Photos extends \Zotlabs\Web\Controller {
\App::$page['htmlhead'] .= "\r\n" . ' ' . "\r\n";
- $r = q("SELECT `resource_id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s'
+ $r = q("SELECT `resource_id`, max(`imgscale`) AS `imgscale` FROM `photo` WHERE `uid` = %d
and photo_usage in ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY `resource_id`",
intval(\App::$data['channel']['channel_id']),
- dbesc('Contact Photos'),
- dbesc( t('Contact Photos')),
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval($unsafe)
);
- if(count($r)) {
+ if($r) {
\App::set_pager_total(count($r));
\App::set_pager_itemspage(60);
}
- $r = q("SELECT p.resource_id, p.id, p.filename, p.type, p.album, p.scale, p.created FROM photo p INNER JOIN
- (SELECT resource_id, max(scale) scale FROM photo
- WHERE uid=%d AND album != '%s' AND album != '%s'
- AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra group by resource_id) ph
- ON (p.resource_id = ph.resource_id and p.scale = ph.scale) ORDER by p.created DESC LIMIT %d OFFSET %d",
+ $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created FROM photo p
+ INNER JOIN ( SELECT resource_id, max(imgscale) imgscale FROM photo
+ WHERE uid = %d AND photo_usage IN ( %d, %d )
+ AND is_nsfw = %d $sql_extra group by resource_id ) ph
+ ON (p.resource_id = ph.resource_id and p.imgscale = ph.imgscale)
+ ORDER by p.created DESC LIMIT %d OFFSET %d",
intval(\App::$data['channel']['channel_id']),
- dbesc('Contact Photos'),
- dbesc( t('Contact Photos')),
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE),
intval($unsafe),
@@ -1309,14 +1306,14 @@ class Photos extends \Zotlabs\Web\Controller {
$photos = array();
- if(count($r)) {
+ if($r) {
$twist = 'rotright';
foreach($r as $rr) {
if($twist == 'rotright')
$twist = 'rotleft';
else
$twist = 'rotright';
- $ext = $phototypes[$rr['type']];
+ $ext = $phototypes[$rr['mimetype']];
if(\App::get_template_engine() === 'internal') {
$alt_e = template_escape($rr['filename']);
@@ -1332,7 +1329,7 @@ class Photos extends \Zotlabs\Web\Controller {
'twist' => ' ' . $twist . rand(2,4),
'link' => z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'],
'title' => t('View Photo'),
- 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . ((($rr['scale']) == 6) ? 4 : $rr['scale']) . '.' . $ext,
+ 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . ((($rr['imgscale']) == 6) ? 4 : $rr['imgscale']) . '.' . $ext,
'alt' => $alt_e,
'album' => array(
'link' => z_root() . '/photos/' . \App::$data['channel']['channel_address'] . '/album/' . bin2hex($rr['album']),
diff --git a/Zotlabs/Module/Ping.php b/Zotlabs/Module/Ping.php
index bea4a08b7..5cbf45daa 100644
--- a/Zotlabs/Module/Ping.php
+++ b/Zotlabs/Module/Ping.php
@@ -1,12 +1,13 @@
'%s' ",
+ $r = q("update event set `dimissed` = 1 where `dismissed` = 0 and uid = %d AND dtstart < '%s' AND dtstart > '%s' ",
intval(local_channel()),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
@@ -208,17 +209,17 @@ class Ping extends \Zotlabs\Web\Controller {
);
if($t && intval($t[0]['total']) > 49) {
$z = q("select * from notify where uid = %d
- and seen = 0 order by date desc limit 50",
+ and seen = 0 order by created desc limit 50",
intval(local_channel())
);
}
else {
$z1 = q("select * from notify where uid = %d
- and seen = 0 order by date desc limit 50",
+ and seen = 0 order by created desc limit 50",
intval(local_channel())
);
$z2 = q("select * from notify where uid = %d
- and seen = 1 order by date desc limit %d",
+ and seen = 1 order by created desc limit %d",
intval(local_channel()),
intval(50 - intval($t[0]['total']))
);
@@ -229,10 +230,10 @@ class Ping extends \Zotlabs\Web\Controller {
foreach($z as $zz) {
$notifs[] = array(
'notify_link' => z_root() . '/notify/view/' . $zz['id'],
- 'name' => $zz['name'],
+ 'name' => $zz['xname'],
'url' => $zz['url'],
'photo' => $zz['photo'],
- 'when' => relative_date($zz['date']),
+ 'when' => relative_date($zz['created']),
'hclass' => (($zz['seen']) ? 'notify-seen' : 'notify-unseen'),
'message' => strip_tags(bbcode($zz['msg']))
);
@@ -285,7 +286,7 @@ class Ping extends \Zotlabs\Web\Controller {
foreach($r as $item) {
if((argv(1) === 'home') && (! intval($item['item_wall'])))
continue;
- $result[] = format_notification($item);
+ $result[] = \Zotlabs\Lib\Enotify::format($item);
}
}
// logger('ping (network||home): ' . print_r($result, true), LOGGER_DATA);
@@ -324,9 +325,9 @@ class Ping extends \Zotlabs\Web\Controller {
$result = array();
$r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash
- WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0
- and type in ( 'event', 'birthday' )
- ORDER BY `start` DESC LIMIT 1000",
+ WHERE `event`.`uid` = %d AND dtstart < '%s' AND dtstart > '%s' and `dismissed` = 0
+ and etype in ( 'event', 'birthday' )
+ ORDER BY `dtstart` DESC LIMIT 1000",
intval(local_channel()),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
@@ -335,14 +336,14 @@ class Ping extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $rr) {
if($rr['adjust'])
- $md = datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'Y/m');
+ $md = datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'Y/m');
else
- $md = datetime_convert('UTC', 'UTC', $rr['start'], 'Y/m');
+ $md = datetime_convert('UTC', 'UTC', $rr['dtstart'], 'Y/m');
- $strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['start']);
+ $strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart']);
$today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false);
- $when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
+ $when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
$result[] = array(
'notify_link' => z_root() . '/events', // FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'],
@@ -442,10 +443,10 @@ class Ping extends \Zotlabs\Web\Controller {
$t5 = dba_timer();
if($vnotify & (VNOTIFY_EVENT|VNOTIFY_EVENTTODAY|VNOTIFY_BIRTHDAY)) {
- $events = q("SELECT type, start, adjust FROM `event`
- WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0
- and type in ( 'event', 'birthday' )
- ORDER BY `start` ASC ",
+ $events = q("SELECT etype, dtstart, adjust FROM `event`
+ WHERE `event`.`uid` = %d AND dtstart < '%s' AND dtstart > '%s' and `dismissed` = 0
+ and etype in ( 'event', 'birthday' )
+ ORDER BY `dtstart` ASC ",
intval(local_channel()),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')),
dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days'))
@@ -458,14 +459,14 @@ class Ping extends \Zotlabs\Web\Controller {
$str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d');
foreach($events as $x) {
$bd = false;
- if($x['type'] === 'birthday') {
+ if($x['etype'] === 'birthday') {
$result['birthdays'] ++;
$bd = true;
}
else {
$result['events'] ++;
}
- if(datetime_convert('UTC', ((intval($x['adjust'])) ? date_default_timezone_get() : 'UTC'), $x['start'], 'Y-m-d') === $str_now) {
+ if(datetime_convert('UTC', ((intval($x['adjust'])) ? date_default_timezone_get() : 'UTC'), $x['dtstart'], 'Y-m-d') === $str_now) {
$result['all_events_today'] ++;
if($bd)
$result['birthdays_today'] ++;
diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php
index 123ecbc7b..cf8d83023 100644
--- a/Zotlabs/Module/Poke.php
+++ b/Zotlabs/Module/Poke.php
@@ -115,7 +115,7 @@ class Poke extends \Zotlabs\Web\Controller {
),
);
- $arr['object'] = json_encode($obj);
+ $arr['obj'] = json_encode($obj);
$arr['item_origin'] = 1;
$arr['item_wall'] = 1;
diff --git a/Zotlabs/Module/Prate.php b/Zotlabs/Module/Prate.php
index 65bbcca9a..2a8539ed0 100644
--- a/Zotlabs/Module/Prate.php
+++ b/Zotlabs/Module/Prate.php
@@ -85,7 +85,7 @@ class Prate extends \Zotlabs\Web\Controller {
$record = $z[0]['xlink_id'];
}
if($record) {
- proc_run('php','include/ratenotif.php','rating',$record);
+ \Zotlabs\Daemon\Master::Summon(array('Ratenotif','rating',$record));
}
json_return_and_die(array('result' => true));;
diff --git a/Zotlabs/Module/Probe.php b/Zotlabs/Module/Probe.php
index 79abe9819..dda792131 100644
--- a/Zotlabs/Module/Probe.php
+++ b/Zotlabs/Module/Probe.php
@@ -20,17 +20,17 @@ class Probe extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
$addr = trim($_GET['addr']);
$do_import = ((intval($_GET['import']) && is_site_admin()) ? true : false);
- $res = zot_finger($addr,$channel,false);
+
+ $j = \Zotlabs\Zot\Finger::run($addr,$channel,false);
+
+ // $res = zot_finger($addr,$channel,false);
+
$o .= '';
- if($res['success'])
- $j = json_decode($res['body'],true);
- else {
+ if(! $j['success']) {
$o .= sprintf( t('Fetching URL returns error: %1$s'),$res['error'] . "\r\n\r\n");
$o .= "https connection failed. Trying again with auto failover to http. \r\n\r\n";
- $res = zot_finger($addr,$channel,true);
- if($res['success'])
- $j = json_decode($res['body'],true);
- else
+ $j = \Zotlabs\Zot\Finger::run($addr,$channel,true);
+ if(! $j['success'])
$o .= sprintf( t('Fetching URL returns error: %1$s'),$res['error'] . "\r\n\r\n");
}
diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php
index 04a64fe76..8bf358bc8 100644
--- a/Zotlabs/Module/Profile.php
+++ b/Zotlabs/Module/Profile.php
@@ -55,8 +55,8 @@ class Profile extends \Zotlabs\Web\Controller {
function get() {
- if(get_config('system','block_public') && (! get_account_id()) && (! remote_channel())) {
- return login();
+ if(observer_prohibited(true)) {
+ return login();
}
$groups = array();
diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php
index 8f879503c..6129a7492 100644
--- a/Zotlabs/Module/Profile_photo.php
+++ b/Zotlabs/Module/Profile_photo.php
@@ -9,7 +9,7 @@ namespace Zotlabs\Module;
require_once('include/photo/photo_driver.php');
require_once('include/photos.php');
-require_once('include/identity.php');
+require_once('include/channel.php');
/* @brief Function for sync'ing permissions of profile-photos and their profile
*
@@ -93,7 +93,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$srcW = $_POST['xfinal'] - $srcX;
$srcH = $_POST['yfinal'] - $srcY;
- $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND scale = %d LIMIT 1",
+ $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1",
dbesc($image_id),
dbesc(local_channel()),
intval($scale));
@@ -101,9 +101,9 @@ class Profile_photo extends \Zotlabs\Web\Controller {
if($r) {
$base_image = $r[0];
- $base_image['data'] = (($r[0]['os_storage']) ? @file_get_contents($base_image['data']) : dbunescbin($base_image['data']));
+ $base_image['content'] = (($r[0]['os_storage']) ? @file_get_contents($base_image['content']) : dbunescbin($base_image['content']));
- $im = photo_factory($base_image['data'], $base_image['type']);
+ $im = photo_factory($base_image['content'], $base_image['mimetype']);
if($im->is_valid()) {
$im->cropImage(300,$srcX,$srcY,$srcW,$srcH);
@@ -113,25 +113,25 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$p = array('aid' => $aid, 'uid' => local_channel(), 'resource_id' => $base_image['resource_id'],
'filename' => $base_image['filename'], 'album' => t('Profile Photos'));
- $p['scale'] = 4;
+ $p['imgscale'] = 4;
$p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL);
$r1 = $im->save($p);
$im->scaleImage(80);
- $p['scale'] = 5;
+ $p['imgscale'] = 5;
$r2 = $im->save($p);
$im->scaleImage(48);
- $p['scale'] = 6;
+ $p['imgscale'] = 6;
$r3 = $im->save($p);
if($r1 === false || $r2 === false || $r3 === false) {
// if one failed, delete them all so we can start over.
notice( t('Image resize failed.') . EOL );
- $x = q("delete from photo where resource_id = '%s' and uid = %d and scale >= 4 ",
+ $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 4 ",
dbesc($base_image['resource_id']),
local_channel()
);
@@ -179,7 +179,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL);
// Update directory in background
- proc_run('php',"include/directory.php",$channel['channel_id']);
+ \Zotlabs\Daemon\Master::Summon(array('Directory',$channel['channel_id']));
// Now copy profile-permissions to pictures, to prevent privacyleaks by automatically created folder 'Profile Pictures'
@@ -208,7 +208,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
logger('attach_store: ' . print_r($res,true));
if($res && intval($res['data']['is_photo'])) {
- $i = q("select * from photo where resource_id = '%s' and uid = %d order by scale",
+ $i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($hash),
intval(local_channel())
);
@@ -220,11 +220,11 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$os_storage = false;
foreach($i as $ii) {
- if(intval($ii['scale']) < 2) {
- $smallest = intval($ii['scale']);
+ if(intval($ii['imgscale']) < 2) {
+ $smallest = intval($ii['imgscale']);
$os_storage = intval($ii['os_storage']);
- $imagedata = $ii['data'];
- $filetype = $ii['type'];
+ $imagedata = $ii['content'];
+ $filetype = $ii['mimetype'];
}
}
}
@@ -250,7 +250,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
*/
- function get() {
+ function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL );
@@ -275,7 +275,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
$resource_id = argv(2);
- $r = q("SELECT id, album, scale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY scale ASC",
+ $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC",
intval(local_channel()),
dbesc($resource_id)
);
@@ -285,7 +285,7 @@ class Profile_photo extends \Zotlabs\Web\Controller {
}
$havescale = false;
foreach($r as $rr) {
- if($rr['scale'] == 5)
+ if($rr['imgscale'] == 5)
$havescale = true;
}
@@ -311,11 +311,11 @@ class Profile_photo extends \Zotlabs\Web\Controller {
);
profile_photo_set_profile_perms(); //Reset default photo permissions to public
- proc_run('php','include/directory.php',local_channel());
+ \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
goaway(z_root() . '/profiles');
}
- $r = q("SELECT `data`, `type`, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
+ $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1",
intval($r[0]['id']),
intval(local_channel())
@@ -326,15 +326,15 @@ class Profile_photo extends \Zotlabs\Web\Controller {
}
if(intval($r[0]['os_storage']))
- $data = @file_get_contents($r[0]['data']);
+ $data = @file_get_contents($r[0]['content']);
else
- $data = dbunescbin($r[0]['data']);
+ $data = dbunescbin($r[0]['content']);
- $ph = photo_factory($data, $r[0]['type']);
+ $ph = photo_factory($data, $r[0]['mimetype']);
$smallest = 0;
if($ph->is_valid()) {
// go ahead as if we have just uploaded a new photo to crop
- $i = q("select resource_id, scale from photo where resource_id = '%s' and uid = %d order by scale",
+ $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale",
dbesc($r[0]['resource_id']),
intval(local_channel())
);
@@ -342,8 +342,8 @@ class Profile_photo extends \Zotlabs\Web\Controller {
if($i) {
$hash = $i[0]['resource_id'];
foreach($i as $ii) {
- if(intval($ii['scale']) < 2) {
- $smallest = intval($ii['scale']);
+ if(intval($ii['imgscale']) < 2) {
+ $smallest = intval($ii['imgscale']);
}
}
}
diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php
index 72edf396f..06e5cfd7b 100644
--- a/Zotlabs/Module/Profiles.php
+++ b/Zotlabs/Module/Profiles.php
@@ -1,7 +1,8 @@
z_root(),
@@ -714,7 +710,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'$is_default' => $is_default,
'$default' => t('This is your default profile.') . EOL . translate_scope(map_scope($channel['channel_r_profile'])),
'$advanced' => $advanced,
- '$name' => array('name', t('Your full name'), $r[0]['name'], t('Required'), '*'),
+ '$name' => array('name', t('Your full name'), $r[0]['fullname'], t('Required'), '*'),
'$pdesc' => array('pdesc', t('Title/Description'), $r[0]['pdesc']),
'$dob' => dob($r[0]['dob']),
'$hide_friends' => $hide_friends,
@@ -727,7 +723,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'$gender_min' => gender_selector_min($r[0]['gender']),
'$marital' => marital_selector($r[0]['marital']),
'$marital_min' => marital_selector_min($r[0]['marital']),
- '$with' => array('with', t("Who (if applicable)"), $r[0]['with'], t('Examples: cathy123, Cathy Williams, cathy@example.com')),
+ '$with' => array('with', t("Who (if applicable)"), $r[0]['partner'], t('Examples: cathy123, Cathy Williams, cathy@example.com')),
'$howlong' => array('howlong', t('Since (date)'), ($r[0]['howlong'] === NULL_DATE ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong']))),
'$sexual' => sexpref_selector($r[0]['sexual']),
'$sexual_min' => sexpref_selector_min($r[0]['sexual']),
@@ -745,7 +741,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'$film' => array('film', t('Film/Dance/Culture/Entertainment'), $r[0]['film']),
'$interest' => array('interest', t('Hobbies/Interests'), $r[0]['interest']),
'$romance' => array('romance',t('Love/Romance'), $r[0]['romance']),
- '$work' => array('work', t('Work/Employment'), $r[0]['work']),
+ '$work' => array('work', t('Work/Employment'), $r[0]['employment']),
'$education' => array('education', t('School/Education'), $r[0]['education']),
'$contact' => array('contact', t('Contact information and social networks'), $r[0]['contact']),
'$channels' => array('channels', t('My other channels'), $r[0]['channels']),
@@ -761,7 +757,7 @@ class Profiles extends \Zotlabs\Web\Controller {
$r = q("SELECT * FROM `profile` WHERE `uid` = %d",
local_channel());
- if(count($r)) {
+ if($r) {
$tpl = get_markup_template('profile_entry.tpl');
foreach($r as $rr) {
@@ -782,10 +778,7 @@ class Profiles extends \Zotlabs\Web\Controller {
'$cr_new' => t('Create New'),
'$cr_new_link' => 'profiles/new?t=' . get_form_security_token("profile_new"),
'$profiles' => $profiles
- ));
-
-
-
+ ));
}
return $o;
diff --git a/Zotlabs/Module/Profperm.php b/Zotlabs/Module/Profperm.php
index 94267aaac..33e9d1ece 100644
--- a/Zotlabs/Module/Profperm.php
+++ b/Zotlabs/Module/Profperm.php
@@ -1,7 +1,7 @@
' . t('Hub URL') . ' ' . t('Access Type') . ' ' . t('Registration Policy') . ' ' . t('Ratings') . ' ';
+ $o .= ' ' . t('Hub URL') . ' ' . t('Access Type') . ' ' . t('Registration Policy') . ' ' . t('Stats') . ' ' . t('Software') . ' ' . t('Ratings') . ' ';
if($j['sites']) {
foreach($j['sites'] as $jj) {
- if($jj['project'] !== \Zotlabs\Project\System::get_platform_name())
+ $m = parse_url($jj['url']);
+ if(strpos($jj['project'],\Zotlabs\Lib\System::get_platform_name()) === false)
continue;
$host = strtolower(substr($jj['url'],strpos($jj['url'],'://')+3));
$rate_links = ((local_channel()) ? ' ' . t('Rate') . ' ' : '');
@@ -43,7 +44,7 @@ class Pubsites extends \Zotlabs\Web\Controller {
$location = ' ';
}
$urltext = str_replace(array('https://'), '', $jj['url']);
- $o .= ' ' . $urltext . ' ' . $location . '' . $jj['access'] . ' ' . $jj['register'] . ' ' . t('View') . ' ' . $rate_links . ' ';
+ $o .= ' ' . $urltext . ' ' . $location . '' . $jj['access'] . ' ' . $jj['register'] . ' ' . ' ' . ucwords($jj['project']) . ' ' . t('View') . ' ' . $rate_links . ' ';
}
}
diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php
index adc16e6e6..312be7718 100644
--- a/Zotlabs/Module/Pubstream.php
+++ b/Zotlabs/Module/Pubstream.php
@@ -12,7 +12,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$_SESSION['loadtime'] = datetime_convert();
- if(get_config('system','block_public') && (! get_account_id()) && (! remote_channel())) {
+ if(observer_prohibited(true)) {
return login();
}
@@ -71,7 +71,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
}
- require_once('include/identity.php');
+ require_once('include/channel.php');
require_once('include/security.php');
if(get_config('system','site_firehose')) {
diff --git a/Zotlabs/Module/Randprof.php b/Zotlabs/Module/Randprof.php
index 86b25c22a..dc2e925fe 100644
--- a/Zotlabs/Module/Randprof.php
+++ b/Zotlabs/Module/Randprof.php
@@ -6,7 +6,6 @@ namespace Zotlabs\Module;
class Randprof extends \Zotlabs\Web\Controller {
function init() {
- require_once('include/Contact.php');
$x = random_profile();
if($x)
goaway(chanlink_url($x));
diff --git a/Zotlabs/Module/Rate.php b/Zotlabs/Module/Rate.php
index e2c05b6d4..da23b840e 100644
--- a/Zotlabs/Module/Rate.php
+++ b/Zotlabs/Module/Rate.php
@@ -102,14 +102,12 @@ class Rate extends \Zotlabs\Web\Controller {
}
if($record) {
- proc_run('php','include/ratenotif.php','rating',$record);
+ \Zotlabs\Daemon\Master::Summon(array('Ratenotif','rating',$record));
}
}
-
-
- function get() {
+ function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
diff --git a/Zotlabs/Module/Ratings.php b/Zotlabs/Module/Ratings.php
index 802bbfec2..969fb5015 100644
--- a/Zotlabs/Module/Ratings.php
+++ b/Zotlabs/Module/Ratings.php
@@ -8,7 +8,7 @@ class Ratings extends \Zotlabs\Web\Controller {
function init() {
- if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
return;
}
@@ -80,9 +80,9 @@ class Ratings extends \Zotlabs\Web\Controller {
- function get() {
+ function get() {
- if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php
new file mode 100644
index 000000000..ed4f87e7e
--- /dev/null
+++ b/Zotlabs/Module/React.php
@@ -0,0 +1,51 @@
+identity = $address;
$openid->returnUrl = z_root() . '/openid';
$openid->required = array('namePerson/friendly', 'namePerson');
$openid->optional = array('namePerson/first','media/image/aspect11','media/image/default');
goaway($openid->authUrl());
- } catch (Exception $e) {
+ } catch (\Exception $e) {
notice( t('We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.').' '. t('The error message was:').' '.$e->getMessage());
}
@@ -82,7 +82,7 @@ class Rmagic extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
$o = replace_macros(get_markup_template('rmagic.tpl'),array(
'$title' => t('Remote Authentication'),
diff --git a/Zotlabs/Module/Rsd_xml.php b/Zotlabs/Module/Rsd_xml.php
index 06af39ad1..e5059834b 100644
--- a/Zotlabs/Module/Rsd_xml.php
+++ b/Zotlabs/Module/Rsd_xml.php
@@ -6,7 +6,7 @@ class Rsd_xml extends \Zotlabs\Web\Controller {
function init() {
header ("Content-Type: text/xml");
echo replace_macros(get_markup_template('rsd.tpl'),array(
- '$project' => \Zotlabs\Project\System::get_platform_name(),
+ '$project' => \Zotlabs\Lib\System::get_platform_name(),
'$baseurl' => z_root(),
'$apipath' => z_root() . '/api/'
));
diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php
index 9941ebbd2..402a27d40 100644
--- a/Zotlabs/Module/Search.php
+++ b/Zotlabs/Module/Search.php
@@ -79,7 +79,7 @@ class Search extends \Zotlabs\Web\Controller {
return $o;
if($tag) {
- $sql_extra = sprintf(" AND `item`.`id` IN (select `oid` from term where otype = %d and type in ( %d , %d) and term = '%s') ",
+ $sql_extra = sprintf(" AND `item`.`id` IN (select `oid` from term where otype = %d and ttype in ( %d , %d) and term = '%s') ",
intval(TERM_OBJ_POST),
intval(TERM_HASHTAG),
intval(TERM_COMMUNITYTAG),
@@ -139,7 +139,7 @@ class Search extends \Zotlabs\Web\Controller {
$item_normal = item_normal();
$pub_sql = public_permissions_sql($observer_hash);
- require_once('include/identity.php');
+ require_once('include/channel.php');
$sys = get_sys_channel();
diff --git a/Zotlabs/Module/Search_ac.php b/Zotlabs/Module/Search_ac.php
index 78bcf374d..4e936d97b 100644
--- a/Zotlabs/Module/Search_ac.php
+++ b/Zotlabs/Module/Search_ac.php
@@ -46,7 +46,7 @@ class Search_ac extends \Zotlabs\Web\Controller {
}
}
- $r = q("select distinct term, tid, url from term where type in ( %d, %d ) $tag_sql_extra group by term order by term asc",
+ $r = q("select distinct term, tid, url from term where ttype in ( %d, %d ) $tag_sql_extra group by term order by term asc",
intval(TERM_HASHTAG),
intval(TERM_COMMUNITYTAG)
);
diff --git a/Zotlabs/Module/Settings.php b/Zotlabs/Module/Settings.php
index a6293e842..875004fae 100644
--- a/Zotlabs/Module/Settings.php
+++ b/Zotlabs/Module/Settings.php
@@ -78,7 +78,7 @@ class Settings extends \Zotlabs\Web\Controller {
$r = q("UPDATE clients SET
client_id='%s',
pw='%s',
- name='%s',
+ clname='%s',
redirect_uri='%s',
icon='%s',
uid=%d
@@ -91,7 +91,7 @@ class Settings extends \Zotlabs\Web\Controller {
intval(local_channel()),
dbesc($key));
} else {
- $r = q("INSERT INTO clients (client_id, pw, name, redirect_uri, icon, uid)
+ $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid)
VALUES ('%s','%s','%s','%s','%s',%d)",
dbesc($key),
dbesc($secret),
@@ -337,7 +337,7 @@ class Settings extends \Zotlabs\Web\Controller {
}
$hide_presence = 1 - (intval($role_permissions['online']));
if($role_permissions['default_collection']) {
- $r = q("select hash from groups where uid = %d and name = '%s' limit 1",
+ $r = q("select hash from groups where uid = %d and gname = '%s' limit 1",
intval(local_channel()),
dbesc( t('Friends') )
);
@@ -345,7 +345,7 @@ class Settings extends \Zotlabs\Web\Controller {
require_once('include/group.php');
group_add(local_channel(), t('Friends'));
group_add_member(local_channel(),t('Friends'),$channel['channel_hash']);
- $r = q("select hash from groups where uid = %d and name = '%s' limit 1",
+ $r = q("select hash from groups where uid = %d and gname = '%s' limit 1",
intval(local_channel()),
dbesc( t('Friends') )
);
@@ -483,7 +483,7 @@ class Settings extends \Zotlabs\Web\Controller {
if($username != $channel['channel_name']) {
$name_change = true;
- require_once('include/identity.php');
+ require_once('include/channel.php');
$err = validate_channelname($username);
if($err) {
notice($err);
@@ -537,13 +537,13 @@ class Settings extends \Zotlabs\Web\Controller {
dbesc(datetime_convert()),
dbesc($channel['channel_hash'])
);
- $r = q("update profile set name = '%s' where uid = %d and is_default = 1",
+ $r = q("update profile set fullname = '%s' where uid = %d and is_default = 1",
dbesc($username),
intval($channel['channel_id'])
);
}
- proc_run('php','include/directory.php',local_channel());
+ \Zotlabs\Daemon\Master::Summon(array('Directory',local_channel()));
build_sync_packet();
@@ -562,7 +562,7 @@ class Settings extends \Zotlabs\Web\Controller {
- function get() {
+ function get() {
$o = '';
nav_set_selected('settings');
@@ -615,7 +615,7 @@ class Settings extends \Zotlabs\Web\Controller {
'$title' => t('Add application'),
'$submit' => t('Update'),
'$cancel' => t('Cancel'),
- '$name' => array('name', t('Name'), $app['name'] , ''),
+ '$name' => array('name', t('Name'), $app['clname'] , ''),
'$key' => array('key', t('Consumer Key'), $app['client_id'], ''),
'$secret' => array('secret', t('Consumer Secret'), $app['pw'], ''),
'$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''),
@@ -1047,7 +1047,7 @@ class Settings extends \Zotlabs\Web\Controller {
'$h_prv' => t('Security and Privacy Settings'),
'$permissions_set' => $permissions_set,
- '$server_role' => \Zotlabs\Project\System::get_server_role(),
+ '$server_role' => \Zotlabs\Lib\System::get_server_role(),
'$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'),
'$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no),
@@ -1062,11 +1062,11 @@ class Settings extends \Zotlabs\Web\Controller {
'$lbl_p2macro' => t('Advanced Privacy Settings'),
- '$expire' => array('expire',t('Expire other channel content after this many days'),$expire,sprintf( t('0 or blank to use the website limit. The website expires after %d days.'),intval($sys_expire))),
+ '$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')),
'$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')),
- '$permissions' => t('Default Post Permissions'),
+ '$permissions' => t('Default Post and Publish Permissions'),
'$permdesc' => t("\x28click to open/close\x29"),
- '$aclselect' => populate_acl($perm_defaults, false, \PermissionDescription::fromDescription(t('Use my default audience setting for the type of post'))),
+ '$aclselect' => populate_acl($perm_defaults, false, \PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))),
'$suggestme' => $suggestme,
'$group_select' => $group_select,
'$role' => array('permissions_role' , t('Channel permissions category:'), $permissions_role, '', get_roles()),
diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php
index f8c14951b..c4878e217 100644
--- a/Zotlabs/Module/Setup.php
+++ b/Zotlabs/Module/Setup.php
@@ -12,7 +12,6 @@ namespace Zotlabs\Module;
/**
* @brief Initialisation for the setup module.
*
- * @param[in,out] App &$a
*/
class Setup extends \Zotlabs\Web\Controller {
@@ -54,16 +53,15 @@ class Setup extends \Zotlabs\Web\Controller {
/**
* @brief Handle the actions of the different setup steps.
*
- * @param[in,out] App &$a
*/
- function post() {
- global $db;
+
+ function post() {
switch($this->install_wizard_pass) {
case 1:
case 2:
return;
- break; // just in case return don't return :)
+ // implied break;
case 3:
$urlpath = \App::get_path();
$dbhost = trim($_POST['dbhost']);
@@ -82,39 +80,15 @@ class Setup extends \Zotlabs\Web\Controller {
$siteurl = rtrim($siteurl,'/');
require_once('include/dba/dba_driver.php');
- unset($db);
- $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
+
+ $db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
- if(! $db->connected) {
- echo 'Database Connect failed: ' . $db->error;
+ if(! \DBA::$dba->connected) {
+ echo 'Database Connect failed: ' . DBA::$dba->error;
killme();
- \App::$data['db_conn_failed']=true;
}
- /*if(get_db_errno()) {
- unset($db);
- $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, '', true);
-
- if(! get_db_errno()) {
- $r = q("CREATE DATABASE '%s'",
- dbesc($dbdata)
- );
- if($r) {
- unset($db);
- $db = new dba($dbhost, $dbport, $dbuser, $dbpass, $dbdata, true);
- } else {
- \App::$data['db_create_failed']=true;
- }
- } else {
- \App::$data['db_conn_failed']=true;
- return;
- }
- }*/
- //if(get_db_errno()) {
-
- //}
-
return;
- break;
+ // implied break;
case 4:
$urlpath = \App::get_path();
$dbhost = notags(trim($_POST['dbhost']));
@@ -138,10 +112,12 @@ class Setup extends \Zotlabs\Web\Controller {
}
}
- // connect to db
- $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
-
- if(! $db->connected) {
+ if(! \DBA::$dba->connected) {
+ // connect to db
+ $db = \DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);
+ }
+
+ if(! \DBA::$dba->connected) {
echo 'CRITICAL: DB not connected.';
killme();
}
@@ -175,6 +151,8 @@ class Setup extends \Zotlabs\Web\Controller {
\App::$data['db_installed'] = true;
return;
+ // implied break;
+ default:
break;
}
}
@@ -191,11 +169,10 @@ class Setup extends \Zotlabs\Web\Controller {
*
* Depending on the state we are currently in it returns different content.
*
- * @param App &$a
* @return string parsed HTML output
*/
- function get() {
- global $db;
+
+ function get() {
$o = '';
$wizard_status = '';
@@ -228,7 +205,7 @@ class Setup extends \Zotlabs\Web\Controller {
$txt .= "".\App::$data['db_failed'] . " ". EOL ;
$db_return_text .= $txt;
}
- if($db && $db->connected) {
+ if(\DBA::$dba && \DBA::$dba->connected) {
$r = q("SELECT COUNT(*) as `total` FROM `account`");
if($r && count($r) && $r[0]['total']) {
$tpl = get_markup_template('install.tpl');
@@ -407,8 +384,8 @@ class Setup extends \Zotlabs\Web\Controller {
function check_php(&$phpath, &$checks) {
$help = '';
- if(version_compare(PHP_VERSION, '5.4') < 0) {
- $help .= t('PHP version 5.4 or greater is required.');
+ if(version_compare(PHP_VERSION, '5.5') < 0) {
+ $help .= t('PHP version 5.5 or greater is required.');
$this->check_add($checks, t('PHP version'), false, false, $help);
}
@@ -598,7 +575,7 @@ class Setup extends \Zotlabs\Web\Controller {
if(! is_writable(TEMPLATE_BUILD_PATH) ) {
$status = false;
$help = t('Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') .EOL;
- $help .= sprintf( t('In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder.'), TEMPLATE_BUILD_PATH) . EOL;
+ $help .= sprintf( t('In order to store these compiled templates, the web server needs to have write access to the directory %s under the top level web folder.'), TEMPLATE_BUILD_PATH) . EOL;
$help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL;
$help .= sprintf( t('Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains.'), TEMPLATE_BUILD_PATH) . EOL;
}
@@ -698,12 +675,12 @@ class Setup extends \Zotlabs\Web\Controller {
function load_database($db) {
- $str = file_get_contents($db->get_install_script());
+ $str = file_get_contents(\DBA::$dba->get_install_script());
$arr = explode(';',$str);
$errors = false;
foreach($arr as $a) {
if(strlen(trim($a))) {
- $r = @$db->q(trim($a));
+ $r = dbq(trim($a));
if(! $r) {
$errors .= t('Errors encountered creating database tables.') . $a . EOL;
}
@@ -734,7 +711,7 @@ class Setup extends \Zotlabs\Web\Controller {
set_config('system','curl_ssl_ciphers','ALL:!eNULL');
// Create a system channel
- require_once ('include/identity.php');
+ require_once ('include/channel.php');
create_sys_channel();
$baseurl = z_root();
diff --git a/Zotlabs/Module/Share.php b/Zotlabs/Module/Share.php
index 73db01657..fcc2486ba 100644
--- a/Zotlabs/Module/Share.php
+++ b/Zotlabs/Module/Share.php
@@ -48,7 +48,7 @@ class Share extends \Zotlabs\Web\Controller {
$is_photo = (($r[0]['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
if($is_photo) {
- $object = json_decode($r[0]['object'],true);
+ $object = json_decode($r[0]['obj'],true);
$photo_bb = $object['body'];
}
diff --git a/Zotlabs/Module/Sharedwithme.php b/Zotlabs/Module/Sharedwithme.php
index 8eaa47dba..25bc7dba3 100644
--- a/Zotlabs/Module/Sharedwithme.php
+++ b/Zotlabs/Module/Sharedwithme.php
@@ -46,7 +46,7 @@ class Sharedwithme extends \Zotlabs\Web\Controller {
}
//list files
- $r = q("SELECT id, uid, object, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'",
+ $r = q("SELECT id, uid, obj, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'",
dbesc(ACTIVITY_POST),
dbesc(ACTIVITY_OBJ_FILE),
intval(local_channel()),
@@ -59,7 +59,7 @@ class Sharedwithme extends \Zotlabs\Web\Controller {
if($r) {
foreach($r as $rr) {
- $object = json_decode($rr['object'],true);
+ $object = json_decode($rr['obj'],true);
$item = array();
$item['id'] = $rr['id'];
diff --git a/Zotlabs/Module/Siteinfo.php b/Zotlabs/Module/Siteinfo.php
index c65277004..41f6e9f0b 100644
--- a/Zotlabs/Module/Siteinfo.php
+++ b/Zotlabs/Module/Siteinfo.php
@@ -16,10 +16,10 @@ class Siteinfo extends \Zotlabs\Web\Controller {
function get() {
if(! get_config('system','hidden_version_siteinfo')) {
- $version = sprintf( t('Version %s'), \Zotlabs\Project\System::get_project_version());
+ $version = sprintf( t('Version %s'), \Zotlabs\Lib\System::get_project_version());
if(@is_dir('.git') && function_exists('shell_exec')) {
$commit = @shell_exec('git log -1 --format="%h"');
- $tag = \Zotlabs\Project\System::get_std_version(); // @shell_exec('git describe --tags --abbrev=0');
+ $tag = \Zotlabs\Lib\System::get_std_version(); // @shell_exec('git describe --tags --abbrev=0');
}
if(! isset($commit) || strlen($commit) > 16)
$commit = '';
diff --git a/Zotlabs/Module/Subthread.php b/Zotlabs/Module/Subthread.php
index 16a011a40..0226664d7 100644
--- a/Zotlabs/Module/Subthread.php
+++ b/Zotlabs/Module/Subthread.php
@@ -144,7 +144,7 @@ class Subthread extends \Zotlabs\Web\Controller {
$arr['verb'] = $activity;
$arr['obj_type'] = $objtype;
- $arr['object'] = $obj;
+ $arr['obj'] = $obj;
$arr['allow_cid'] = $item['allow_cid'];
$arr['allow_gid'] = $item['allow_gid'];
diff --git a/Zotlabs/Module/Tagger.php b/Zotlabs/Module/Tagger.php
index 879cf3dbb..0a46cf56d 100644
--- a/Zotlabs/Module/Tagger.php
+++ b/Zotlabs/Module/Tagger.php
@@ -124,14 +124,14 @@ class Tagger extends \Zotlabs\Web\Controller {
$arr['tgt_type'] = $targettype;
$arr['target'] = $target;
$arr['obj_type'] = $objtype;
- $arr['object'] = $obj;
+ $arr['obj'] = $obj;
$arr['parent_mid'] = $item['mid'];
store_item_tag($item['uid'],$item['id'],TERM_OBJ_POST,TERM_COMMUNITYTAG,$term,$tagid);
$ret = post_activity_item($arr);
if($ret['success'])
- proc_run('php','include/notifier.php','tag',$ret['activity']['id']);
+ \Zotlabs\Daemon\Master::Summon(array('Notifier','tag',$ret['activity']['id']));
killme();
diff --git a/Zotlabs/Module/Tagrm.php b/Zotlabs/Module/Tagrm.php
index 81ae30aa5..42aa6e90f 100644
--- a/Zotlabs/Module/Tagrm.php
+++ b/Zotlabs/Module/Tagrm.php
@@ -54,7 +54,7 @@ class Tagrm extends \Zotlabs\Web\Controller {
- function get() {
+ function get() {
if(! local_channel()) {
goaway(z_root() . '/' . $_SESSION['photo_return']);
diff --git a/Zotlabs/Module/Tasks.php b/Zotlabs/Module/Tasks.php
index ab05f8be9..6d0a92d91 100644
--- a/Zotlabs/Module/Tasks.php
+++ b/Zotlabs/Module/Tasks.php
@@ -45,7 +45,7 @@ class Tasks extends \Zotlabs\Web\Controller {
if((argc() > 2) && (argv(1) === 'complete') && intval(argv(2))) {
$ret = array('success' => false);
- $r = q("select * from event where `type` = 'task' and uid = %d and id = %d limit 1",
+ $r = q("select * from event where `etype` = 'task' and uid = %d and id = %d limit 1",
intval(local_channel()),
intval(argv(2))
);
@@ -80,9 +80,9 @@ class Tasks extends \Zotlabs\Web\Controller {
$event['account'] = $channel['channel_account_id'];
$event['uid'] = $channel['channel_id'];
$event['event_xchan'] = $channel['channel_hash'];
- $event['type'] = 'task';
+ $event['etype'] = 'task';
$event['nofinish'] = true;
- $event['created'] = $event['edited'] = $event['start'] = datetime_convert();
+ $event['created'] = $event['edited'] = $event['dtstart'] = datetime_convert();
$event['adjust'] = 1;
$event['allow_cid'] = '<' . $channel['channel_hash'] . '>';
$event['summary'] = escape_tags($_REQUEST['summary']);
@@ -92,21 +92,13 @@ class Tasks extends \Zotlabs\Web\Controller {
else
$x = array('success' => false);
json_return_and_die($x);
- }
-
-
+ }
}
-
-
-
-
- function get() {
-
+ function get() {
if(! local_channel())
return;
-
-
+
return '';
}
}
diff --git a/Zotlabs/Module/Thing.php b/Zotlabs/Module/Thing.php
index e95ec53f6..65fc0588e 100644
--- a/Zotlabs/Module/Thing.php
+++ b/Zotlabs/Module/Thing.php
@@ -7,7 +7,7 @@ namespace Zotlabs\Module;
require_once('include/items.php');
require_once('include/security.php');
-require_once('include/contact_selectors.php');
+require_once('include/selectors.php');
require_once('include/acl_selectors.php');
@@ -26,7 +26,7 @@ class Thing extends \Zotlabs\Web\Controller {
$verb = escape_tags($_REQUEST['verb']);
$activity = intval($_REQUEST['activity']);
$profile_guid = escape_tags($_REQUEST['profile_assign']);
- $url = $_REQUEST['link'];
+ $url = $_REQUEST['url'];
$photo = $_REQUEST['img'];
$hash = random_string();
@@ -212,7 +212,7 @@ class Thing extends \Zotlabs\Web\Controller {
$arr['verb'] = $verb;
$arr['obj_type'] = $objtype;
- $arr['object'] = $obj;
+ $arr['obj'] = $obj;
if(! $profile['is_default']) {
$arr['item_private'] = true;
@@ -235,7 +235,7 @@ class Thing extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
// @FIXME one problem with things is we can't share them unless we provide the channel in the url
// so we can definitively lookup the owner.
diff --git a/Zotlabs/Module/Uexport.php b/Zotlabs/Module/Uexport.php
index ada7e0986..d48f96d76 100644
--- a/Zotlabs/Module/Uexport.php
+++ b/Zotlabs/Module/Uexport.php
@@ -11,7 +11,7 @@ class Uexport extends \Zotlabs\Web\Controller {
if(argc() > 1) {
$channel = \App::get_channel();
- require_once('include/identity.php');
+ require_once('include/channel.php');
if(argc() > 1 && intval(argv(1)) > 1900) {
$year = intval(argv(1));
diff --git a/Zotlabs/Module/Viewconnections.php b/Zotlabs/Module/Viewconnections.php
index 726ef043b..ea478f92a 100644
--- a/Zotlabs/Module/Viewconnections.php
+++ b/Zotlabs/Module/Viewconnections.php
@@ -1,23 +1,22 @@
1)
profile_load($a,argv(1));
}
- function get() {
+ function get() {
- if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php
index 5bdecfa75..9a1019ddb 100644
--- a/Zotlabs/Module/Wall_attach.php
+++ b/Zotlabs/Module/Wall_attach.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
require_once('include/attach.php');
-require_once('include/identity.php');
+require_once('include/channel.php');
require_once('include/photos.php');
diff --git a/Zotlabs/Module/Wall_upload.php b/Zotlabs/Module/Wall_upload.php
index fff3ed03a..3868cb14e 100644
--- a/Zotlabs/Module/Wall_upload.php
+++ b/Zotlabs/Module/Wall_upload.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Module;
require_once('include/photo/photo_driver.php');
-require_once('include/identity.php');
+require_once('include/channel.php');
require_once('include/photos.php');
diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php
index d8adb55b2..bb8d454c8 100644
--- a/Zotlabs/Module/Webpages.php
+++ b/Zotlabs/Module/Webpages.php
@@ -1,7 +1,7 @@
1)
+ $nick = argv(1); // if the channel name is in the URL, use that
+ if (!$nick && local_channel()) { // if no channel name was provided, assume the current logged in channel
+ $channel = \App::get_channel();
+ if ($channel && $channel['channel_address']) {
+ $nick = $channel['channel_address'];
+ goaway(z_root() . '/wiki/' . $nick);
+ }
+ }
+ if (!$nick) {
+ notice(t('You must be logged in to see this page.') . EOL);
+ goaway('/login');
+ }
+ }
+
+ function get() {
+ require_once('include/wiki.php');
+ require_once('include/acl_selectors.php');
+ // TODO: Combine the interface configuration into a unified object
+ // Something like $interface = array('new_page_button' => false, 'new_wiki_button' => false, ...)
+ $wiki_owner = false;
+ $showNewWikiButton = false;
+ $showCommitMsg = false;
+ $hidePageHistory = false;
+ $pageHistory = array();
+ $local_observer = null;
+ $resource_id = '';
+
+ // init() should have forced the URL to redirect to /wiki/channel so assume argc() > 1
+ $nick = argv(1);
+ $channel = get_channel_by_nick($nick); // The channel who owns the wikis being viewed
+ if(! $channel) {
+ notice('Invalid channel' . EOL);
+ goaway('/' . argv(0));
+ }
+ // Determine if the observer is the channel owner so the ACL dialog can be populated
+ if (local_channel() === intval($channel['channel_id'])) {
+ $local_observer = \App::get_channel();
+ $wiki_owner = true;
+
+ // Obtain the default permission settings of the channel
+ $channel_acl = array(
+ 'allow_cid' => $local_observer['channel_allow_cid'],
+ 'allow_gid' => $local_observer['channel_allow_gid'],
+ 'deny_cid' => $local_observer['channel_deny_cid'],
+ 'deny_gid' => $local_observer['channel_deny_gid']
+ );
+ // Initialize the ACL to the channel default permissions
+ $x = array(
+ 'lockstate' => (( $local_observer['channel_allow_cid'] ||
+ $local_observer['channel_allow_gid'] ||
+ $local_observer['channel_deny_cid'] ||
+ $local_observer['channel_deny_gid'])
+ ? 'lock' : 'unlock'),
+ 'acl' => populate_acl($channel_acl),
+ 'bang' => ''
+ );
+ } else {
+ // Not the channel owner
+ $channel_acl = $x = array();
+ }
+
+ switch (argc()) {
+ case 2:
+ // Configure page template
+ $wikiheader = t('Wiki Sandbox');
+ $content = '"# Wiki Sandbox\n\nContent you **edit** and **preview** here *will not be saved*."';
+ $hide_editor = false;
+ $showPageControls = false;
+ $showNewWikiButton = $wiki_owner;
+ $showNewPageButton = false;
+ $hidePageHistory = true;
+ $showCommitMsg = false;
+ break;
+ case 3:
+ // /wiki/channel/wiki -> No page was specified, so redirect to Home.md
+ $wikiUrlName = urlencode(argv(2));
+ goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName.'/Home');
+ case 4:
+ // GET /wiki/channel/wiki/page
+ // Fetch the wiki info and determine observer permissions
+ $wikiUrlName = urlencode(argv(2));
+ $pageUrlName = urlencode(argv(3));
+ $w = wiki_exists_by_name($channel['channel_id'], $wikiUrlName);
+ if(!$w['resource_id']) {
+ notice('Wiki not found' . EOL);
+ goaway('/'.argv(0).'/'.argv(1));
+ }
+ $resource_id = $w['resource_id'];
+
+ if (!$wiki_owner) {
+ // Check for observer permissions
+ $observer_hash = get_observer_hash();
+ $perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
+ if(!$perms['read']) {
+ notice('Permission denied.' . EOL);
+ goaway('/'.argv(0).'/'.argv(1));
+ }
+ if($perms['write']) {
+ $wiki_editor = true;
+ } else {
+ $wiki_editor = false;
+ }
+ } else {
+ $wiki_editor = true;
+ }
+ $wikiheader = urldecode($wikiUrlName) . ': ' . urldecode($pageUrlName); // show wiki name and page
+ $p = wiki_get_page_content(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
+ if(!$p['success']) {
+ notice('Error retrieving page content' . EOL);
+ goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName);
+ }
+ $content = ($p['content'] !== '' ? $p['content'] : '"# New page\n"');
+ $hide_editor = false;
+ $showPageControls = $wiki_editor;
+ $showNewWikiButton = $wiki_owner;
+ $showNewPageButton = $wiki_editor;
+ $hidePageHistory = false;
+ $showCommitMsg = true;
+ $pageHistory = wiki_page_history(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
+ break;
+ default: // Strip the extraneous URL components
+ goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName.'/'.$pageUrlName);
+ }
+ // Render the Markdown-formatted page content in HTML
+ require_once('library/markdown.php');
+
+ $o .= replace_macros(get_markup_template('wiki.tpl'),array(
+ '$wikiheader' => $wikiheader,
+ '$hideEditor' => $hide_editor,
+ '$showPageControls' => $showPageControls,
+ '$showNewWikiButton'=> $showNewWikiButton,
+ '$showNewPageButton'=> $showNewPageButton,
+ '$hidePageHistory' => $hidePageHistory,
+ '$showCommitMsg' => $showCommitMsg,
+ '$channel' => $channel['channel_address'],
+ '$resource_id' => $resource_id,
+ '$page' => $pageUrlName,
+ '$lockstate' => $x['lockstate'],
+ '$acl' => $x['acl'],
+ '$bang' => $x['bang'],
+ '$content' => $content,
+ '$renderedContent' => Markdown(json_decode($content)),
+ '$wikiName' => array('wikiName', t('Enter the name of your new wiki:'), '', ''),
+ '$pageName' => array('pageName', t('Enter the name of the new page:'), '', ''),
+ '$commitMsg' => array('commitMsg', '', '', '', '', 'placeholder="(optional) Enter a custom message when saving the page..."'),
+ '$pageHistory' => $pageHistory['history']
+ ));
+ head_add_js('library/ace/ace.js'); // Ace Code Editor
+ return $o;
+ }
+
+ function post() {
+ require_once('include/wiki.php');
+
+ // /wiki/channel/preview
+ // Render mardown-formatted text in HTML for preview
+ if((argc() > 2) && (argv(2) === 'preview')) {
+ $content = $_POST['content'];
+ require_once('library/markdown.php');
+ $html = purify_html(Markdown($content));
+ json_return_and_die(array('html' => $html, 'success' => true));
+ }
+
+ // Create a new wiki
+ // /wiki/channel/create/wiki
+ if ((argc() > 3) && (argv(2) === 'create') && (argv(3) === 'wiki')) {
+ $nick = argv(1);
+ $channel = get_channel_by_nick($nick);
+ // Determine if observer has permission to create wiki
+ $observer_hash = get_observer_hash();
+ // Only the channel owner can create a wiki, at least until we create a
+ // more detail permissions framework
+ if (local_channel() !== intval($channel['channel_id'])) {
+ goaway('/'.argv(0).'/'.$nick.'/');
+ }
+ $wiki = array();
+ // Generate new wiki info from input name
+ $wiki['rawName'] = $_POST['wikiName'];
+ $wiki['htmlName'] = escape_tags($_POST['wikiName']);
+ $wiki['urlName'] = urlencode($_POST['wikiName']);
+ if($wiki['urlName'] === '') {
+ notice('Error creating wiki. Invalid name.');
+ goaway('/wiki');
+ }
+ // Get ACL for permissions
+ $acl = new \Zotlabs\Access\AccessList($channel);
+ $acl->set_from_array($_POST);
+ $r = wiki_create_wiki($channel, $observer_hash, $wiki, $acl);
+ if ($r['success']) {
+ $homePage = wiki_create_page('Home', $r['item']['resource_id']);
+ if(!$homePage['success']) {
+ notice('Wiki created, but error creating Home page.');
+ goaway('/wiki/'.$nick.'/'.$wiki['urlName']);
+ }
+ goaway('/wiki/'.$nick.'/'.$wiki['urlName'].'/'.$homePage['page']['urlName']);
+ } else {
+ notice('Error creating wiki');
+ goaway('/wiki');
+ }
+ }
+
+ // Delete a wiki
+ if ((argc() > 3) && (argv(2) === 'delete') && (argv(3) === 'wiki')) {
+ $nick = argv(1);
+ $channel = get_channel_by_nick($nick);
+ // Only the channel owner can delete a wiki, at least until we create a
+ // more detail permissions framework
+ if (local_channel() !== intval($channel['channel_id'])) {
+ logger('Wiki delete permission denied.' . EOL);
+ json_return_and_die(array('message' => 'Wiki delete permission denied.', 'success' => false));
+ } else {
+ /*
+ $channel = get_channel_by_nick($nick);
+ $observer_hash = get_observer_hash();
+ // Figure out who the page owner is.
+ $perms = get_all_perms(intval($channel['channel_id']), $observer_hash);
+ // TODO: Create a new permission setting for wiki analogous to webpages. Until
+ // then, use webpage permissions
+ if (!$perms['write_pages']) {
+ logger('Wiki delete permission denied.' . EOL);
+ json_return_and_die(array('success' => false));
+ }
+ */
+ }
+ $resource_id = $_POST['resource_id'];
+ $deleted = wiki_delete_wiki($resource_id);
+ if ($deleted['success']) {
+ json_return_and_die(array('message' => '', 'success' => true));
+ } else {
+ logger('Error deleting wiki: ' . $resource_id);
+ json_return_and_die(array('message' => 'Error deleting wiki', 'success' => false));
+ }
+ }
+
+ // Create a page
+ if ((argc() === 4) && (argv(2) === 'create') && (argv(3) === 'page')) {
+ $nick = argv(1);
+ $resource_id = $_POST['resource_id'];
+ // Determine if observer has permission to create a page
+ $channel = get_channel_by_nick($nick);
+ if (local_channel() !== intval($channel['channel_id'])) {
+ $observer_hash = get_observer_hash();
+ $perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
+ if(!$perms['write']) {
+ logger('Wiki write permission denied. ' . EOL);
+ json_return_and_die(array('success' => false));
+ }
+ }
+ $name = $_POST['name']; //Get new page name
+ if(urlencode(escape_tags($_POST['name'])) === '') {
+ json_return_and_die(array('message' => 'Error creating page. Invalid name.', 'success' => false));
+ }
+ $page = wiki_create_page($name, $resource_id);
+ if ($page['success']) {
+ json_return_and_die(array('url' => '/'.argv(0).'/'.argv(1).'/'.$page['wiki']['urlName'].'/'.urlencode($page['page']['urlName']), 'success' => true));
+ } else {
+ logger('Error creating page');
+ json_return_and_die(array('message' => 'Error creating page.', 'success' => false));
+ }
+ }
+
+ // Fetch page list for a wiki
+ if ((argc() === 5) && (argv(2) === 'get') && (argv(3) === 'page') && (argv(4) === 'list')) {
+ $resource_id = $_POST['resource_id']; // resource_id for wiki in db
+ $channel = get_channel_by_nick(argv(1));
+ $observer_hash = get_observer_hash();
+ if (local_channel() !== intval($channel['channel_id'])) {
+ $perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
+ if(!$perms['read']) {
+ logger('Wiki read permission denied.' . EOL);
+ json_return_and_die(array('pages' => null, 'message' => 'Permission denied.', 'success' => false));
+ }
+ }
+ $page_list_html = widget_wiki_pages(array(
+ 'resource_id' => $resource_id,
+ 'refresh' => true,
+ 'channel' => argv(1)));
+ json_return_and_die(array('pages' => $page_list_html, 'message' => '', 'success' => true));
+ }
+
+ // Save a page
+ if ((argc() === 4) && (argv(2) === 'save') && (argv(3) === 'page')) {
+
+ $resource_id = $_POST['resource_id'];
+ $pageUrlName = $_POST['name'];
+ $pageHtmlName = escape_tags($_POST['name']);
+ $content = $_POST['content']; //Get new content
+ $commitMsg = $_POST['commitMsg'];
+ if ($commitMsg === '') {
+ $commitMsg = 'Updated ' . $pageHtmlName;
+ }
+ $nick = argv(1);
+ $channel = get_channel_by_nick($nick);
+ // Determine if observer has permission to save content
+ if (local_channel() !== intval($channel['channel_id'])) {
+ $observer_hash = get_observer_hash();
+ $perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
+ if(!$perms['write']) {
+ logger('Wiki write permission denied. ' . EOL);
+ json_return_and_die(array('success' => false));
+ }
+ }
+
+ $saved = wiki_save_page(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName, 'content' => $content));
+ if($saved['success']) {
+ $ob = \App::get_observer();
+ $commit = wiki_git_commit(array(
+ 'commit_msg' => $commitMsg,
+ 'resource_id' => $resource_id,
+ 'observer' => $ob,
+ 'files' => array($pageUrlName.'.md')
+ ));
+ if($commit['success']) {
+ json_return_and_die(array('message' => 'Wiki git repo commit made', 'success' => true));
+ } else {
+ json_return_and_die(array('message' => 'Error making git commit','success' => false));
+ }
+ } else {
+ json_return_and_die(array('message' => 'Error saving page', 'success' => false));
+ }
+ }
+
+ // Update page history
+ // /wiki/channel/history/page
+ if ((argc() === 4) && (argv(2) === 'history') && (argv(3) === 'page')) {
+
+ $resource_id = $_POST['resource_id'];
+ $pageUrlName = $_POST['name'];
+
+ $nick = argv(1);
+ $channel = get_channel_by_nick($nick);
+ // Determine if observer has permission to read content
+ if (local_channel() !== intval($channel['channel_id'])) {
+ $observer_hash = get_observer_hash();
+ $perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
+ if(!$perms['read']) {
+ logger('Wiki read permission denied.' . EOL);
+ json_return_and_die(array('historyHTML' => '', 'message' => 'Permission denied.', 'success' => false));
+ }
+ }
+ $historyHTML = widget_wiki_page_history(array(
+ 'resource_id' => $resource_id,
+ 'pageUrlName' => $pageUrlName
+ ));
+ json_return_and_die(array('historyHTML' => $historyHTML, 'message' => '', 'success' => true));
+ }
+
+ // Delete a page
+ if ((argc() === 4) && (argv(2) === 'delete') && (argv(3) === 'page')) {
+ $resource_id = $_POST['resource_id'];
+ $pageUrlName = $_POST['name'];
+ if ($pageUrlName === 'Home') {
+ json_return_and_die(array('message' => 'Cannot delete Home','success' => false));
+ }
+ // Determine if observer has permission to delete pages
+ $nick = argv(1);
+ $channel = get_channel_by_nick($nick);
+ if (local_channel() !== intval($channel['channel_id'])) {
+ $observer_hash = get_observer_hash();
+ $perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
+ if(!$perms['write']) {
+ logger('Wiki write permission denied. ' . EOL);
+ json_return_and_die(array('success' => false));
+ }
+ }
+ $deleted = wiki_delete_page(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
+ if($deleted['success']) {
+ $ob = \App::get_observer();
+ $commit = wiki_git_commit(array(
+ 'commit_msg' => 'Deleted ' . $pageHtmlName,
+ 'resource_id' => $resource_id,
+ 'observer' => $ob,
+ 'files' => null
+ ));
+ if($commit['success']) {
+ json_return_and_die(array('message' => 'Wiki git repo commit made', 'success' => true));
+ } else {
+ json_return_and_die(array('message' => 'Error making git commit','success' => false));
+ }
+ } else {
+ json_return_and_die(array('message' => 'Error deleting page', 'success' => false));
+ }
+ }
+
+ // Revert a page
+ if ((argc() === 4) && (argv(2) === 'revert') && (argv(3) === 'page')) {
+ $resource_id = $_POST['resource_id'];
+ $pageUrlName = $_POST['name'];
+ $commitHash = $_POST['commitHash'];
+ // Determine if observer has permission to revert pages
+ $nick = argv(1);
+ $channel = get_channel_by_nick($nick);
+ if (local_channel() !== intval($channel['channel_id'])) {
+ $observer_hash = get_observer_hash();
+ $perms = wiki_get_permissions($resource_id, intval($channel['channel_id']), $observer_hash);
+ if(!$perms['write']) {
+ logger('Wiki write permission denied.' . EOL);
+ json_return_and_die(array('success' => false));
+ }
+ }
+ $reverted = wiki_revert_page(array('commitHash' => $commitHash, 'observer' => \App::get_observer(), 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
+ if($reverted['success']) {
+ json_return_and_die(array('content' => $reverted['content'], 'message' => '', 'success' => true));
+ } else {
+ json_return_and_die(array('content' => '', 'message' => 'Error reverting page', 'success' => false));
+ }
+ }
+
+
+ //notice('You must be authenticated.');
+ json_return_and_die(array('message' => 'You must be authenticated.', 'success' => false));
+
+ }
+}
diff --git a/Zotlabs/Module/Zotfeed.php b/Zotlabs/Module/Zotfeed.php
index 28040149f..6b505c890 100644
--- a/Zotlabs/Module/Zotfeed.php
+++ b/Zotlabs/Module/Zotfeed.php
@@ -15,7 +15,7 @@ class Zotfeed extends \Zotlabs\Web\Controller {
if(! $mindate)
$mindate = datetime_convert('UTC','UTC', 'now - 14 days');
- if(get_config('system','block_public') && (! get_account_id()) && (! remote_channel())) {
+ if(observer_prohibited()) {
$result['message'] = 'Public access denied';
json_return_and_die($result);
}
@@ -45,8 +45,6 @@ class Zotfeed extends \Zotlabs\Web\Controller {
$result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate));
$result['success'] = true;
json_return_and_die($result);
-
-
}
}
diff --git a/Zotlabs/Render/Comanche.php b/Zotlabs/Render/Comanche.php
index 776874e35..1017ec6aa 100644
--- a/Zotlabs/Render/Comanche.php
+++ b/Zotlabs/Render/Comanche.php
@@ -8,7 +8,6 @@ require_once('include/widgets.php');
-
class Comanche {
@@ -95,7 +94,7 @@ class Comanche {
$cnt = preg_match_all("/\[region=(.*?)\](.*?)\[\/region\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
foreach($matches as $mtch) {
- \App::$layout['region_' . $mtch[1]] = $this->region($mtch[2]);
+ \App::$layout['region_' . $mtch[1]] = $this->region($mtch[2],$mtch[1]);
}
}
}
@@ -320,7 +319,9 @@ class Comanche {
}
- function region($s) {
+ function region($s,$region_name) {
+
+ $s = str_replace('$region',$region_name,$s);
$matches = array();
diff --git a/include/template_processor.php b/Zotlabs/Render/SimpleTemplate.php
similarity index 98%
rename from include/template_processor.php
rename to Zotlabs/Render/SimpleTemplate.php
index d2bf283e3..ff1bb5c3c 100755
--- a/include/template_processor.php
+++ b/Zotlabs/Render/SimpleTemplate.php
@@ -1,9 +1,11 @@
r = $r;
diff --git a/Zotlabs/Render/SmartyInterface.php b/Zotlabs/Render/SmartyInterface.php
new file mode 100755
index 000000000..0e3a47c2f
--- /dev/null
+++ b/Zotlabs/Render/SmartyInterface.php
@@ -0,0 +1,48 @@
+ "view/theme/$thname/tpl/");
+ if( x(\App::$theme_info,"extends") )
+ $template_dirs = $template_dirs + array('extends' => "view/theme/" . \App::$theme_info["extends"] . "/tpl/");
+ $template_dirs = $template_dirs + array('base' => 'view/tpl/');
+ $this->setTemplateDir($template_dirs);
+
+ $basecompiledir = \App::$config['system']['smarty3_folder'];
+
+ $this->setCompileDir($basecompiledir.'/compiled/');
+ $this->setConfigDir($basecompiledir.'/config/');
+ $this->setCacheDir($basecompiledir.'/cache/');
+
+ $this->left_delimiter = \App::get_template_ldelim('smarty3');
+ $this->right_delimiter = \App::get_template_rdelim('smarty3');
+
+ // Don't report errors so verbosely
+ $this->error_reporting = E_ALL & (~E_NOTICE);
+ }
+
+ function parsed($template = '') {
+ if($template) {
+ return $this->fetch('string:' . $template);
+ }
+ return $this->fetch('file:' . $this->filename);
+ }
+}
+
+
+
diff --git a/Zotlabs/Render/SmartyTemplate.php b/Zotlabs/Render/SmartyTemplate.php
new file mode 100755
index 000000000..532d6e42f
--- /dev/null
+++ b/Zotlabs/Render/SmartyTemplate.php
@@ -0,0 +1,75 @@
+ERROR: folder $basecompiledir does not exist."; killme();
+ }
+ if(!is_writable($basecompiledir)){
+ echo "ERROR: folder $basecompiledir must be writable by webserver."; killme();
+ }
+ \App::$config['system']['smarty3_folder'] = $basecompiledir;
+ }
+
+ // TemplateEngine interface
+
+ public function replace_macros($s, $r) {
+ $template = '';
+ if(gettype($s) === 'string') {
+ $template = $s;
+ $s = new SmartyInterface();
+ }
+ foreach($r as $key=>$value) {
+ if($key[0] === '$') {
+ $key = substr($key, 1);
+ }
+ $s->assign($key, $value);
+ }
+ return $s->parsed($template);
+ }
+
+ public function get_markup_template($file, $root=''){
+ $template_file = theme_include($file, $root);
+ if($template_file) {
+ $template = new SmartyInterface();
+ $template->filename = $template_file;
+
+ return $template;
+ }
+ return "";
+ }
+
+ public function get_intltext_template($file, $root='') {
+
+ $lang = \App::$language;
+
+ if(file_exists("view/$lang/$file"))
+ $template_file = "view/$lang/$file";
+ elseif(file_exists("view/en/$file"))
+ $template_file = "view/en/$file";
+ else
+ $template_file = theme_include($file,$root);
+ if($template_file) {
+ $template = new SmartyInterface();
+ $template->filename = $template_file;
+
+ return $template;
+ }
+ return "";
+ }
+
+
+
+}
diff --git a/include/ITemplateEngine.php b/Zotlabs/Render/TemplateEngine.php
similarity index 73%
rename from include/ITemplateEngine.php
rename to Zotlabs/Render/TemplateEngine.php
index 7bd559a63..600ff913e 100755
--- a/include/ITemplateEngine.php
+++ b/Zotlabs/Render/TemplateEngine.php
@@ -1,10 +1,12 @@
1) ? $t[1] : '');
+
+ $opts = '';
+ $opts = ((\App::$profile_uid) ? '?f=&puid=' . \App::$profile_uid : '');
+
+ $schema_str = ((x(\App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
+ if(($s) && (! $schema_str))
+ $schema_str = '&schema=' . $s;
+ $opts .= $schema_str;
+
+ if(file_exists('view/theme/' . $t . '/php/style.php'))
+ return('view/theme/' . $t . '/php/style.pcss' . $opts);
+
+ return('view/theme/' . $t . '/css/style.css');
+ }
+}
+
diff --git a/Zotlabs/Storage/BasicAuth.php b/Zotlabs/Storage/BasicAuth.php
index da5af7659..121a9c3a1 100644
--- a/Zotlabs/Storage/BasicAuth.php
+++ b/Zotlabs/Storage/BasicAuth.php
@@ -73,10 +73,12 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
protected $timezone = '';
+ public $module_disabled = false;
+
+
/**
* @brief Validates a username and password.
*
- * Guest access is granted with the password "+++".
*
* @see \Sabre\DAV\Auth\Backend\AbstractBasic::validateUserPass
* @param string $username
@@ -92,7 +94,7 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
intval($record['account_id']),
intval($record['account_default_channel'])
);
- if ($r) {
+ if($r && $this->check_module_access($r[0]['channel_id'])) {
return $this->setAuthenticated($r[0]);
}
}
@@ -109,13 +111,17 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
if ((($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED))
&& (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) {
logger('password verified for ' . $username);
- return $this->setAuthenticated($r[0]);
+ if($this->check_module_access($r[0]['channel_id']))
+ return $this->setAuthenticated($r[0]);
}
}
}
}
- $error = 'password failed for ' . $username;
+ if($this->module_disabled)
+ $error = 'module not enabled for ' . $username;
+ else
+ $error = 'password failed for ' . $username;
logger($error);
log_failed_login($error);
@@ -139,6 +145,17 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
return true;
}
+ protected function check_module_access($channel_id) {
+ if($channel_id && \App::$module === 'cdav') {
+ $x = get_pconfig($channel_id,'cdav','enabled');
+ if(! $x) {
+ $this->module_disabled = true;
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Sets the channel_name from the currently logged-in channel.
*
diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php
index ca262b739..f875cbf33 100644
--- a/Zotlabs/Storage/Browser.php
+++ b/Zotlabs/Storage/Browser.php
@@ -246,14 +246,17 @@ class Browser extends DAV\Browser\Plugin {
\App::$page['content'] = $html;
load_pdl($a);
- $theme_info_file = "view/theme/" . current_theme() . "/php/theme.php";
+ $current_theme = \Zotlabs\Render\Theme::current();
+
+ $theme_info_file = "view/theme/" . $current_theme[0] . "/php/theme.php";
if (file_exists($theme_info_file)){
require_once($theme_info_file);
- if (function_exists(str_replace('-', '_', current_theme()) . '_init')) {
- $func = str_replace('-', '_', current_theme()) . '_init';
+ if (function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) {
+ $func = str_replace('-', '_', $current_theme[0]) . '_init';
$func($a);
}
}
+ $this->server->httpResponse->setHeader('Content-Security-Policy', "script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'");
construct_page($a);
}
diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php
index 3c0cff6ef..06ae90a5f 100644
--- a/Zotlabs/Storage/Directory.php
+++ b/Zotlabs/Storage/Directory.php
@@ -194,7 +194,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
* @return null|string ETag
*/
public function createFile($name, $data = null) {
- logger($name, LOGGER_DEBUG);
+ logger('create file in directory ' . $name, LOGGER_DEBUG);
if (! $this->auth->owner_id) {
logger('permission denied ' . $name);
@@ -246,7 +246,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$deny_gid = $c[0]['channel_deny_gid'];
}
- $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
+ $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, content, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
intval($c[0]['channel_account_id']),
intval($c[0]['channel_id']),
@@ -358,7 +358,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
* @return void
*/
public function createDirectory($name) {
- logger($name, LOGGER_DEBUG);
+ logger('create directory ' . $name, LOGGER_DEBUG);
if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) {
throw new DAV\Exception\Forbidden('Permission denied.');
@@ -372,7 +372,9 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash));
if($result['success']) {
- $sync = attach_export_data($r[0],$ret['data']['hash']);
+ $sync = attach_export_data($r[0],$result['data']['hash']);
+ logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG);
+
if($sync) {
build_sync_packet($r[0]['channel_id'],array('file' => array($sync)));
}
@@ -563,4 +565,4 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$free
);
}
-}
\ No newline at end of file
+}
diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php
index d40fee0ea..ecd15cc55 100644
--- a/Zotlabs/Storage/File.php
+++ b/Zotlabs/Storage/File.php
@@ -124,7 +124,7 @@ class File extends DAV\Node implements DAV\IFile {
);
if ($r) {
if (intval($r[0]['os_storage'])) {
- $d = q("select folder, data from attach where hash = '%s' and uid = %d limit 1",
+ $d = q("select folder, content from attach where hash = '%s' and uid = %d limit 1",
dbesc($this->data['hash']),
intval($c[0]['channel_id'])
);
@@ -139,7 +139,7 @@ class File extends DAV\Node implements DAV\IFile {
$direct = $f1[0];
}
}
- $fname = dbunescbin($d[0]['data']);
+ $fname = dbunescbin($d[0]['content']);
if(strpos($fname,'store') === false)
$f = 'store/' . $this->auth->owner_nick . '/' . $fname ;
else
@@ -158,12 +158,12 @@ class File extends DAV\Node implements DAV\IFile {
}
else {
// this shouldn't happen any more
- $r = q("UPDATE attach SET data = '%s' WHERE hash = '%s' AND uid = %d",
+ $r = q("UPDATE attach SET content = '%s' WHERE hash = '%s' AND uid = %d",
dbescbin(stream_get_contents($data)),
dbesc($this->data['hash']),
intval($this->data['uid'])
);
- $r = q("SELECT length(data) AS fsize FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
+ $r = q("SELECT length(content) AS fsize FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
dbesc($this->data['hash']),
intval($this->data['uid'])
);
@@ -236,7 +236,7 @@ class File extends DAV\Node implements DAV\IFile {
logger('get file ' . basename($this->name), LOGGER_DEBUG);
logger('os_path: ' . $this->os_path, LOGGER_DATA);
- $r = q("SELECT data, flags, os_storage, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
+ $r = q("SELECT content, flags, os_storage, filename, filetype FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
dbesc($this->data['hash']),
intval($this->data['uid'])
);
@@ -250,14 +250,14 @@ class File extends DAV\Node implements DAV\IFile {
}
if (intval($r[0]['os_storage'])) {
- $x = dbunescbin($r[0]['data']);
+ $x = dbunescbin($r[0]['content']);
if(strpos($x,'store') === false)
$f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $x;
else
$f = $x;
return fopen($f, 'rb');
}
- return dbunescbin($r[0]['data']);
+ return dbunescbin($r[0]['content']);
}
}
diff --git a/Zotlabs/Storage/GitRepo.php b/Zotlabs/Storage/GitRepo.php
index 2a24e03c0..306abc0ba 100644
--- a/Zotlabs/Storage/GitRepo.php
+++ b/Zotlabs/Storage/GitRepo.php
@@ -75,6 +75,15 @@ class GitRepo {
}
}
}
+
+ public function initRepo() {
+ if(!$this->path) return false;
+ try {
+ return $this->git->init($this->path);
+ } catch (\PHPGit\Exception\GitException $ex) {
+ return false;
+ }
+ }
public function pull() {
try {
@@ -118,6 +127,15 @@ class GitRepo {
$repo['logs'] = $git->log(array('limit' => 50));
return $repo;
}
+
+ // Commit changes to the repo. Default is to stage all changes and commit everything.
+ public function commit($msg, $options = array()) {
+ try {
+ return $this->git->commit($msg, $options);
+ } catch (\PHPGit\Exception\GitException $ex) {
+ return false;
+ }
+ }
public static function isValidGitRepoURL($url) {
if (validate_url($url) && strrpos(parse_url($url, PHP_URL_PATH), '.')) {
diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php
index e6733ffdb..f9290ac30 100644
--- a/Zotlabs/Web/Router.php
+++ b/Zotlabs/Web/Router.php
@@ -206,13 +206,15 @@ class Router {
* load current theme info
*/
- $theme_info_file = 'view/theme/' . current_theme() . '/php/theme.php';
+ $current_theme = \Zotlabs\Render\Theme::current();
+
+ $theme_info_file = 'view/theme/' . $current_theme[0] . '/php/theme.php';
if (file_exists($theme_info_file)){
require_once($theme_info_file);
}
- if(function_exists(str_replace('-', '_', current_theme()) . '_init')) {
- $func = str_replace('-', '_', current_theme()) . '_init';
+ if(function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) {
+ $func = str_replace('-', '_', $current_theme[0]) . '_init';
$func($a);
}
elseif (x(\App::$theme_info, 'extends') && file_exists('view/theme/' . \App::$theme_info['extends'] . '/php/theme.php')) {
diff --git a/Zotlabs/Web/Session.php b/Zotlabs/Web/Session.php
index e18ad38fb..4f2a3f1f7 100644
--- a/Zotlabs/Web/Session.php
+++ b/Zotlabs/Web/Session.php
@@ -13,10 +13,10 @@ namespace Zotlabs\Web;
class Session {
- private static $handler = null;
- private static $session_started = false;
+ private $handler = null;
+ private $session_started = false;
- function init() {
+ public function init() {
$gc_probability = 50;
@@ -29,7 +29,8 @@ class Session {
*/
$handler = new \Zotlabs\Web\SessionHandler();
- self::$handler = $handler;
+
+ $this->handler = $handler;
$x = session_set_save_handler($handler,false);
if(! $x)
@@ -38,11 +39,17 @@ class Session {
// Force cookies to be secure (https only) if this site is SSL enabled.
// Must be done before session_start().
+
$arr = session_get_cookie_params();
+
+ // Note when setting cookies: set the domain to false which creates a single domain
+ // cookie. If you use a hostname it will create a .domain.com wildcard which will
+ // have some nasty side effects if you have any other subdomains running hubzilla.
+
session_set_cookie_params(
((isset($arr['lifetime'])) ? $arr['lifetime'] : 0),
((isset($arr['path'])) ? $arr['path'] : '/'),
- ((isset($arr['domain'])) ? $arr['domain'] : App::get_hostname()),
+ (($arr['domain']) ? $arr['domain'] : false),
((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),
((isset($arr['httponly'])) ? $arr['httponly'] : true)
);
@@ -51,9 +58,9 @@ class Session {
}
- function start() {
+ public function start() {
session_start();
- self::$session_started = true;
+ $this->session_started = true;
}
/**
@@ -62,8 +69,8 @@ class Session {
* @return void
*/
- function nuke() {
- self::new_cookie(0); // 0 means delete on browser exit
+ public function nuke() {
+ $this->new_cookie(0); // 0 means delete on browser exit
if($_SESSION && count($_SESSION)) {
foreach($_SESSION as $k => $v) {
unset($_SESSION[$k]);
@@ -71,48 +78,53 @@ class Session {
}
}
- function new_cookie($xtime) {
+ public function new_cookie($xtime) {
$newxtime = (($xtime> 0) ? (time() + $xtime) : 0);
$old_sid = session_id();
- if(self::$handler && self::$session_started) {
+ $arr = session_get_cookie_params();
+
+ if($this->handler && $this->session_started) {
+
session_regenerate_id(true);
// force SessionHandler record creation with the new session_id
// which occurs as a side effect of read()
- self::$handler->read(session_id());
+ $this->handler->read(session_id());
}
else
logger('no session handler');
if (x($_COOKIE, 'jsdisabled')) {
- setcookie('jsdisabled', $_COOKIE['jsdisabled'], $newxtime);
+ setcookie('jsdisabled', $_COOKIE['jsdisabled'], $newxtime, '/', false,((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),((isset($arr['httponly'])) ? $arr['httponly'] : true));
}
- setcookie(session_name(),session_id(),$newxtime);
+ setcookie(session_name(),session_id(),$newxtime, '/', false,((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),((isset($arr['httponly'])) ? $arr['httponly'] : true));
$arr = array('expire' => $xtime);
call_hooks('new_cookie', $arr);
}
- function extend_cookie() {
+ public function extend_cookie() {
+
+ $arr = session_get_cookie_params();
// if there's a long-term cookie, extend it
$xtime = (($_SESSION['remember_me']) ? (60 * 60 * 24 * 365) : 0 );
if($xtime)
- setcookie(session_name(),session_id(),(time() + $xtime));
+ setcookie(session_name(),session_id(),(time() + $xtime), '/', false,((isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on') ? true : false),((isset($arr['httponly'])) ? $arr['httponly'] : true));
$arr = array('expire' => $xtime);
call_hooks('extend_cookie', $arr);
}
- function return_check() {
+ public function return_check() {
// check a returning visitor against IP changes.
// If the change results in being blocked from re-entry with the current cookie
@@ -152,7 +164,7 @@ class Session {
// check any difference at all
logger('Session address changed. Paranoid setting in effect, blocking session. '
. $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']);
- self::nuke();
+ $this->nuke();
goaway(z_root());
break;
}
diff --git a/Zotlabs/Web/SessionHandler.php b/Zotlabs/Web/SessionHandler.php
index 6980a6408..6e7333b4b 100644
--- a/Zotlabs/Web/SessionHandler.php
+++ b/Zotlabs/Web/SessionHandler.php
@@ -18,10 +18,10 @@ class SessionHandler implements \SessionHandlerInterface {
function read ($id) {
if($id) {
- $r = q("SELECT `data` FROM `session` WHERE `sid`= '%s'", dbesc($id));
+ $r = q("SELECT `sess_data` FROM `session` WHERE `sid`= '%s'", dbesc($id));
if($r) {
- return $r[0]['data'];
+ return $r[0]['sess_data'];
}
else {
q("INSERT INTO `session` (sid, expire) values ('%s', '%s')",
@@ -59,7 +59,7 @@ class SessionHandler implements \SessionHandlerInterface {
}
q("UPDATE `session`
- SET `data` = '%s', `expire` = '%s' WHERE `sid` = '%s'",
+ SET `sess_data` = '%s', `expire` = '%s' WHERE `sid` = '%s'",
dbesc($data),
dbesc($expire),
dbesc($id)
diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php
new file mode 100644
index 000000000..88ab4995b
--- /dev/null
+++ b/Zotlabs/Web/WebServer.php
@@ -0,0 +1,130 @@
+start();
+ }
+ else {
+ session_start();
+ register_shutdown_function('session_write_close');
+ }
+
+ /**
+ * Language was set earlier, but we can over-ride it in the session.
+ * We have to do it here because the session was just now opened.
+ */
+
+ if(array_key_exists('system_language',$_POST)) {
+ if(strlen($_POST['system_language']))
+ $_SESSION['language'] = $_POST['system_language'];
+ else
+ unset($_SESSION['language']);
+ }
+ if((x($_SESSION, 'language')) && ($_SESSION['language'] !== $lang)) {
+ \App::$language = $_SESSION['language'];
+ load_translation_table(\App::$language);
+ }
+
+ if((x($_GET,'zid')) && (! \App::$install)) {
+ \App::$query_string = strip_zids(\App::$query_string);
+ if(! local_channel()) {
+ $_SESSION['my_address'] = $_GET['zid'];
+ zid_init($a);
+ }
+ }
+
+ if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (\App::$module === 'login'))
+ require('include/auth.php');
+
+ if(! x($_SESSION, 'sysmsg'))
+ $_SESSION['sysmsg'] = array();
+
+ if(! x($_SESSION, 'sysmsg_info'))
+ $_SESSION['sysmsg_info'] = array();
+
+ /*
+ * check_config() is responsible for running update scripts. These automatically
+ * update the DB schema whenever we push a new one out. It also checks to see if
+ * any plugins have been added or removed and reacts accordingly.
+ */
+
+
+ if(\App::$install) {
+ /* Allow an exception for the view module so that pcss will be interpreted during installation */
+ if(\App::$module != 'view')
+ \App::$module = 'setup';
+ }
+ else
+ check_config($a);
+
+ nav_set_selected('nothing');
+
+ $Router = new Router($a);
+
+ /* initialise content region */
+
+ if(! x(\App::$page, 'content'))
+ \App::$page['content'] = '';
+
+ call_hooks('page_content_top', \App::$page['content']);
+
+
+ $Router->Dispatch($a);
+
+
+ // If you're just visiting, let javascript take you home
+
+ if(x($_SESSION, 'visitor_home')) {
+ $homebase = $_SESSION['visitor_home'];
+ } elseif(local_channel()) {
+ $homebase = z_root() . '/channel/' . \App::$channel['channel_address'];
+ }
+
+ if(isset($homebase)) {
+ \App::$page['content'] .= '';
+ }
+
+ // now that we've been through the module content, see if the page reported
+ // a permission problem and if so, a 403 response would seem to be in order.
+
+ if(stristr(implode("", $_SESSION['sysmsg']), t('Permission denied'))) {
+ header($_SERVER['SERVER_PROTOCOL'] . ' 403 ' . t('Permission denied.'));
+ }
+
+ call_hooks('page_end', \App::$page['content']);
+
+ construct_page($a);
+
+ killme();
+ }
+}
\ No newline at end of file
diff --git a/Zotlabs/Zot/Auth.php b/Zotlabs/Zot/Auth.php
index f764172fa..0837be21a 100644
--- a/Zotlabs/Zot/Auth.php
+++ b/Zotlabs/Zot/Auth.php
@@ -80,11 +80,9 @@ class Auth {
if(! $x) {
// finger them if they can't be found.
- $ret = zot_finger($address, null);
- if ($ret['success']) {
- $j = json_decode($ret['body'], true);
- if($j)
- import_xchan($j);
+ $j = Finger::run($address, null);
+ if ($j['success']) {
+ import_xchan($j);
$x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
where hubloc_addr = '%s' order by hubloc_id desc",
dbesc($address)
diff --git a/Zotlabs/Zot/Finger.php b/Zotlabs/Zot/Finger.php
new file mode 100644
index 000000000..229fda8bd
--- /dev/null
+++ b/Zotlabs/Zot/Finger.php
@@ -0,0 +1,130 @@
+ true) or array('success' => false);
+ */
+
+ static public function run($webbie, $channel = null, $autofallback = true) {
+
+ $ret = array('success' => false);
+
+ self::$token = random_string();
+
+ if (strpos($webbie,'@') === false) {
+ $address = $webbie;
+ $host = App::get_hostname();
+ } else {
+ $address = substr($webbie,0,strpos($webbie,'@'));
+ $host = substr($webbie,strpos($webbie,'@')+1);
+ }
+
+ $xchan_addr = $address . '@' . $host;
+
+ if ((! $address) || (! $xchan_addr)) {
+ logger('zot_finger: no address :' . $webbie);
+ return $ret;
+ }
+
+ logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA, LOG_DEBUG);
+
+ // potential issue here; the xchan_addr points to the primary hub.
+ // The webbie we were called with may not, so it might not be found
+ // unless we query for hubloc_addr instead of xchan_addr
+
+ $r = q("select xchan.*, hubloc.* from xchan
+ left join hubloc on xchan_hash = hubloc_hash
+ where xchan_addr = '%s' and hubloc_primary = 1 limit 1",
+ dbesc($xchan_addr)
+ );
+
+ if ($r) {
+ $url = $r[0]['hubloc_url'];
+
+ if ($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') {
+ logger('zot_finger: alternate network: ' . $webbie);
+ logger('url: '.$url.', net: '.var_export($r[0]['hubloc_network'],true), LOGGER_DATA, LOG_DEBUG);
+ return $ret;
+ }
+ }
+ else {
+ $url = 'https://' . $host;
+ }
+
+ $rhs = '/.well-known/zot-info';
+ $https = ((strpos($url,'https://') === 0) ? true : false);
+
+ logger('zot_finger: ' . $address . ' at ' . $url, LOGGER_DEBUG);
+
+ if ($channel) {
+ $postvars = array(
+ 'address' => $address,
+ 'target' => $channel['channel_guid'],
+ 'target_sig' => $channel['channel_guid_sig'],
+ 'key' => $channel['channel_pubkey'],
+ 'token' => self::$token
+ );
+
+ $result = z_post_url($url . $rhs,$postvars);
+
+ if ((! $result['success']) && ($autofallback)) {
+ if ($https) {
+ logger('zot_finger: https failed. falling back to http');
+ $result = z_post_url('http://' . $host . $rhs,$postvars);
+ }
+ }
+ }
+ else {
+ $rhs .= '?f=&address=' . urlencode($address) . '&token=' . self::$token;
+
+ $result = z_fetch_url($url . $rhs);
+ if ((! $result['success']) && ($autofallback)) {
+ if ($https) {
+ logger('zot_finger: https failed. falling back to http');
+ $result = z_fetch_url('http://' . $host . $rhs);
+ }
+ }
+ }
+
+ if(! $result['success']) {
+ logger('zot_finger: no results');
+ return $ret;
+ }
+
+ $x = json_decode($result['body'],true);
+ if($x) {
+ $signed_token = ((is_array($x) && array_key_exists('signed_token',$x)) ? $x['signed_token'] : null);
+ if($signed_token) {
+ $valid = rsa_verify('token.' . self::$token,base64url_decode($signed_token),$x['key']);
+ if(! $valid) {
+ logger('invalid signed token: ' . $url . $rhs, LOGGER_NORMAL, LOG_ERR);
+ return $ret;
+ }
+ }
+ else {
+ logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING);
+ // after 2017-01-01 this will be a hard error unless you over-ride it.
+ if((time() > 1483228800) && (! get_config('system','allow_unsigned_zotfinger')))
+ return $ret;
+ }
+ }
+
+ return $x;
+ }
+
+}
\ No newline at end of file
diff --git a/Zotlabs/Zot/Verify.php b/Zotlabs/Zot/Verify.php
index 1192202db..06bd3188c 100644
--- a/Zotlabs/Zot/Verify.php
+++ b/Zotlabs/Zot/Verify.php
@@ -6,7 +6,7 @@ namespace Zotlabs\Zot;
class Verify {
function create($type,$channel_id,$token,$meta) {
- return q("insert into verify ( type, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )",
+ return q("insert into verify ( vtype, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )",
dbesc($type),
intval($channel_id),
dbesc($token),
@@ -16,7 +16,7 @@ class Verify {
}
function match($type,$channel_id,$token,$meta) {
- $r = q("select id from verify where type = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1",
+ $r = q("select id from verify where vtype = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1",
dbesc($type),
intval($channel_id),
dbesc($token),
@@ -32,7 +32,7 @@ class Verify {
}
function purge($type,$interval) {
- q("delete from verify where type = '%s' and created < %s - INTERVAL %s",
+ q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s",
dbesc($type),
db_utcnow(),
db_quoteinterval($interval)
diff --git a/app/wiki.apd b/app/wiki.apd
new file mode 100644
index 000000000..95245055c
--- /dev/null
+++ b/app/wiki.apd
@@ -0,0 +1,4 @@
+url: $baseurl/wiki/$nick
+requires: local_channel
+name: Wiki
+photo: $baseurl/app/wiki.png
diff --git a/app/wiki.png b/app/wiki.png
new file mode 100644
index 000000000..31d981679
Binary files /dev/null and b/app/wiki.png differ
diff --git a/boot.php b/boot.php
index 625bc39fa..94f1c5342 100755
--- a/boot.php
+++ b/boot.php
@@ -37,19 +37,18 @@ require_once('include/nav.php');
require_once('include/cache.php');
require_once('include/permissions.php');
require_once('library/Mobile_Detect/Mobile_Detect.php');
-require_once('include/BaseObject.php');
require_once('include/features.php');
require_once('include/taxonomy.php');
-require_once('include/identity.php');
-require_once('include/Contact.php');
+require_once('include/channel.php');
+require_once('include/connections.php');
require_once('include/account.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
-define ( 'STD_VERSION', '1.6.6' );
-define ( 'ZOT_REVISION', 1 );
+define ( 'STD_VERSION', '1.8' );
+define ( 'ZOT_REVISION', 1.1 );
-define ( 'DB_UPDATE_VERSION', 1168 );
+define ( 'DB_UPDATE_VERSION', 1176 );
/**
@@ -474,6 +473,7 @@ define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' );
* activity stream defines
*/
+define ( 'ACTIVITY_REACT', NAMESPACE_ZOT . '/activity/react' );
define ( 'ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like' );
define ( 'ACTIVITY_DISLIKE', NAMESPACE_ZOT . '/activity/dislike' );
define ( 'ACTIVITY_AGREE', NAMESPACE_ZOT . '/activity/agree' );
@@ -514,6 +514,7 @@ define ( 'ACTIVITY_OBJ_ALBUM', NAMESPACE_ACTIVITY_SCHEMA . 'photo-album' );
define ( 'ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event' );
define ( 'ACTIVITY_OBJ_GROUP', NAMESPACE_ACTIVITY_SCHEMA . 'group' );
define ( 'ACTIVITY_OBJ_GAME', NAMESPACE_ACTIVITY_SCHEMA . 'game' );
+define ( 'ACTIVITY_OBJ_WIKI', NAMESPACE_ACTIVITY_SCHEMA . 'wiki' );
define ( 'ACTIVITY_OBJ_TAGTERM', NAMESPACE_ZOT . '/activity/tagterm' );
define ( 'ACTIVITY_OBJ_PROFILE', NAMESPACE_ZOT . '/activity/profile' );
define ( 'ACTIVITY_OBJ_THING', NAMESPACE_ZOT . '/activity/thing' );
@@ -580,6 +581,72 @@ define ( 'ITEM_IS_STICKY', 1000 );
define ( 'DBTYPE_MYSQL', 0 );
define ( 'DBTYPE_POSTGRES', 1 );
+
+function sys_boot() {
+
+ // our central App object
+
+ App::init();
+
+ /*
+ * Load the configuration file which contains our DB credentials.
+ * Ignore errors. If the file doesn't exist or is empty, we are running in
+ * installation mode.
+ */
+
+ // miniApp is a conversion object from old style .htconfig.php files
+
+ $a = new miniApp;
+
+
+ App::$install = ((file_exists('.htconfig.php') && filesize('.htconfig.php')) ? false : true);
+
+ @include('.htconfig.php');
+
+ if(! defined('UNO'))
+ define('UNO', 0);
+
+ if(array_key_exists('default_timezone',get_defined_vars())) {
+ App::$config['system']['timezone'] = $default_timezone;
+ }
+
+ $a->convert();
+
+ App::$timezone = ((App::$config['system']['timezone']) ? App::$config['system']['timezone'] : 'UTC');
+ date_default_timezone_set(App::$timezone);
+
+
+ /*
+ * Try to open the database;
+ */
+
+ require_once('include/dba/dba_driver.php');
+
+ if(! App::$install) {
+ DBA::dba_factory($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type, App::$install);
+ if(! DBA::$dba->connected) {
+ system_unavailable();
+ }
+
+ unset($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type);
+
+ /**
+ * Load configs from db. Overwrite configs from .htconfig.php
+ */
+
+ load_config('config');
+ load_config('system');
+ load_config('feature');
+
+ App::$session = new Zotlabs\Web\Session();
+ App::$session->init();
+ load_hooks();
+ call_hooks('init_1');
+ }
+
+}
+
+
/**
*
* Reverse the effect of magic_quotes_gpc if it is enabled.
@@ -626,12 +693,25 @@ function startup() {
class ZotlabsAutoloader {
static public function loader($className) {
$filename = str_replace('\\', '/', $className) . ".php";
- if (file_exists($filename)) {
+ if(file_exists($filename)) {
include($filename);
if (class_exists($className)) {
return TRUE;
}
}
+ $arr = explode('\\',$className);
+ if($arr && count($arr) > 1) {
+ if(! $arr[0])
+ $arr = array_shift($arr);
+ $filename = 'addon/' . lcfirst($arr[0]) . '/' . $arr[1] . ((count($arr) === 2) ? '.php' : '/' . $arr[2] . ".php");
+ if(file_exists($filename)) {
+ include($filename);
+ if (class_exists($className)) {
+ return TRUE;
+ }
+ }
+ }
+
return FALSE;
}
}
@@ -687,6 +767,7 @@ class App {
private static $perms = null; // observer permissions
private static $widgets = array(); // widgets for this page
+ public static $session = null;
public static $groups;
public static $language;
public static $langsave;
@@ -703,6 +784,7 @@ class App {
public static $content;
public static $data = array();
public static $error = false;
+ public static $emojitab = false;
public static $cmd;
public static $argv;
public static $argc;
@@ -889,22 +971,28 @@ class App {
self::head_set_icon('/images/hz-32.png');
- BaseObject::set_app($this);
-
/*
* register template engines
*/
- $dc = get_declared_classes();
- foreach ($dc as $k) {
- if (in_array("ITemplateEngine", class_implements($k))){
- self::register_template_engine($k);
- }
- }
spl_autoload_register('ZotlabsAutoloader::loader');
self::$meta= new Zotlabs\Web\HttpMeta();
+ // create an instance of the smarty template engine so we can register it.
+
+ $smarty = new Zotlabs\Render\SmartyTemplate();
+
+ $dc = get_declared_classes();
+
+ foreach ($dc as $k) {
+ if(in_array('Zotlabs\\Render\\TemplateEngine', class_implements($k))) {
+ self::register_template_engine($k);
+ }
+ }
+
+
+
}
public static function get_baseurl($ssl = false) {
@@ -1057,7 +1145,7 @@ class App {
if(! self::$meta->get_field('og:title'))
self::$meta->set('og:title',self::$page['title']);
- self::$meta->set('generator', Zotlabs\Project\System::get_platform_name());
+ self::$meta->set('generator', Zotlabs\Lib\System::get_platform_name());
/* put the head template at the beginning of page['htmlhead']
* since the code added by the modules frequently depends on it
@@ -1072,7 +1160,7 @@ class App {
'$local_channel' => local_channel(),
'$metas' => self::$meta->get(),
'$update_interval' => $interval,
- 'osearch' => sprintf( t('Search %1$s (%2$s)','opensearch'), Zotlabs\Project\System::get_site_name(), t('$Projectname','opensearch')),
+ 'osearch' => sprintf( t('Search %1$s (%2$s)','opensearch'), Zotlabs\Lib\System::get_site_name(), t('$Projectname','opensearch')),
'$icon' => head_get_icon(),
'$head_css' => head_get_css(),
'$head_js' => head_get_js(),
@@ -1178,7 +1266,6 @@ class App {
* @return App
*/
function get_app() {
- global $a;
return $a;
}
@@ -1228,7 +1315,6 @@ function system_unavailable() {
function clean_urls() {
- global $a;
// if(App::$config['system']['clean_urls'])
return true;
@@ -1236,8 +1322,6 @@ function clean_urls() {
}
function z_path() {
- global $a;
-
$base = z_root();
if(! clean_urls())
$base .= '/?q=';
@@ -1253,7 +1337,6 @@ function z_path() {
* @return string
*/
function z_root() {
- global $a;
return App::get_baseurl();
}
@@ -1383,6 +1466,12 @@ function check_config(&$a) {
@unlink($lockfile);
//send the administrator an e-mail
file_put_contents($lockfile, $x);
+
+ $r = q("select account_language from account where account_email = '%s' limit 1",
+ dbesc(App::$config['system']['admin_email'])
+ );
+ push_lang(($r) ? $r[0]['account_language'] : 'en');
+
$email_tpl = get_intltext_template("update_fail_eml.tpl");
$email_msg = replace_macros($email_tpl, array(
@@ -1400,6 +1489,7 @@ function check_config(&$a) {
. 'Content-transfer-encoding: 8bit' );
//try the logger
logger('CRITICAL: Update Failed: ' . $x);
+ pop_lang();
}
else
set_config('database','update_r' . $x, 'success');
@@ -1442,11 +1532,11 @@ function check_config(&$a) {
if(count($installed)) {
foreach($installed as $i) {
- if(! in_array($i['name'], $plugins_arr)) {
- unload_plugin($i['name']);
+ if(! in_array($i['aname'], $plugins_arr)) {
+ unload_plugin($i['aname']);
}
else {
- $installed_arr[] = $i['name'];
+ $installed_arr[] = $i['aname'];
}
}
}
@@ -1556,7 +1646,7 @@ function fix_system_urls($oldurl, $newurl) {
}
}
- proc_run('php', 'include/notifier.php', 'refresh_all', $c[0]['channel_id']);
+ Zotlabs\Daemon\Master::Summon(array('Notifier', 'refresh_all', $c[0]['channel_id']));
}
}
@@ -1585,7 +1675,6 @@ function fix_system_urls($oldurl, $newurl) {
// returns the complete html for inserting into the page
function login($register = false, $form_id = 'main-login', $hiddens=false) {
- $a = get_app();
$o = '';
$reg = false;
$reglink = get_config('system', 'register_link');
@@ -1655,9 +1744,13 @@ function goaway($s) {
}
function shutdown() {
+<<<<<<< HEAD
global $db;
if(is_object($db) && $db->connected)
$db->close();
+=======
+
+>>>>>>> 1.8RC
}
/**
@@ -1691,7 +1784,9 @@ function get_account_id() {
* @return int|bool channel_id or false
*/
function local_channel() {
- if((x($_SESSION, 'authenticated')) && (x($_SESSION, 'uid')))
+ if(session_id()
+ && array_key_exists('authenticated',$_SESSION) && $_SESSION['authenticated']
+ && array_key_exists('uid',$_SESSION) && intval($_SESSION['uid']))
return intval($_SESSION['uid']);
return false;
@@ -1722,7 +1817,9 @@ function local_user() {
* @return string|bool visitor_id or false
*/
function remote_channel() {
- if((x($_SESSION, 'authenticated')) && (x($_SESSION, 'visitor_id')))
+ if(session_id()
+ && array_key_exists('authenticated',$_SESSION) && $_SESSION['authenticated']
+ && array_key_exists('visitor_id',$_SESSION) && $_SESSION['visitor_id'])
return $_SESSION['visitor_id'];
return false;
@@ -1747,7 +1844,9 @@ function remote_user() {
* @param string $s Text to display
*/
function notice($s) {
- $a = get_app();
+ if(! session_id())
+ return;
+
if(! x($_SESSION, 'sysmsg')) $_SESSION['sysmsg'] = array();
// ignore duplicated error messages which haven't yet been displayed
@@ -1771,8 +1870,10 @@ function notice($s) {
* @param string $s Text to display
*/
function info($s) {
- $a = get_app();
- if(! x($_SESSION, 'sysmsg_info')) $_SESSION['sysmsg_info'] = array();
+ if(! session_id())
+ return;
+ if(! x($_SESSION, 'sysmsg_info'))
+ $_SESSION['sysmsg_info'] = array();
if(App::$interactive)
$_SESSION['sysmsg_info'][] = $s;
}
@@ -1800,42 +1901,45 @@ function get_max_import_size() {
*
* $cmd and string args are surrounded with ""
*/
-function proc_run($cmd){
-
- $a = get_app();
+function proc_run(){
$args = func_get_args();
$newargs = array();
+
if(! count($args))
return;
- // expand any arrays
-
- foreach($args as $arg) {
- if(is_array($arg)) {
- foreach($arg as $n) {
- $newargs[] = $n;
- }
- }
- else
- $newargs[] = $arg;
- }
-
- $args = $newargs;
+ $args = flatten_array_recursive($args);
$arr = array('args' => $args, 'run_cmd' => true);
call_hooks('proc_run', $arr);
+
if(! $arr['run_cmd'])
return;
if(count($args) && $args[0] === 'php')
$args[0] = ((x(App::$config,'system')) && (x(App::$config['system'],'php_path')) && (strlen(App::$config['system']['php_path'])) ? App::$config['system']['php_path'] : 'php');
- for($x = 0; $x < count($args); $x++)
- $args[$x] = escapeshellarg($args[$x]);
+ // redirect proc_run statements of legacy daemon processes to the newer Daemon Master object class
+ // We will keep this interface until everybody has transitioned. (2016-05-20)
+
+ if(strstr($args[1],'include/')) {
+ // convert 'include/foo.php' to 'Foo'
+ $orig = substr(ucfirst(substr($args[1],8)),0,-4);
+ logger('proc_run_redirect: ' . $orig);
+ if(file_exists('Zotlabs/Daemon/' . $orig . '.php')) {
+ array_shift($args); // daemons are all run by php, pop it off the top of the array
+ $args[0] = $orig; // replace with the new daemon name
+ logger('Redirecting old proc_run interface: ' . print_r($args,true), LOGGER_DEBUG, LOG_DEBUG);
+ \Zotlabs\Daemon\Master::Summon($args); // summon the daemon
+ return;
+ }
+ }
+
+ $args = array_map('escapeshellarg',$args);
$cmdline = implode($args," ");
if(is_windows()) {
@@ -1855,110 +1959,15 @@ function proc_run($cmd){
* @brief Checks if we are running on M$ Windows.
*
* @return bool true if we run on M$ Windows
+ *
+ * It's possible you might be able to run on WAMP or XAMPP, and this
+ * has been accomplished, but is not officially supported. Good luck.
+ *
*/
function is_windows() {
return ((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true : false);
}
-
-function current_theme(){
- $app_base_themes = array('redbasic');
-
- $a = get_app();
- $page_theme = null;
-
- // Find the theme that belongs to the channel whose stuff we are looking at
-
- if(App::$profile_uid && App::$profile_uid != local_channel()) {
- $r = q("select channel_theme from channel where channel_id = %d limit 1",
- intval(App::$profile_uid)
- );
- if($r)
- $page_theme = $r[0]['channel_theme'];
- }
-
- if(array_key_exists('theme', App::$layout) && App::$layout['theme'])
- $page_theme = App::$layout['theme'];
-
- // Allow folks to over-rule channel themes and always use their own on their own site.
- // The default is for channel themes to take precedence over your own on pages belonging
- // to that channel.
-
- if($page_theme && local_channel() && App::$profile_uid && local_channel() != App::$profile_uid) {
- if(get_pconfig(local_channel(),'system','always_my_theme'))
- $page_theme = null;
- }
-
- $is_mobile = App::$is_mobile || App::$is_tablet;
-
- $standard_system_theme = ((isset(App::$config['system']['theme'])) ? App::$config['system']['theme'] : '');
- $standard_theme_name = ((isset($_SESSION) && x($_SESSION,'theme')) ? $_SESSION['theme'] : $standard_system_theme);
-
- if($is_mobile) {
- if(isset($_SESSION['show_mobile']) && !$_SESSION['show_mobile']) {
- $system_theme = $standard_system_theme;
- $theme_name = $standard_theme_name;
- }
- else {
- $system_theme = ((isset(App::$config['system']['mobile_theme'])) ? App::$config['system']['mobile_theme'] : '');
- $theme_name = ((isset($_SESSION) && x($_SESSION,'mobile_theme')) ? $_SESSION['mobile_theme'] : $system_theme);
-
- if($theme_name === '' || $theme_name === '---' ) {
- // user has selected to have the mobile theme be the same as the normal one
- $system_theme = $standard_system_theme;
- $theme_name = $standard_theme_name;
- }
- }
- }
- else {
- $system_theme = $standard_system_theme;
- $theme_name = $standard_theme_name;
-
- if($page_theme)
- $theme_name = $page_theme;
- }
-
- if($theme_name &&
- (file_exists('view/theme/' . $theme_name . '/css/style.css') ||
- file_exists('view/theme/' . $theme_name . '/php/style.php')))
- return($theme_name);
-
- foreach($app_base_themes as $t) {
- if(file_exists('view/theme/' . $t . '/css/style.css') ||
- file_exists('view/theme/' . $t . '/php/style.php'))
- return($t);
- }
-
- $fallback = array_merge(glob('view/theme/*/css/style.css'),glob('view/theme/*/php/style.php'));
- if(count($fallback))
- return (str_replace('view/theme/','', substr($fallback[0],0,-10)));
-
-}
-
-
-/**
- * @brief Return full URL to theme which is currently in effect.
- *
- * Provide a sane default if nothing is chosen or the specified theme does not exist.
- *
- * @param bool $installing default false
- *
- * @return string
- */
-function current_theme_url($installing = false) {
- global $a;
-
- $t = current_theme();
-
- $opts = '';
- $opts = ((App::$profile_uid) ? '?f=&puid=' . App::$profile_uid : '');
- $opts .= ((x(App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : '');
- if(file_exists('view/theme/' . $t . '/php/style.php'))
- return('view/theme/' . $t . '/php/style.pcss' . $opts);
-
- return('view/theme/' . $t . '/css/style.css');
-}
-
/**
* @brief Check if current user has admin role.
*
@@ -1966,8 +1975,11 @@ function current_theme_url($installing = false) {
*
* @return bool true if user is an admin
*/
+
function is_site_admin() {
- $a = get_app();
+
+ if(! session_id())
+ return false;
if($_SESSION['delegate'])
return false;
@@ -1988,7 +2000,10 @@ function is_site_admin() {
* @return bool true if user is a developer
*/
function is_developer() {
- $a = get_app();
+
+ if(! session_id())
+ return false;
+
if((intval($_SESSION['authenticated']))
&& (is_array(App::$account))
&& (App::$account['account_roles'] & ACCOUNT_ROLE_DEVELOPER))
@@ -1999,7 +2014,6 @@ function is_developer() {
function load_contact_links($uid) {
- $a = get_app();
$ret = array();
@@ -2008,7 +2022,7 @@ function load_contact_links($uid) {
// logger('load_contact_links');
- $r = q("SELECT abook_id, abook_flags, abook_my_perms, abook_their_perms, xchan_hash, xchan_photo_m, xchan_name, xchan_url from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d ",
+ $r = q("SELECT abook_id, abook_flags, abook_my_perms, abook_their_perms, xchan_hash, xchan_photo_m, xchan_name, xchan_url, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d ",
intval($uid)
);
if($r) {
@@ -2031,6 +2045,7 @@ function load_contact_links($uid) {
*
* @return string
*/
+
function build_querystring($params, $name = null) {
$ret = '';
foreach($params as $key => $val) {
@@ -2073,8 +2088,9 @@ function dba_timer() {
/**
* @brief Returns xchan_hash from the observer.
*
- * @return string Empty if no observer, otherwise xchan_hash from observer
+ * @return empty string if no observer, otherwise xchan_hash from observer
*/
+
function get_observer_hash() {
$observer = App::get_observer();
if(is_array($observer))
@@ -2131,8 +2147,6 @@ function load_pdl(&$a) {
App::$comanche = new Zotlabs\Render\Comanche();
- // require_once('include/comanche.php');
-
if (! count(App::$layout)) {
$arr = array('module' => App::$module, 'layout' => '');
@@ -2153,13 +2167,10 @@ function load_pdl(&$a) {
App::$pdl = $s;
}
}
-
}
function exec_pdl(&$a) {
-// require_once('include/comanche.php');
-
if(App::$pdl) {
App::$comanche->parse(App::$pdl,1);
}
@@ -2195,7 +2206,9 @@ function construct_page(&$a) {
}
}
- if (($p = theme_include(current_theme() . '.js')) != '')
+ $current_theme = Zotlabs\Render\Theme::current();
+
+ if (($p = theme_include($current_theme[0] . '.js')) != '')
head_add_js($p);
if (($p = theme_include('mod_' . App::$module . '.php')) != '')
@@ -2209,7 +2222,7 @@ function construct_page(&$a) {
head_add_css(((x(App::$page, 'template')) ? App::$page['template'] : 'default' ) . '.css');
head_add_css('mod_' . App::$module . '.css');
- head_add_css(current_theme_url($installing));
+ head_add_css(Zotlabs\Render\Theme::url($installing));
head_add_js('mod_' . App::$module . '.js');
@@ -2315,7 +2328,6 @@ function appdirpath() {
* @param string $icon
*/
function head_set_icon($icon) {
- global $a;
App::$data['pageicon'] = $icon;
// logger('head_set_icon: ' . $icon);
@@ -2327,7 +2339,6 @@ function head_set_icon($icon) {
* @return string absolut path to pageicon
*/
function head_get_icon() {
- global $a;
$icon = App::$data['pageicon'];
if(! strpos($icon, '://'))
@@ -2393,7 +2404,7 @@ function z_get_temp_dir() {
}
function z_check_cert() {
- $a = get_app();
+
if(strpos(z_root(),'https://') !== false) {
$x = z_fetch_url(z_root() . '/siteinfo/json');
if(! $x['success']) {
@@ -2414,8 +2425,6 @@ function z_check_cert() {
*/
function cert_bad_email() {
- $a = get_app();
-
$email_tpl = get_intltext_template("cert_bad_eml.tpl");
$email_msg = replace_macros($email_tpl, array(
'$sitename' => App::$config['system']['sitename'],
@@ -2436,26 +2445,30 @@ function cert_bad_email() {
*/
function check_cron_broken() {
- $t = get_config('system','lastpollcheck');
+ $d = get_config('system','lastcron');
+
+ if((! $d) || ($d < datetime_convert('UTC','UTC','now - 4 hours'))) {
+ Zotlabs\Daemon\Master::Summon(array('Cron'));
+ }
+
+ $t = get_config('system','lastcroncheck');
if(! $t) {
// never checked before. Start the timer.
- set_config('system','lastpollcheck',datetime_convert());
+ set_config('system','lastcroncheck',datetime_convert());
return;
}
+
if($t > datetime_convert('UTC','UTC','now - 3 days')) {
// Wait for 3 days before we do anything so as not to swamp the admin with messages
return;
}
- $d = get_config('system','lastpoll');
if(($d) && ($d > datetime_convert('UTC','UTC','now - 3 days'))) {
// Scheduled tasks have run successfully in the last 3 days.
- set_config('system','lastpollcheck',datetime_convert());
+ set_config('system','lastcroncheck',datetime_convert());
return;
}
- $a = get_app();
-
$email_tpl = get_intltext_template("cron_bad_eml.tpl");
$email_msg = replace_macros($email_tpl, array(
'$sitename' => App::$config['system']['sitename'],
@@ -2469,8 +2482,16 @@ function check_cron_broken() {
'From: Administrator' . '@' . App::get_hostname() . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
. 'Content-transfer-encoding: 8bit' );
- set_config('system','lastpollcheck',datetime_convert());
return;
}
+
+function observer_prohibited($allow_account = false) {
+
+ if($allow_account)
+ return (((get_config('system','block_public')) && (! get_account_id()) && (! remote_channel())) ? true : false );
+ return (((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) ? true : false );
+
+}
+
diff --git a/doc/Privacy.md b/doc/Privacy.md
index 511293c52..089977d7e 100644
--- a/doc/Privacy.md
+++ b/doc/Privacy.md
@@ -42,11 +42,11 @@ You MAY additionally provide other profile information. Any information which yo
Content you provide (status posts, photos, files, etc.) belongs to you. The $Projectname default is to publish content openly and visible to anybody on the internet (PUBLIC). You MAY control this in your channel settings and restrict the default permissions or you MAY restrict the visibility of any single published item separately (PRIVATE). $Projectname developers will ensure that restricted content is ONLY visible to those in the restriction list - to the best of their ability.
-Content (especially status posts) that you share with other networks or that you have made visible to anybody on the internet (PUBLIC) cannot easily be taken back once it has been published. It MAY be shared with other networks and made available through RSS/Atom feeds. It may also be syndicated on other $Projectname sites. It MAY appear on spy networks and internet searches. If you do not wish this default behaviour please adjust your channel settings and restrict who can see your content.
+Content (especially status posts) that you share with other networks or that you have made visible to anybody on the internet (PUBLIC) cannot easily be taken back once it has been published. It MAY be shared with other networks and made available through RSS/Atom feeds. It may also be syndicated on other $Projectname sites. It MAY appear on other networks and websites and be visible in internet searches. If you do not wish this default behaviour please adjust your channel settings and restrict who can see your content.
**Comments and Forum posts**
-Comments to posts that were created by others and posts which are designated as forum posts belong to you as the creator/author, but the distribution of these posts is not under your direct control. These posts/comments MAY be re-distributed to others, and MAY be visible to anybody on the internet. In the case of comments, the creator of the "first message" in the thread to which you are replying controls the distribution of all comments and replies to that message.
+Comments to posts that were created by others and posts which are designated as forum posts belong to you as the creator/author, but the distribution of these posts is not under your direct control, and you relinquish SOME rights to these items. These posts/comments MAY be re-distributed to others, and MAY be visible to anybody on the internet. In the case of comments, the creator of the "first message" in the thread (conversation) to which you are replying controls the distribution of all comments and replies to that message. They "own" and therefore have certain rights with regard to the entire conversation (including all comments contained within it). You can still edit or delete the comment, but the conversation owner also has rights to edit, delete, re-distribute, and backup/restore any or all the content from the conversation.
**Private Information**
diff --git a/doc/addons.bb b/doc/addons.bb
index 67282521f..b83b3276a 100644
--- a/doc/addons.bb
+++ b/doc/addons.bb
@@ -2,10 +2,12 @@
[list=1]
[*] abcjsplugin - Create musical scores in your posts
[*] adultphotoflag - prevents nsfw photos from being displayed in public albums
+[*] b2tbtn - provide button to go directly to top of page if you are scrolled a long way down
[*] bbmath - use complex math expressions in your posts
[*] bookmarker - replace #^ with bookmark link in posts
[*] buglink - provide a bug reporting icon in the lower-left corner of every page
[*] calc - a scientific calculator
+[*] cdav - CalDAV/CardDAV server
[*] chess - cross domain identity aware interactive chess games
[*] chords - generate fingering charts and alternatives for every known guitar chord
[*] custom_home - set a custom page as the hub start page
@@ -13,18 +15,24 @@
[*] diaspora - Diaspora protocol emulator
[*] diaspost - crosspost to a Diaspora account (different from the Diaspora protocol emulator)
[*] dirstats - show some interesting statistics generated by the driectory server
+[*] docs - alternate documentation pages
[*] donate - provides a project donation page
[*] dwpost - crosspost to Dreamwidth
+[*] embedphotos - tool to embed photos from your albums in a post
[*] extcron - use an external cron service to run your hub's scheduled tasks
[*] flattrwidget - provides a "Flattr Us" button
[*] flip - create upside down text
[*] fortunate - displays random quote (fortune cookie). Requires setting up a fortune server.
+[*] friendica - Friendica (DFRN) protocol. Under development.
[*] frphotos - import photo albums from Friendica
+[*] gnusoc - GNU-Social (OStatus) protocol. Under development.
[*] hexit - headecimal conversion tool
+[*] hubwall - send an admin email to all hub accounts
[*] ijpost - crosspost to Insanejournal
[*] irc - connect to IRC chatrooms
[*] jappixmini - XMPP chat
-[*] jsupload - (recommended) upload multiple photos to photo albums at once.
+[*] jsupload - upload multiple photos to photo albums at once.
+[*] keepout - prevents nearly all use of site when not logged in, more restrictive than 'block public' setting
[*] ldapauth - login via account on LDAP or Windows Active Directory domain
[*] libertree - crosspost to Libertree
[*] likebanner - create a "like us on red#matrix" banner image
@@ -32,6 +40,7 @@
[*] logrot - logfile rotation utility
[*] mahjongg - Chinese puzzle game
[*] mailhost - when using multiple channel clones, select one to receive email notifications
+[*] metatag - provide SEO friendly pages
[*] mayan_places - set location field to a random city in the Mayan world
[*] morechoice - additional gender/sexual-preference choices for profiles (not safe for work)
[*] moremoods - Additional mood options
@@ -60,6 +69,7 @@
[*] startpage - set a personal preferred page to redirect after logging in.
[*] statistics_json - Diaspora statistics generator
[*] statusnet - GNU-social and StatusNet crosspost [zrl=[baseurl]/help/addons_gnusocial]Posting To Gnu Social[/zrl]
+[*] std_embeds - allow unfiltered embeds for popular providers like youtube, vimeo and soundcloud
[*] superblock - Highly recommended - completely block an offensive channel from your stream
[*] testdrive - Turns your hub into a test drive site with accounts that expire after a trail period.
[*] tictac - 3D tic-tac-toe
@@ -76,6 +86,13 @@
[h3]Addon Repositories[/h3]
+We [b]strongly recommend[/b] that authors of addons publish/submit them to the project addon repository. This has several advantages. Project developers can easily fix security flaws and make changes to comply with recent changes in core code. Addons provided in third-party repositories are considered untrusted. If the project core code changes in an incompatible way, there may be no alternative but to physically remove or rename the addon files in order to get your site working again. Often only the plugin/addon author can help you regain control of your website, and project developers are unable to assist you; because by definition your site configuration has been modified in ways that we cannot easily test or verify.
+
+For these reasons we [b]strongly recommend[/b] that you do NOT install addons from third-party repositories.
+
+We also recognise that some developers prefer working on their own and do not wish their code to be mingled with the project repository for a variety of reasons. These developers can ease troubleshooting and debugging by providing a README file in their respective code repository outlining the process for submitting patches and bug fixes. It is also recommended that these projects provide both a 'dev' (development) and 'master' (production) branch which tracks the current project branches of those names. This is because dev and master are often not compatible from the viewpoint of library interfaces. It is also highly recommended that your repository versions are tagged and moved forward within 24 hours of project releases. This is a major inconvenience for everybdy involved, and can present downtime for production sites while this process is being carried out; which is one more reason why we [b]strongly recommend[/b] that addons be submitted to the project addon repository and that you do NOT install such third-party addons.
+
+
[url=https://github.com/redmatrix/hubzilla-addons]https://github.com/redmatrix/hubzilla-addons[/url] Main project addon repository
[url=https://github.com/23n/red-addons]https://github.com/23n/red-addons[/url] Oliver's repository (mayan_places and flip)
diff --git a/doc/bugs.bb b/doc/bugs.bb
index 1a27e66ba..f50337648 100644
--- a/doc/bugs.bb
+++ b/doc/bugs.bb
@@ -5,11 +5,6 @@
Hubzilla Community Server is open source software which is maintained by "the community" - essentially unpaid volunteers.
-[b]Hubzilla Enterprise Server[/b]
-
-Hubzilla Enterprise Server is commercial software with a variety of support plans depending on the specific license terms.
-
-
The first thing you need to do is talk to your hub administrator - the person who runs and manages your site. They are in the unique position of having access to the internal software and database and [b]logfiles[/b] and will need to be involved in fixing your problem. Other people "on the net" can't really help with this. The first thing the hub administrator needs to do is look at their logs and/or try to reproduce the problem. So try to be as helpful and courteous as possible in helping them look into the problem.
To find your hub administrator (if you don't know who they are) please look at [url=[baseurl]/siteinfo]this page[/url]. If they have not provided any contact info on that page or provided an "Impressum" there, see [url=[baseurl]/siteinfo/json]this site info summary[/url] under the heading "admin:".
@@ -24,13 +19,6 @@ If you get a blank white screen when doing something, this is almost always a co
[h3]I'm stumped. I can't figure out what is wrong.[/h3]
-[b]Hubzilla Enterprise Server[/b]
-
-Please make contact with the vendor - who will have provided you with support contact details. Preferably this contact will be made by the hub administrator so that he/she can assist us in collecting the necessary issue details. We will assign a ticket and notify you of progress.
-
-
-[b]Hubzilla Community Server[/b]
-
At this point it might be worthwhile discussing the issue on one of the online forums. There may be several of these and some may be more suited to your spoken language. As a last resort, try "Channel One", which is in English.
If the community developers can't help you right away, understand that they are volunteers and may have a lot of other work and demands on their time. At this point you need to file a bug report. You will need an account on github.com to do this. So register, and then visit https://github.com/redmatrix/hubzilla/issues
@@ -39,7 +27,5 @@ If the community developers can't help you right away, understand that they are
Then you wait. If it's a high profile issue, it may get fixed quickly. But nobody is in charge of fixing bugs. If it lingers without resolution, please spend some more time investigating the problem. Ask about anything you don't understand related to the behaviour. You will learn more about how the software works and quite possibly figure out why it isn't working now. Ultimately it is somebody in the community who is going to fix this and you are a member of the community; and this is how the open source process works.
-[b]In either case[/b]
-
-Other developers working to fix the problem may need to find out more, so do your homework and document what is happening and everything you've tried. Don't say "I did xyz and it didn't work." That doesn't tell us anything. Tell us precisely what steps you took and what you expected the result to be, and precisely what happened as a result. If there were any error messages, don't say "there was an error message". Tell us exactly what the message said.
+Other developers working to fix the problem may need to find out more, so do your homework and document what is happening and everything you've tried. Don't say "I did xyz and it didn't work." That doesn't tell us anything. Tell us precisely what steps you took and what you expected the result to be, and precisely what happened as a result. If there were any error messages, don't say "there was an error message". Tell us exactly what the message said. Tell us what version you're running and any other details that may be unique about your site configuration.
\ No newline at end of file
diff --git a/doc/ca/develop.bb b/doc/ca/develop.bb
index 7e82049c7..bc709963c 100644
--- a/doc/ca/develop.bb
+++ b/doc/ca/develop.bb
@@ -26,9 +26,6 @@
[zrl=[baseurl]/help/git_for_non_developers]Git per a No-Desenvolupadors[/zrl]
[zrl=[baseurl]/help/dev_beginner]Manual pas-a-pas per a desenvolupadors principiants[/zrl]
-[h3]Preguntes Més Freqüents (FAQ) Per Desenvolupadors[/h3]
-[zrl=[baseurl]/help/faq_developers]FAQ Per Desenvoupadors[/zrl]
-
[h3]Recursos Externs[/h3]
[url=https://zothub.com/channel/one]Development Channel[/url]
[url=https://federated.social/channel/postgres]Postgres-specific $Projectname Admin Support Channel[/url]
diff --git a/doc/classRedmatrix_1_1Import_1_1Import-members.html b/doc/classRedmatrix_1_1Import_1_1Import-members.html
deleted file mode 100644
index d5e2f9277..000000000
--- a/doc/classRedmatrix_1_1Import_1_1Import-members.html
+++ /dev/null
@@ -1,131 +0,0 @@
-
-
-
-
-
-
-The Hubzilla: Member List
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The Hubzilla
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
This is the complete list of members for Hubzilla\Import\Import , including all inherited members.
-
-
\ No newline at end of file
diff --git a/doc/classRedmatrix_1_1Import_1_1Import.html b/doc/classRedmatrix_1_1Import_1_1Import.html
deleted file mode 100644
index 9a7128d65..000000000
--- a/doc/classRedmatrix_1_1Import_1_1Import.html
+++ /dev/null
@@ -1,446 +0,0 @@
-
-
-
-
-
-
-The Hubzilla: Hubzilla\Import\Import Class Reference
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The Hubzilla
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::convert_child
- (
-
- $child )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::convert_item
- (
-
- $item_ident )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::convert_taxonomy
- (
-
- $item_ident )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::get_children
- (
-
- $item_ident )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::get_credentials
- (
- )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::get_item
- (
-
- $item_ident )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::get_item_ident
- (
-
- $item )
-
-
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::get_itemlist
- (
- )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::get_taxonomy
- (
-
- $item_ident )
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::run
- (
- )
-
-
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::store
- (
-
- $item ,
-
-
-
-
-
- $update = false
-
-
-
- )
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::$credentials = null
-
-
-
-
-private
-
-
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::$itemlist = null
-
-
-
-
-protected
-
-
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::$items = null
-
-
-
-
-protected
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Hubzilla\Import\Import::$src_items = null
-
-
-
-
-protected
-
-
-
-
-
-
-
The documentation for this class was generated from the following file:
-
-
\ No newline at end of file
diff --git a/doc/context/es b/doc/context/es
deleted file mode 120000
index 55914a5c4..000000000
--- a/doc/context/es
+++ /dev/null
@@ -1 +0,0 @@
-es-es/
\ No newline at end of file
diff --git a/doc/de/develop.bb b/doc/de/develop.bb
index 473b18b68..30e2954c6 100644
--- a/doc/de/develop.bb
+++ b/doc/de/develop.bb
@@ -25,9 +25,6 @@
[zrl=[baseurl]/help/git_for_non_developers]Git für Nicht-Entwickler[/zrl]
[zrl=[baseurl]/help/dev_beginner]Schritt-für-Schritt-Einführung für neue Entwickler[/zrl]
-[h3]Häufig gestellte Fragen für Entwickler[/h3]
-[zrl=[baseurl]/help/faq_developers]FAQ für Entwickler[/zrl]
-
[h3]Externe Ressourcen[/h3]
[url=https://zothub.com/channel/one]Entwickler-Kanal[/url]
[url=https://federated.social/channel/postgres]Postgres-spezifischer Admin-Support-Kanal[/url]
diff --git a/doc/develop.bb b/doc/develop.bb
index 56ba08421..ef3ea5bd0 100644
--- a/doc/develop.bb
+++ b/doc/develop.bb
@@ -26,9 +26,6 @@
[zrl=[baseurl]/help/git_for_non_developers]Git for Non-Developers[/zrl]
[zrl=[baseurl]/help/dev_beginner]Step-for-step manual for beginning developers[/zrl]
-[h3]Frequently Asked Questions For Developers[/h3]
-[zrl=[baseurl]/help/faq_developers]FAQ For Developers[/zrl]
-
[h3]External Resources[/h3]
[url=https://zothub.com/channel/one]Development Channel[/url]
[url=https://federated.social/channel/postgres]Postgres-specific $Projectname Admin Support Channel[/url]
diff --git a/doc/developer_function_primer.bb b/doc/developer_function_primer.bb
index 684fea569..183581361 100644
--- a/doc/developer_function_primer.bb
+++ b/doc/developer_function_primer.bb
@@ -12,10 +12,6 @@ Returns authenticated numeric channel_id if authenticated and connected to a cha
Returns authenticated string hash of Red global identifier, if authenticated via remote auth, or an empty string.
-[b]get_app()[/b]
-
-Returns the global app structure ($a).
-
[b]App::get_observer()[/b]
returns an xchan structure representing the current viewer if authenticated (locally or remotely).
diff --git a/doc/faq_developers.bb b/doc/faq_developers.bb
deleted file mode 100644
index 5da2c19ff..000000000
--- a/doc/faq_developers.bb
+++ /dev/null
@@ -1,454 +0,0 @@
-[size=large][b]Frequently Asked Questions For Developers[/b][/size]
-
-[toc]
-
-
-[h3]What does $a mean?[/h3]
-$a is a class defined in boot.php and passed all around $Projectname as a global reference variable. It defines everything necessary for the $Projectname application: Server variables, URL arguments, page structures, layouts, content, installed plugins, output device info, theme info, identity of the observer and (potential) page owner ...
-
-We don't ever create more than one instance and always modify the elements of the single instance. The mechanics of this are somewhat tricky. If you have a function that is passed $a and needs to modify $a you need to declare it as a reference with '&' e.g.
-
-[code]function foo(&$a) { App::$something = 'x'; // whatever };
-
-*or* access it within your function as a global variable via get_app()
-
-function foo() {
- $a = get_app();
- App::$something = 'x';
-}
-
-
-function foo($a) { App::$something = 'x'; };
-
-will *not* change the global app state.
-
-function foo() {
- App::$something = 'x';
-}
-[/code]
-
-
-An example (large) &$a object showing some of its many members and structures-- in JSON format for easier readability-- is here:
-
-[code] {
- "category": null,
- "nav_sel": {
- "home": null,
- "community": null,
- "contacts": null,
- "directory": null,
- "settings": null,
- "notifications": null,
- "intros": null,
- "messages": null,
- "register": null,
- "manage": null,
- "profiles": null,
- "network": null,
- "help": "active"
- },
- "argc": 2,
- "install": false,
- "is_mobile": false,
- "timezone": "America/Los_Angeles",
- "sourcename": "",
- "module_loaded": true,
- "contacts": null,
- "interactive": true,
- "config": {
- "system": {
- "max_import_size": 200000,
- "logfile": "/tmp/hubzilla.log",
- "channels_active_monthly_stat": "3",
- "last_expire_day": "4",
- "loglevel": "4",
- "sitename": "Hubzilla",
- "access_policy": 0,
- "directory_mode": 0,
- "debugging": "1",
- "verify_email": 1,
- "register_text": "",
- "urlverify": "687474703a2f2f6875627a696c6c61",
- "register_policy": 2,
- "theme": "redbasic",
- "smarty3_folder": "/home/src/hubzilla/store/[data]/smarty3",
- "channels_total_stat": "4",
- "admin_email": "foo@bar.com",
- "channels_active_halfyear_stat": "3",
- "location_hash": "910792b7bf75296cbf238ae29a5493f3c78805812652d3f0396e88763a26ce1b",
- "local_posts_stat": "63",
- "lastpollcheck": "2015-11-03 07:40:38",
- "baseurl": "http://hubzilla",
- "config_loaded": true,
- "pubkey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuR4neYAxuWwZg34fqofU\nZg8y1YSTX39Tzhgcgn7QFCeH600NHJBHWXbPdS5imdYq6W+P1vtKxsVNLI9d01+j\ns3MF3amgEuJH0X+JLLjyittQksyAiukvh/o4MSit8mcYcXs8Dxaybe+KaY09N4ys\ndxKcn6EPlthUiQPJMPitybp4vYkw9LupWZOQWThz9ur6T5wnk9ehBIPFN8gYvKrT\nAG9RFfbq3y59rTOiSHNA2PIUMzo2HEh4QBVCvVolKt7GPhUM4Bze40VRe8ELZTPp\nyehNxEHyhHZfnC+XRVNlvSPXBU2vtE+zcok+5DXsKAqMt8YgFIThNEOLQKvff/lv\nsdGvk6jJZok7+9lKtYfwnNnRWf51aVVuSAO3aIIVLroLyhiji0KA7G5YRHeF1rNL\np88e8peMyUMCX2Svv1wudJzqOfWSvOpY0NLZrdGZXRN2/rXyHPRD/TtS3SNDdd7J\nYQUjyxGjF1/zB3xqvPr09s8tzXqJl9pZNcN9iz58oPBbTuGdUr8CJro/3nVHgkRf\nw7/zhapSW1UaroJjecrC9yWx5QUD3KNU51phsP9iHCFdMyPBdUHjmNvE5f7YJWBh\nO1rRKUoE3i+eHLYAWeYblFX7T+EKOCB2hd3NUrIqDL98OSpfDiZT7rf9PdcWCOY5\nuddm6KzwHjffl5kZd8MM8bMCAwEAAQ==\n-----END PUBLIC KEY-----\n",
- "addon": "converse",
- "lastpoll": "2015-11-04 07:40:01",
- "php_path": "/usr/bin/php",
- "allowed_themes": "redbasic",
- "sellpage": "",
- "prvkey": "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n",
- "directory_server": "https://red.zottel.red",
- "curl_ssl_ciphers": "ALL:!eNULL",
- "db_version": "1158"
- },
- "config": {
- "config_loaded": true
- },
- "feature": {
- "config_loaded": true
- },
- "2": {
- "redbasic": {
- "schema": "dark",
- "comment_indent": "",
- "toolicon_activecolour": "",
- "item_colour": "",
- "nav_gradient_top": "",
- "nav_active_icon_colour": "",
- "nav_active_gradient_top": "",
- "top_photo": "",
- "converse_width": "",
- "nav_min_opacity": "",
- "body_font_size": "",
- "reply_photo": "",
- "background_colour": "",
- "radius": "",
- "nav_gradient_bottom": "",
- "toolicon_colour": "",
- "nav_active_gradient_bottom": "",
- "nav_icon_colour": "",
- "narrow_navbar": "",
- "nav_bg": "",
- "comment_item_colour": "",
- "config_loaded": true,
- "banner_colour": "",
- "comment_border_colour": "",
- "align_left": "",
- "font_size": "",
- "font_colour": "",
- "nav_bd": "",
- "photo_shadow": "",
- "background_image": "",
- "link_colour": ""
- },
- "system": {
- "network_list_mode": "0",
- "post_joingroup": "0",
- "channel_list_mode": "0",
- "title_tosource": "0",
- "blocktags": "0",
- "photo_path": "%Y-%m",
- "suggestme": "0",
- "autoperms": "0",
- "hide_presence": "0",
- "channel_divmore_height": "400",
- "network_divmore_height": "400",
- "post_profilechange": "0",
- "channel_menu": "",
- "always_show_in_notices": "0",
- "use_browser_location": "0",
- "update_interval": "80000",
- "itemspage": "20",
- "attach_path": "%Y-%m",
- "permissions_role": "social",
- "vnotify": "2047",
- "post_newfriend": "0",
- "config_loaded": true,
- "no_smilies": "0",
- "evdays": "3",
- "user_scalable": "1"
- }
- }
- },
- "layout": {
- "region_aside": "\n<div class="widget"><h3>Documentation</h3><ul class="nav nav-pills nav-stacked"><li><a href="help/general">Project/Site Information</a></li><li><a href="help/members">For Members</a></li><li><a href="help/admins">For Administrators</a></li><li><a href="help/develop">For Developers</a></li></ul></div>\n"
- },
- "is_sys": false,
- "content": null,
- "cid": null,
- "profile_uid": 0,
- "hooks": {
- "construct_page": [
- [
- "addon/converse/converse.php",
- "converse_content"
- ]
- ]
- },
- "strings": [],
- "js_sources": [
- "jquery.js",
- "library/justifiedGallery/jquery.justifiedGallery.min.js",
- "library/sprintf.js/dist/sprintf.min.js",
- "spin.js",
- "jquery.spin.js",
- "jquery.textinputs.js",
- "autocomplete.js",
- "library/jquery-textcomplete/jquery.textcomplete.js",
- "library/jquery.timeago.js",
- "library/readmore.js/readmore.js",
- "library/jgrowl/jquery.jgrowl_minimized.js",
- "library/cryptojs/components/core-min.js",
- "library/cryptojs/rollups/aes.js",
- "library/cryptojs/rollups/rabbit.js",
- "library/cryptojs/rollups/tripledes.js",
- "acl.js",
- "webtoolkit.base64.js",
- "main.js",
- "crypto.js",
- "library/jRange/jquery.range.js",
- "library/colorbox/jquery.colorbox-min.js",
- "library/jquery.AreYouSure/jquery.are-you-sure.js",
- "library/tableofcontents/jquery.toc.js",
- "library/bootstrap/js/bootstrap.min.js",
- "library/bootbox/bootbox.min.js",
- "library/bootstrap-tagsinput/bootstrap-tagsinput.js",
- "library/datetimepicker/jquery.datetimepicker.js",
- "library/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js",
- "view/theme/redbasic/js/redbasic.js",
- "mod_help.js"
- ],
- "channel": {
- "channel_hash": "uRy0nF-urp6k_bFrkdtCc2EkBynwpgCJL_FQFoTwyw2Hep7AHkrSt1MZcHWV_8DQucNlHSY1vHgUNS2Fvoirpw",
- "channel_address": "testes",
- "channel_primary": "1",
- "channel_allow_gid": "",
- "xchan_deleted": "0",
- "xchan_connpage": "",
- "channel_r_storage": "1",
- "xchan_pubforum": "0",
- "channel_pubkey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7MP/xxsq/srA8I7m+WKf\nHlguwwg0b1tz+I3o+djp7b+wF8q03XPKQpYmKfXIj47vpAOu75nKA4Tn90lLymmk\nSXUHogOqOMy1CHoaVrAw2T2/tAeRoMAjAJ5IxSOAM7Xda0nVUK6FmfxPcvftKf9y\nPmvvFadXpaHT4JGPH0tszDhGXLkqlt9xSkIkpsgMA6emj/7bacc6x8eTdtvzo2e5\n/NyPXvBKH4henmYaKjq/4aIYZcBWYVGt6onxaP2j1cSNbksnOY7GbJl+hy95iFoZ\nDWGxiFwQd+CroiBbdlpVGp13cV/WKp2spZzlzkmCRGYoNbbM5RlgFLnmyTa4XMZE\nwnA3ZUB59MsrUJK+0H/utiZrpX5NQcFl33z8k5zB3pPnhc5S5/P+UJZRnqhet1wQ\n7AZVmdP30D75QD8LZ4SytZ1DHn/N76EsVhSADNMnUfEphs708V33Z0gFWultYDoK\nlvXUf4O0/V8GTufFHb6XdAiy92IUzrormXCpXoOmdOcJdaH9RnotZi/DkuQ0zP+Y\nCvxU9nrjyZvAwAdew//XFDjw4HoThVM4k4jzkIhCTlCao/yRnNM7A/i3OKcXq9wU\n7OZqcRfM9o0BFpZTIoXB7BMtpeioJcBi/7FUaV9U9uYLFuLL0qWa1YxLwfsN9rDk\n6A1gbhD60G9/dAbolp8xAHkCAwEAAQ==\n-----END PUBLIC KEY-----\n",
- "xchan_flags": "0",
- "channel_allow_cid": "",
- "xchan_censored": "0",
- "channel_w_pages": "128",
- "xchan_instance_url": "",
- "xchan_photo_s": "http://hubzilla/photo/profile/s/2",
- "channel_w_stream": "128",
- "channel_timezone": "America/Los_Angeles",
- "xchan_pubkey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7MP/xxsq/srA8I7m+WKf\nHlguwwg0b1tz+I3o+djp7b+wF8q03XPKQpYmKfXIj47vpAOu75nKA4Tn90lLymmk\nSXUHogOqOMy1CHoaVrAw2T2/tAeRoMAjAJ5IxSOAM7Xda0nVUK6FmfxPcvftKf9y\nPmvvFadXpaHT4JGPH0tszDhGXLkqlt9xSkIkpsgMA6emj/7bacc6x8eTdtvzo2e5\n/NyPXvBKH4henmYaKjq/4aIYZcBWYVGt6onxaP2j1cSNbksnOY7GbJl+hy95iFoZ\nDWGxiFwQd+CroiBbdlpVGp13cV/WKp2spZzlzkmCRGYoNbbM5RlgFLnmyTa4XMZE\nwnA3ZUB59MsrUJK+0H/utiZrpX5NQcFl33z8k5zB3pPnhc5S5/P+UJZRnqhet1wQ\n7AZVmdP30D75QD8LZ4SytZ1DHn/N76EsVhSADNMnUfEphs708V33Z0gFWultYDoK\nlvXUf4O0/V8GTufFHb6XdAiy92IUzrormXCpXoOmdOcJdaH9RnotZi/DkuQ0zP+Y\nCvxU9nrjyZvAwAdew//XFDjw4HoThVM4k4jzkIhCTlCao/yRnNM7A/i3OKcXq9wU\n7OZqcRfM9o0BFpZTIoXB7BMtpeioJcBi/7FUaV9U9uYLFuLL0qWa1YxLwfsN9rDk\n6A1gbhD60G9/dAbolp8xAHkCAwEAAQ==\n-----END PUBLIC KEY-----\n",
- "channel_w_chat": "128",
- "xchan_connurl": "http://hubzilla/poco/testes",
- "channel_guid_sig": "XXX",
- "xchan_name_date": "2015-10-09 00:45:41",
- "channel_expire_days": "0",
- "xchan_system": "0",
- "xchan_photo_date": "2015-10-09 00:45:41",
- "channel_startpage": "",
- "channel_deny_gid": "",
- "channel_lastpost": "2015-10-09 02:53:23",
- "xchan_photo_m": "http://hubzilla/photo/profile/m/2",
- "channel_passwd_reset": "",
- "xchan_hidden": "0",
- "xchan_selfcensored": "0",
- "xchan_photo_mimetype": "image/jpeg",
- "channel_a_republish": "128",
- "channel_w_tagwall": "128",
- "channel_r_stream": "1",
- "channel_w_comment": "128",
- "channel_system": "0",
- "channel_w_mail": "128",
- "channel_pageflags": "0",
- "xchan_network": "zot",
- "channel_id": "2",
- "xchan_guid": "Ok-ycNKQYMzjokLnIz5OTCF8M5f4CtRT4vJCUeUivJhIOJWk3ORwIQgGx3P5g2Yz79KxQ-rs_Cn2G_jsgM6hmw",
- "channel_removed": "0",
- "channel_dirdate": "2015-10-09 00:46:00",
- "channel_w_storage": "128",
- "channel_w_photos": "0",
- "channel_prvkey": "-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n",
- "channel_guid": "Ok-ycNKQYMzjokLnIz5OTCF8M5f4CtRT4vJCUeUivJhIOJWk3ORwIQgGx3P5g2Yz79KxQ-rs_Cn2G_jsgM6hmw",
- "channel_max_friend_req": "0",
- "channel_w_wall": "128",
- "channel_r_abook": "1",
- "channel_max_anon_mail": "0",
- "channel_location": "",
- "channel_a_delegate": "128",
- "channel_deny_cid": "",
- "channel_r_profile": "1",
- "channel_name": "testes",
- "xchan_guid_sig": "XXX",
- "xchan_hash": "uRy0nF-urp6k_bFrkdtCc2EkBynwpgCJL_FQFoTwyw2Hep7AHkrSt1MZcHWV_8DQucNlHSY1vHgUNS2Fvoirpw",
- "channel_notifyflags": "703",
- "channel_theme": "redbasic",
- "channel_w_like": "2",
- "xchan_url": "http://hubzilla/channel/testes",
- "channel_default_group": "",
- "channel_r_photos": "0",
- "channel_account_id": "1",
- "xchan_addr": "testes@hubzilla",
- "channel_r_pages": "1",
- "channel_deleted": "0000-00-00 00:00:00",
- "xchan_orphan": "0",
- "xchan_follow": "http://hubzilla/follow?f=&url=%s",
- "xchan_name": "testes",
- "xchan_photo_l": "http://hubzilla/photo/profile/l/2"
- },
- "page": {
- "content": "<div id="help-content" class="generic-content-wrapper">\n\t<div class="section-title-wrapper">\n\t<h2>Hubzilla Documentation</h2>\n\t</div>\n\t<div class="section-content-wrapper">\n\t<h2>Documentation for Developers</h2><br /><br /><h3>Technical Documentation</h3><br /><a class="zrl" href="http://hubzilla/help/Zot---A-High-Level-Overview" target="_blank" >A high level overview of Zot</a><br /><a class="zrl" href="http://hubzilla/help/zot" target="_blank" >An introduction to Zot</a><br /><a class="zrl" href="http://hubzilla/help/zot_structures" target="_blank" >Zot Stuctures</a><br /><a class="zrl" href="http://hubzilla/help/comanche" target="_blank" >Comanche Page Descriptions</a><br /><a class="zrl" href="http://hubzilla/help/Creating-Templates" target="_blank" >Creating Comanche Templates</a><br /><a class="zrl" href="http://hubzilla/help/Widgets" target="_blank" >Widgets</a><br /><a class="zrl" href="http://hubzilla/help/plugins" target="_blank" >Plugins</a><br /><a class="zrl" href="http://hubzilla/help/hooks" target="_blank" >Hooks</a><br /><a class="zrl" href="http://hubzilla/help/doco" target="_blank" >Contributing Documentation</a><br /><a class="zrl" href="http://hubzilla/help/DerivedTheme1" target="_blank" >Creating Derivative Themes</a><br /><a class="zrl" href="http://hubzilla/help/schema_development" target="_blank" >Schemas</a><br /><a class="zrl" href="http://hubzilla/help/Translations" target="_blank" >Translations</a><br /><a class="zrl" href="http://hubzilla/help/developers" target="_blank" >Developers</a><br /><a class="zrl" href="http://hubzilla/help/intro_for_developers" target="_blank" >Intro for Developers</a><br /><a class="zrl" href="http://hubzilla/help/database" target="_blank" >Database schema documentation</a><br /><a class="zrl" href="http://hubzilla/help/api_functions" target="_blank" >API functions</a><br /><a class="zrl" href="http://hubzilla/help/api_posting" target="_blank" >Posting to the red# using the API</a><br /><a class="zrl" href="http://hubzilla/help/developer_function_primer" target="_blank" >Red Functions 101</a><br /><a class="zrl" href="http://hubzilla/doc/html/" target="_blank" >Code Reference (Doxygen generated - sets cookies)</a><br /><a class="zrl" href="http://hubzilla/help/to_do_doco" target="_blank" >To-Do list for the Red Documentation Project</a><br /><a class="zrl" href="http://hubzilla/help/to_do_code" target="_blank" >To-Do list for Developers</a><br /><a class="zrl" href="http://hubzilla/help/roadmap" target="_blank" >Version 3 roadmap</a><br /><a class="zrl" href="http://hubzilla/help/git_for_non_developers" target="_blank" >Git for Non-Developers</a><br /><a class="zrl" href="http://hubzilla/help/dev_beginner" target="_blank" >Step-for-step manual for beginning developers</a><br /><br /><h3>Frequently Asked Questions For Developers</h3><br /><a class="zrl" href="http://hubzilla/help/faq_developers" target="_blank" >FAQ For Developers</a><br /><br /><h3>External Resources</h3><br /><br /><a href="https://zothub.com/channel/one" target="_blank" >Development Channel</a><br /><a href="https://federated.social/channel/postgres" target="_blank" >Postgres-specific Hubzilla Admin Support Channel</a><br />\n\t</div>\n</div>\n<script>var homebase = "http://hubzilla/channel/testes";</script>",
- "page_title": "help",
- "title": "Help: Develop",
- "nav": "\t<div class="container-fluid">\n\t\t<div class="navbar-header">\n\t\t\t<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse-1">\n\t\t\t\t<span class="icon-bar"></span>\n\t\t\t\t<span class="icon-bar"></span>\n\t\t\t\t<span class="icon-bar"></span>\n\t\t\t</button>\n\t\t\t<button id="expand-tabs" type="button" class="navbar-toggle" data-toggle="collapse" data-target="#tabs-collapse-1">\n\t\t\t\t<i class="icon-circle-arrow-down" id="expand-tabs-icon"></i>\n\t\t\t</button>\n\t\t\t<button id="expand-aside" type="button" class="navbar-toggle" data-toggle="offcanvas" data-target="#region_1">\n\t\t\t\t<i class="icon-circle-arrow-right" id="expand-aside-icon"></i>\n\t\t\t</button>\n\t\t\t\t\t\t\t<img class="dropdown-toggle fakelink" data-toggle="dropdown" id="avatar" src="http://hubzilla/photo/profile/m/2" alt="testes@hubzilla"><span class="caret" id="usermenu-caret"></span>\n\t\t\t\t\t\t\t\t\t<ul class="dropdown-menu" role="menu" aria-labelledby="avatar">\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation"><a href="channel/testes" title="Your posts and conversations" role="menuitem" id="channel_nav_btn">Home</a></li>\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation"><a href="profile/testes" title="Your profile page" role="menuitem" id="profile_nav_btn">View Profile</a></li>\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation"><a href="profiles/2" title="Edit your profile" role="menuitem" id="profiles_nav_btn">Edit Profile</a></li>\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation"><a href="photos/testes" title="Your photos" role="menuitem" id="photos_nav_btn">Photos</a></li>\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation"><a href="cloud/testes" title="Your files" role="menuitem" id="cloud_nav_btn">Files</a></li>\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation"><a href="chat/testes/new" title="Your chatrooms" role="menuitem" id="chat_nav_btn">Chat</a></li>\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation" class="divider"></li>\n\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation"><a href="settings" title="Account/Channel Settings" role="menuitem" id="settings_nav_btn">Settings</a></li>\t\t\t\t\t\t<li role="presentation"><a href="manage" title="Manage Your Channels" role="menuitem" id="manage_nav_btn">Channel Manager</a></li>\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation" class="divider"></li>\n\t\t\t\t\t\t<li role="presentation"><a href="admin/" title="Site Setup and Configuration" role="menuitem" id="admin_nav_btn">Admin</a></li>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<li role="presentation" class="divider"></li>\n\t\t\t\t\t\t<li role="presentation"><a href="logout" title="End this session" role="menuitem" id="logout_nav_btn">Logout</a></li>\n\t\t\t\t\t\t\t\t\t\t\t</ul>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t<div class="collapse navbar-collapse" id="navbar-collapse-1">\n\t\t\t<ul class="nav navbar-nav navbar-left">\n\t\t\t\t\t\t\n\t\t\t\n\t\t\t\t\t\t\t<li class=" hidden-xs">\n\t\t\t\t\t<a href="network" title="Your grid" id="network_nav_btn"><i class="icon-th"></i></a>\n\t\t\t\t\t<span class="net-update badge dropdown-toggle" data-toggle="dropdown" rel="#nav-network-menu"></span>\n\t\t\t\t\t<ul id="nav-network-menu" role="menu" class="dropdown-menu" rel="network">\n\t\t\t\t\t\t\n\t\t\t\t\t\t<li id="nav-network-mark-all"><a href="#" onclick="markRead('network'); return false;">Mark all grid notifications seen</a></li>\n\t\t\t\t\t\t<li class="empty">Loading...</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t\t<li class=" visible-xs">\n\t\t\t\t\t<a href="network" title="Your grid" ><i class="icon-th"></i></a>\n\t\t\t\t\t<span class="net-update badge" rel="#nav-network-menu"></span>\n\t\t\t\t</li>\n\t\t\t\n\t\t\t\t\t\t\t<li class=" hidden-xs">\n\t\t\t\t\t<a class="" href="channel/testes" title="Channel home" id="home_nav_btn"><i class="icon-home"></i></a>\n\t\t\t\t\t<span class="home-update badge dropdown-toggle" data-toggle="dropdown" rel="#nav-home-menu"></span>\n\t\t\t\t\t<ul id="nav-home-menu" class="dropdown-menu" rel="home">\n\t\t\t\t\t\t\n\t\t\t\t\t\t<li id="nav-home-mark-all"><a href="#" onclick="markRead('home'); return false;">Mark all channel notifications seen</a></li>\n\t\t\t\t\t\t<li class="empty">Loading...</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t\t<li class=" visible-xs">\n\t\t\t\t\t<a class="" href="channel/testes" title="Channel home" ><i class="icon-home"></i></a>\n\t\t\t\t\t<span class="home-update badge" rel="#nav-home-menu"></span>\n\t\t\t\t</li>\n\t\t\t\n\n\t\t\t\t\t\t\t<li class=" hidden-xs">\n\t\t\t\t\t<a class="" href="mail/combined" title="Private mail" id="mail_nav_btn"><i class="icon-envelope"></i></a>\n\t\t\t\t\t<span class="mail-update badge dropdown-toggle" data-toggle="dropdown" rel="#nav-messages-menu"></span>\n\t\t\t\t\t<ul id="nav-messages-menu" class="dropdown-menu" rel="messages">\n\t\t\t\t\t\t<li id="nav-messages-see-all"><a href="mail/combined">See all private messages</a></li>\n\t\t\t\t\t\t<li id="nav-messages-mark-all"><a href="#" onclick="markRead('messages'); return false;">Mark all private messages seen</a></li>\n\t\t\t\t\t\t<li class="empty">Loading...</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t\t<li class=" visible-xs">\n\t\t\t\t\t<a class="" href="mail/combined" title="Private mail" ><i class="icon-envelope"></i></a>\n\t\t\t\t\t<span class="mail-update badge" rel="#nav-messages-menu"></span>\n\t\t\t\t</li>\n\t\t\t\n\t\t\t\t\t\t\t<li class=" hidden-xs">\n\t\t\t\t\t<a class="" href="events" title="Event Calendar" id='events_nav_btn'><i class="icon-calendar"></i></a>\n\t\t\t\t\t<span class="all_events-update badge dropdown-toggle" data-toggle="dropdown" rel="#nav-all_events-menu"></span>\n\t\t\t\t\t<ul id="nav-all_events-menu" class="dropdown-menu" rel="all_events">\n\t\t\t\t\t\t<li id="nav-all_events-see-all"><a href="events">See all events</a></li>\n\t\t\t\t\t\t<li id="nav-all_events-mark-all"><a href="#" onclick="markRead('all_events'); return false;">Mark all events seen</a></li>\n\t\t\t\t\t\t<li class="empty">Loading...</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t\t<li class=" visible-xs">\n\t\t\t\t\t<a class="" href="events" title="Event Calendar" ><i class="icon-calendar"></i></a>\n\t\t\t\t\t<span class="all_events-update badge" rel="#nav-all_events-menu"></span>\n\t\t\t\t</li>\n\t\t\t\n\t\t\t\t\t\t\t<li class=" hidden-xs">\n\t\t\t\t\t<a class="" href="connections/ifpending" title="Connections" id="connections_nav_btn"><i class="icon-user"></i></a>\n\t\t\t\t\t<span class="intro-update badge dropdown-toggle" data-toggle="dropdown" rel="#nav-intros-menu"></span>\n\t\t\t\t\t<ul id="nav-intros-menu" class="dropdown-menu" rel="intros">\n\t\t\t\t\t\t<li id="nav-intros-see-all"><a href=""></a></li>\n\t\t\t\t\t\t<li class="empty">Loading...</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t\t<li class=" visible-xs">\n\t\t\t\t\t<a class="" href="connections/ifpending" title="Connections" ><i class="icon-user"></i></a>\n\t\t\t\t\t<span class="intro-update badge" rel="#nav-intros-menu"></span>\n\t\t\t\t</li>\n\t\t\t\t\t\n\t\t\t\t\t\t\t<li class=" hidden-xs">\n\t\t\t\t\t<a href="notifications/system" title="Notices" id="notifications_nav_btn"><i class="icon-exclamation"></i></a>\n\t\t\t\t\t<span class="notify-update badge dropdown-toggle" data-toggle="dropdown" rel="#nav-notify-menu"></span>\n\t\t\t\t\t<ul id="nav-notify-menu" class="dropdown-menu" rel="notify">\n\t\t\t\t\t\t<li id="nav-notify-see-all"><a href="notifications/system">See all notifications</a></li>\n\t\t\t\t\t\t<li id="nav-notify-mark-all"><a href="#" onclick="markRead('notify'); return false;">Mark all system notifications seen</a></li>\n\t\t\t\t\t\t<li class="empty">Loading...</li>\n\t\t\t\t\t</ul>\n\t\t\t\t</li>\n\t\t\t\t<li class=" visible-xs">\n\t\t\t\t\t<a href="notifications/system" title="Notices"><i class="icon-exclamation"></i></a>\n\t\t\t\t\t<span class="notify-update badge" rel="#nav-notify-menu"></span>\n\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t\t<ul class="nav navbar-nav navbar-right">\n\t\t\t\t<li class="hidden-xs">\n\t\t\t\t\t<form method="get" action="search" role="search">\n\t\t\t\t\t\t<div id="nav-search-spinner"></div><input class="icon-search" id="nav-search-text" type="text" value="" placeholder=" @name, #tag, ?doc, content" name="search" title="Search site @name, #tag, ?docs, content" onclick="this.submit();"/>\n\t\t\t\t\t</form>\n\t\t\t\t</li>\n\t\t\t\t<li class="visible-xs">\n\t\t\t\t\t<a href="/search" title="Search site @name, #tag, ?docs, content"><i class="icon-search"></i></a>\n\t\t\t\t</li>\n\n\t\t\t\t\t\t\t\t\t\t<li class="">\n\t\t\t\t\t<a class="" href="directory" title="Channel Directory" id="directory_nav_btn"><i class="icon-sitemap"></i></a>\n\t\t\t\t</li>\n\t\t\t\n\t\t\t\t\t\t\t<li class="">\n\t\t\t\t\t<a class="" href="apps" title="Applications, utilities, links, games" id="apps_nav_btn"><i class="icon-cogs"></i></a>\n\t\t\t\t</li>\n\t\t\t\n\t\t\t\t\t\t\t<li class="active">\n\t\t\t\t\t<a class="" target="hubzilla-help" href="http://hubzilla/help?f=&cmd=help/develop" title="Help and documentation" id="help_nav_btn"><i class="icon-question"></i></a>\n\t\t\t\t</li>\n\t\t\t\t\t\t</ul>\n\t\t</div>\n\t</div>\n",
- "htmlhead": "<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />\n<base href="http://hubzilla/" />\n<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, user-scalable=1" />\n<meta name="generator" content="hubzilla 2015-11-03.1205H" />\n\n<!--[if IE]>\n<script src="http://hubzilla/library/html5.js"></script>\n<![endif]-->\n\n<link rel="stylesheet" href="http://hubzilla/library/font_awesome/css/font-awesome.min.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/bootstrap/css/bootstrap.min.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/bootstrap-tagsinput/bootstrap-tagsinput.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/view/css/bootstrap-red.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/datetimepicker/jquery.datetimepicker.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/tiptip/tipTip.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/jgrowl/jquery.jgrowl.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/jRange/jquery.range.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/view/css/conversation.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/view/css/widgets.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/view/css/colorbox.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/library/justifiedGallery/justifiedGallery.min.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/view/css/default.css" type="text/css" media="screen">\r\n<link rel="stylesheet" href="http://hubzilla/view/theme/redbasic/php/style.pcss" type="text/css" media="screen">\r\n\n\n<script>\n\n\tvar aStr = {\n\n\t\t'delitem' : "Delete this item?",\n\t\t'comment' : "Comment",\n\t\t'showmore' : "[+] show all",\n\t\t'showfewer' : "[-] show less",\n\t\t'divgrowmore' : "[+] expand",\n\t\t'divgrowless' : "[-] collapse",\n\t\t'pwshort' : "Password too short",\n\t\t'pwnomatch' : "Passwords do not match",\n\t\t'everybody' : "everybody",\n\t\t'passphrase' : "Secret Passphrase",\n\t\t'passhint' : "Passphrase hint",\n\t\t'permschange' : "Notice: Permissions have changed but have not yet been submitted.",\n\t\t'closeAll' : "close all",\n\t\t'nothingnew' : "Nothing new here",\n\t\t'rating_desc' : "Rate This Channel (this is public)",\n\t\t'rating_val' : "Rating",\n\t\t'rating_text' : "Describe (optional)",\n\t\t'submit' : "Submit",\n\t\t'linkurl' : "Please enter a link URL",\n\t\t'leavethispage' : "Unsaved changes. Are you sure you wish to leave this page?",\n\n\t\t't01' : "",\n\t\t't02' : "",\n\t\t't03' : "ago",\n\t\t't04' : "from now",\n\t\t't05' : "less than a minute",\n\t\t't06' : "about a minute",\n\t\t't07' : "%d minutes",\n\t\t't08' : "about an hour",\n\t\t't09' : "about %d hours",\n\t\t't10' : "a day",\n\t\t't11' : "%d days",\n\t\t't12' : "about a month",\n\t\t't13' : "%d months",\n\t\t't14' : "about a year",\n\t\t't15' : "%d years",\n\t\t't16' : " ",\n\t\t't17' : "[]",\n\n\t\t'monthNames' : [ "January","February","March","April","May","June","July","August","September","October","November","December" ],\n\t\t'monthNamesShort' : [ "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" ],\n\t\t'dayNames' : ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],\n\t\t'dayNamesShort' : ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],\n\t\t'today' : "today",\n\t\t'month' : "month",\n\t\t'week' : "week",\n\t\t'day' : "day",\n\t\t'allday' : "All day"\n\t};\n\n</script>\n\t\t\n\n\n<script src="http://hubzilla/view/js/jquery.js" ></script>\r\n<script src="http://hubzilla/library/justifiedGallery/jquery.justifiedGallery.min.js" ></script>\r\n<script src="http://hubzilla/library/sprintf.js/dist/sprintf.min.js" ></script>\r\n<script src="http://hubzilla/view/js/spin.js" ></script>\r\n<script src="http://hubzilla/view/js/jquery.spin.js" ></script>\r\n<script src="http://hubzilla/view/js/jquery.textinputs.js" ></script>\r\n<script src="http://hubzilla/view/js/autocomplete.js" ></script>\r\n<script src="http://hubzilla/library/jquery-textcomplete/jquery.textcomplete.js" ></script>\r\n<script src="http://hubzilla/library/jquery.timeago.js" ></script>\r\n<script src="http://hubzilla/library/readmore.js/readmore.js" ></script>\r\n<script src="http://hubzilla/library/jgrowl/jquery.jgrowl_minimized.js" ></script>\r\n<script src="http://hubzilla/library/cryptojs/components/core-min.js" ></script>\r\n<script src="http://hubzilla/library/cryptojs/rollups/aes.js" ></script>\r\n<script src="http://hubzilla/library/cryptojs/rollups/rabbit.js" ></script>\r\n<script src="http://hubzilla/library/cryptojs/rollups/tripledes.js" ></script>\r\n<script src="http://hubzilla/view/js/acl.js" ></script>\r\n<script src="http://hubzilla/view/js/webtoolkit.base64.js" ></script>\r\n<script src="http://hubzilla/view/js/crypto.js" ></script>\r\n<script src="http://hubzilla/library/jRange/jquery.range.js" ></script>\r\n<script src="http://hubzilla/library/colorbox/jquery.colorbox-min.js" ></script>\r\n<script src="http://hubzilla/library/jquery.AreYouSure/jquery.are-you-sure.js" ></script>\r\n<script src="http://hubzilla/library/tableofcontents/jquery.toc.js" ></script>\r\n<script src="http://hubzilla/library/bootstrap/js/bootstrap.min.js" ></script>\r\n<script src="http://hubzilla/library/bootbox/bootbox.min.js" ></script>\r\n<script src="http://hubzilla/library/bootstrap-tagsinput/bootstrap-tagsinput.js" ></script>\r\n<script src="http://hubzilla/library/datetimepicker/jquery.datetimepicker.js" ></script>\r\n<script src="http://hubzilla/library/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js" ></script>\r\n<script src="http://hubzilla/view/theme/redbasic/js/redbasic.js" ></script>\r\n\n\n<link rel="shortcut icon" href="http://hubzilla/images/hz-32.png" />\n<link rel="search"\n href="http://hubzilla/opensearch" \n type="application/opensearchdescription+xml" \n title="Search in the Hubzilla" />\n\n\n<script>\n\n\tvar updateInterval = 80000;\n\tvar localUser = 2;\n\tvar zid = 'testes@hubzilla';\n\tvar justifiedGalleryActive = false;\n\t\t\n</script>\n\n\n\n\n<script>$(document).ready(function() {\n\t$("#nav-search-text").search_autocomplete('http://hubzilla/acl');\n});\n\n</script><script src="http://hubzilla/view/js/main.js" ></script>\r\n<link rel="stylesheet" href="http://hubzilla/addon/converse/converse.min.js" media="all" /><script src="http://hubzilla/addon/converse/converse.min.js"></script>",
- "header": "<div id="banner" class="hidden-sm hidden-xs">Hubzilla</div>\n\n<ul id="nav-notifications-template" style="display:none;" rel="template">\n\t<li class="{5}"><a href="{0}" title="{2} {3}"><img data-src="{1}"><span class="contactname">{2}</span><span class="dropdown-sub-text">{3}<br>{4}</span></a></li>\n</ul>\n"
- },
- "poi": null,
- "force_max_items": 0,
- "module": "help",
- "template_engines": {
- "smarty3": "FriendicaSmartyEngine",
- "internal": "Template"
- },
- "account": {
- "account_flags": "0",
- "account_service_class": "",
- "account_id": "1",
- "account_salt": "9bf8c193c35a56c4c666f47728fe20da",
- "account_expires": "0000-00-00 00:00:00",
- "account_lastlog": "2015-11-04 07:47:55",
- "account_password_changed": "0000-00-00 00:00:00",
- "account_language": "en",
- "account_default_channel": "2",
- "account_password": "",
- "account_parent": "1",
- "account_expire_notified": "0000-00-00 00:00:00",
- "account_reset": "",
- "account_email": "foo@bar.com",
- "account_level": "0",
- "account_roles": "4096",
- "account_external": "",
- "account_created": "2015-10-09 00:44:51"
- },
- "theme_info": [],
- "argv": [
- "help",
- "develop"
- ],
- "template_engine_instance": {
- "smarty3": {}
- },
- "language": "en",
- "pager": {
- "page": 1,
- "itemspage": 60,
- "start": 0,
- "total": 0
- },
- "plugins": [
- "converse"
- ],
- "error": false,
- "pdl": "[region=aside]\n[widget=helpindex][/widget]\n[/region]\n",
- "query_string": "help/develop",
- "cmd": "help/develop",
- "groups": null,
- "videowidth": 425,
- "css_sources": [
- [
- "library/font_awesome/css/font-awesome.min.css",
- "screen"
- ],
- [
- "library/bootstrap/css/bootstrap.min.css",
- "screen"
- ],
- [
- "library/bootstrap-tagsinput/bootstrap-tagsinput.css",
- "screen"
- ],
- [
- "view/css/bootstrap-red.css",
- "screen"
- ],
- [
- "library/datetimepicker/jquery.datetimepicker.css",
- "screen"
- ],
- [
- "library/bootstrap-colorpicker/dist/css/bootstrap-colorpicker.min.css",
- "screen"
- ],
- [
- "library/tiptip/tipTip.css",
- "screen"
- ],
- [
- "library/jgrowl/jquery.jgrowl.css",
- "screen"
- ],
- [
- "library/jRange/jquery.range.css",
- "screen"
- ],
- [
- "view/css/conversation.css",
- "screen"
- ],
- [
- "view/css/widgets.css",
- "screen"
- ],
- [
- "view/css/colorbox.css",
- "screen"
- ],
- [
- "library/justifiedGallery/justifiedGallery.min.css",
- "screen"
- ],
- [
- "default.css",
- "screen"
- ],
- [
- "mod_help.css",
- "screen"
- ],
- [
- "view/theme/redbasic/php/style.pcss",
- "screen"
- ]
- ],
- "is_tablet": false,
- "observer": {
- "xchan_deleted": "0",
- "xchan_connpage": "",
- "xchan_pubforum": "0",
- "xchan_flags": "0",
- "xchan_censored": "0",
- "xchan_instance_url": "",
- "xchan_photo_s": "http://hubzilla/photo/profile/s/2",
- "xchan_pubkey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7MP/xxsq/srA8I7m+WKf\nHlguwwg0b1tz+I3o+djp7b+wF8q03XPKQpYmKfXIj47vpAOu75nKA4Tn90lLymmk\nSXUHogOqOMy1CHoaVrAw2T2/tAeRoMAjAJ5IxSOAM7Xda0nVUK6FmfxPcvftKf9y\nPmvvFadXpaHT4JGPH0tszDhGXLkqlt9xSkIkpsgMA6emj/7bacc6x8eTdtvzo2e5\n/NyPXvBKH4henmYaKjq/4aIYZcBWYVGt6onxaP2j1cSNbksnOY7GbJl+hy95iFoZ\nDWGxiFwQd+CroiBbdlpVGp13cV/WKp2spZzlzkmCRGYoNbbM5RlgFLnmyTa4XMZE\nwnA3ZUB59MsrUJK+0H/utiZrpX5NQcFl33z8k5zB3pPnhc5S5/P+UJZRnqhet1wQ\n7AZVmdP30D75QD8LZ4SytZ1DHn/N76EsVhSADNMnUfEphs708V33Z0gFWultYDoK\nlvXUf4O0/V8GTufFHb6XdAiy92IUzrormXCpXoOmdOcJdaH9RnotZi/DkuQ0zP+Y\nCvxU9nrjyZvAwAdew//XFDjw4HoThVM4k4jzkIhCTlCao/yRnNM7A/i3OKcXq9wU\n7OZqcRfM9o0BFpZTIoXB7BMtpeioJcBi/7FUaV9U9uYLFuLL0qWa1YxLwfsN9rDk\n6A1gbhD60G9/dAbolp8xAHkCAwEAAQ==\n-----END PUBLIC KEY-----\n",
- "xchan_connurl": "http://hubzilla/poco/testes",
- "xchan_name_date": "2015-10-09 00:45:41",
- "xchan_system": "0",
- "xchan_photo_date": "2015-10-09 00:45:41",
- "xchan_photo_m": "http://hubzilla/photo/profile/m/2",
- "xchan_hidden": "0",
- "xchan_selfcensored": "0",
- "xchan_photo_mimetype": "image/jpeg",
- "xchan_network": "zot",
- "xchan_guid": "Ok-ycNKQYMzjokLnIz5OTCF8M5f4CtRT4vJCUeUivJhIOJWk3ORwIQgGx3P5g2Yz79KxQ-rs_Cn2G_jsgM6hmw",
- "xchan_guid_sig": "XXX",
- "xchan_hash": "uRy0nF-urp6k_bFrkdtCc2EkBynwpgCJL_FQFoTwyw2Hep7AHkrSt1MZcHWV_8DQucNlHSY1vHgUNS2Fvoirpw",
- "xchan_url": "http://hubzilla/channel/testes",
- "xchan_addr": "testes@hubzilla",
- "xchan_orphan": "0",
- "xchan_follow": "http://hubzilla/follow?f=&url=%s",
- "xchan_name": "testes",
- "xchan_photo_l": "http://hubzilla/photo/profile/l/2"
- },
- "contact": null,
- "identities": null,
- "user": null,
- "videoheight": 350,
- "profile": null,
- "theme_thread_allow": true,
- "data": {
- "pageicon": "/images/hz-32.png"
- }
-}[/code]
-
-
-#include doc/macros/main_footer.bb;
-
diff --git a/doc/hooks.html b/doc/hooks.html
index c05de58ef..f4a5a7630 100644
--- a/doc/hooks.html
+++ b/doc/hooks.html
@@ -1 +1 @@
-Hooks Function Source File Arg $a->module . _mod_aftercontent index.php $arr $a->module . _mod_content index.php $arr $a->module . _mod_init index.php $placeholder $a->module . _mod_post index.php $_POST $a->module . _post_ . $selname include/acl_selectors.php $o $a->module . _post_ . $selname include/acl_selectors.php $o $a->module . _post_ . $selname include/acl_selectors.php $o $a->module . _pre_ . $selname include/acl_selectors.php $arr $a->module . _pre_ . $selname include/acl_selectors.php $arr $a->module . _pre_ . $selname include/acl_selectors.php $arr $name include/plugin.php &$data = null about_hook mod/siteinfo.php $o accept_follow mod/connedit.php $arr account_downgrade include/account.php $ret account_downgrade include/account.php $ret account_settings mod/settings.php $account_settings activity_received include/zot.php $parr affinity_labels include/widgets.php $labels affinity_labels mod/connedit.php $labels api_perm_is_allowed include/permissions.php $arr app_menu index.php $arr atom_author include/items.php $o atom_entry include/items.php $o atom_feed include/items.php $atom atom_feed_end include/items.php $atom attach_upload_file include/attach.php $f authenticate include/auth.php $addon_auth avatar_lookup include/network.php $avatar bb2diaspora include/bb2diaspora.php $Text bbcode include/bbcode.php $Text channel_remove include/Contact.php $r[0] chat_message include/chat.php $arr chat_post mod/chatsvc.php $arr check_account_email include/account.php $arr check_account_invite include/account.php $arr check_account_password include/account.php $arr connect_premium mod/connect.php $arr connector_settings mod/settings.php $settings_connectors construct_page boot.php $arr contact_block_end include/text.php $arr contact_edit mod/connedit.php $arr contact_edit_post mod/connedit.php $_POST contact_select_options include/acl_selectors.php $x conversation_start include/conversation.php $cb create_identity include/identity.php $newuid cron include/cronhooks.php $d cron_daily include/poller.php datetime_convert() cron_weekly include/poller.php datetime_convert() directory_item mod/directory.php $arr discover_by_webbie include/network.php $arr display_item include/ItemObject.php $arr display_item include/conversation.php $arr display_settings mod/settings.php $o display_settings_post mod/settings.php $_POST donate_contributors extend/addon/matrix/donate/donate.php $contributors donate_plugin extend/addon/matrix/donate/donate.php $o donate_sponsors extend/addon/matrix/donate/donate.php $sponsors dreport_is_storable include/zot.php $dr drop_item include/items.php $arr enotify include/enotify.php $h enotify_mail include/enotify.php $datarray enotify_store include/enotify.php $datarray event_created include/event.php $event[id] event_updated include/event.php $event[id] externals_url_select include/externals.php $arr feature_enabled include/features.php $arr feature_settings mod/settings.php $settings_addons feature_settings_post mod/settings.php $_POST follow include/follow.php $arr follow include/follow.php $arr follow_allow include/follow.php $x gender_selector include/profile_selectors.php $select gender_selector_min include/profile_selectors.php $select generate_map include/text.php $arr generate_named_map include/text.php $arr get_all_api_perms include/permissions.php $arr get_all_perms include/permissions.php $arr get_features include/features.php $arr get_role_perms include/permissions.php $ret get_widgets boot.php $arr get_widgets boot.php $arr global_permissions include/permissions.php $ret home_content mod/home.php $o home_init mod/home.php $ret hostxrd mod/hostxrd.php $arr html2bbcode include/html2bbcode.php $message identity_basic_export include/identity.php $addon import_author_xchan include/items.php $arr import_channel mod/import.php $addon import_directory_profile include/zot.php $d import_xchan include/zot.php $arr item_photo_menu include/conversation.php $args item_store include/items.php $d item_store include/items.php $arr item_store_update include/items.php $d item_translate include/items.php $translate item_translate include/items.php $translate jot_networks include/acl_selectors.php $jotnets jot_networks include/conversation.php $jotnets jot_networks mod/editblock.php $jotnets jot_networks mod/editpost.php $jotnets jot_networks mod/editwebpage.php $jotnets jot_networks mod/editlayout.php $jotnets jot_tool include/conversation.php $jotplugins jot_tool mod/editblock.php $jotplugins jot_tool mod/editpost.php $jotplugins jot_tool mod/editwebpage.php $jotplugins jot_tool mod/editlayout.php $jotplugins load_pdl boot.php $arr local_dir_update include/dir_fns.php $arr logged_in include/oauth.php $a->user logged_in include/api.php $a->user logged_in include/security.php $a->account logged_in include/security.php $user_record logging_out include/auth.php $args login_hook boot.php $o magic_auth mod/magic.php $arr magic_auth_openid_success mod/openid.php $arr magic_auth_openid_success mod/openid.php $arr magic_auth_success mod/post.php $arr main_slider include/widgets.php $arr marital_selector include/profile_selectors.php $select marital_selector_min include/profile_selectors.php $select module_loaded index.php $x mood_verbs include/text.php $arr nav include/nav.php $x network_content_init mod/network.php $arr network_ping mod/ping.php $arr network_tabs include/conversation.php $arr network_to_name include/contact_selectors.php $nets notifier_end include/notifier.php $target_item notifier_hub include/notifier.php $narr notifier_normal include/deliver_hooks.php $r[0] obj_verbs include/taxonomy.php $arr oembed_probe include/oembed.php $x page_content_top index.php $a->page[content] page_end index.php $a->page[content] page_header include/nav.php $a->page[nav] parse_atom include/items.php $arr parse_link mod/linkinfo.php $arr pdl_selector include/comanche.php $arr perm_is_allowed include/permissions.php $arr permissions_create include/notifier.php $perm_update permissions_update include/notifier.php $perm_update personal_xrd mod/xrd.php $arr photo_post_end include/photos.php $ret photo_post_end include/photos.php $ret photo_upload_begin include/attach.php $arr photo_upload_begin include/photos.php $args photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/photos.php $ret photo_upload_end include/photos.php $ret photo_upload_end include/photos.php $ret photo_upload_end include/photos.php $ret photo_upload_file include/attach.php $f photo_upload_file include/photos.php $f photo_upload_form mod/photos.php $ret poke_verbs include/text.php $arr post_local include/zot.php $arr post_local include/items.php $arr post_local mod/item.php $datarray post_local_end include/items.php $arr post_local_end include/attach.php $arr post_local_end include/attach.php $arr post_local_end extend/addon/matrix/randpost/randpost.php $x post_local_end extend/addon/matrix/randpost/randpost.php $x post_local_end mod/mood.php $arr post_local_end mod/like.php $arr post_local_end mod/item.php $datarray post_local_end mod/subthread.php $arr post_local_start mod/item.php $_REQUEST post_mail include/items.php $arr post_mail_end include/items.php $arr post_remote include/items.php $arr post_remote_end include/items.php $arr post_remote_update include/items.php $arr post_remote_update_end include/items.php $arr prepare_body include/text.php $prep_arr prepare_body_final include/text.php $prep_arr prepare_body_init include/text.php $item probe_well_known include/probe.php $ret proc_run boot.php $arr process_channel_sync_delivery include/zot.php $addon profile_advanced mod/profile.php $o profile_edit mod/profiles.php $arr profile_photo_content_end mod/profile_photo.php $o profile_post mod/profiles.php $_POST profile_sidebar include/identity.php $arr profile_sidebar_enter include/identity.php $profile profile_tabs include/conversation.php $arr register_account include/account.php $result render_location include/conversation.php $locate replace_macros include/text.php $arr reverse_magic_auth mod/rmagic.php $arr settings_account mod/settings.php $_POST settings_form mod/settings.php $o settings_post mod/settings.php $_POST sexpref_selector include/profile_selectors.php $select sexpref_selector_min include/profile_selectors.php $select smilie include/text.php $params smilie extend/addon/matrix/smileybutton/smileybutton.php $params tagged include/items.php $arr validate_channelname include/identity.php $arr webfinger mod/wfinger.php $arr well_known mod/_well_known.php $arr zid include/identity.php $arr zid_init include/identity.php $arr zot_finger include/zot.php $ret
Generated Tue Nov 03 21:19:02 PST 2015
\ No newline at end of file
+Hooks Function Source File Arg $a->module . _mod_aftercontent index.php $arr $a->module . _mod_content index.php $arr $a->module . _mod_init index.php $placeholder $a->module . _mod_post index.php $_POST $a->module . _post_ . $selname include/acl_selectors.php $o $a->module . _post_ . $selname include/acl_selectors.php $o $a->module . _post_ . $selname include/acl_selectors.php $o $a->module . _pre_ . $selname include/acl_selectors.php $arr $a->module . _pre_ . $selname include/acl_selectors.php $arr $a->module . _pre_ . $selname include/acl_selectors.php $arr $name include/plugin.php &$data = null about_hook mod/siteinfo.php $o accept_follow mod/connedit.php $arr account_downgrade include/account.php $ret account_downgrade include/account.php $ret account_settings mod/settings.php $account_settings activity_received include/zot.php $parr affinity_labels include/widgets.php $labels affinity_labels mod/connedit.php $labels api_perm_is_allowed include/permissions.php $arr app_menu index.php $arr atom_author include/items.php $o atom_entry include/items.php $o atom_feed include/items.php $atom atom_feed_end include/items.php $atom attach_upload_file include/attach.php $f authenticate include/auth.php $addon_auth avatar_lookup include/network.php $avatar bb2diaspora include/bb2diaspora.php $Text bbcode include/bbcode.php $Text channel_remove include/Contact.php $r[0] chat_message include/chat.php $arr chat_post mod/chatsvc.php $arr check_account_email include/account.php $arr check_account_invite include/account.php $arr check_account_password include/account.php $arr connect_premium mod/connect.php $arr connector_settings mod/settings.php $settings_connectors construct_page boot.php $arr contact_block_end include/text.php $arr contact_edit mod/connedit.php $arr contact_edit_post mod/connedit.php $_POST contact_select_options include/acl_selectors.php $x conversation_start include/conversation.php $cb create_identity include/channel.php $newuid cron include/cronhooks.php $d cron_daily include/poller.php datetime_convert() cron_weekly include/poller.php datetime_convert() directory_item mod/directory.php $arr discover_by_webbie include/network.php $arr display_item include/ItemObject.php $arr display_item include/conversation.php $arr display_settings mod/settings.php $o display_settings_post mod/settings.php $_POST donate_contributors extend/addon/matrix/donate/donate.php $contributors donate_plugin extend/addon/matrix/donate/donate.php $o donate_sponsors extend/addon/matrix/donate/donate.php $sponsors dreport_is_storable include/zot.php $dr drop_item include/items.php $arr enotify include/enotify.php $h enotify_mail include/enotify.php $datarray enotify_store include/enotify.php $datarray event_created include/event.php $event[id] event_updated include/event.php $event[id] externals_url_select include/externals.php $arr feature_enabled include/features.php $arr feature_settings mod/settings.php $settings_addons feature_settings_post mod/settings.php $_POST follow include/follow.php $arr follow include/follow.php $arr follow_allow include/follow.php $x gender_selector include/profile_selectors.php $select gender_selector_min include/profile_selectors.php $select generate_map include/text.php $arr generate_named_map include/text.php $arr get_all_api_perms include/permissions.php $arr get_all_perms include/permissions.php $arr get_features include/features.php $arr get_role_perms include/permissions.php $ret get_widgets boot.php $arr get_widgets boot.php $arr global_permissions include/permissions.php $ret home_content mod/home.php $o home_init mod/home.php $ret hostxrd mod/hostxrd.php $arr html2bbcode include/html2bbcode.php $message identity_basic_export include/channel.php $addon import_author_xchan include/items.php $arr import_channel mod/import.php $addon import_directory_profile include/zot.php $d import_xchan include/zot.php $arr item_photo_menu include/conversation.php $args item_store include/items.php $d item_store include/items.php $arr item_store_update include/items.php $d item_translate include/items.php $translate item_translate include/items.php $translate jot_networks include/acl_selectors.php $jotnets jot_networks include/conversation.php $jotnets jot_networks mod/editblock.php $jotnets jot_networks mod/editpost.php $jotnets jot_networks mod/editwebpage.php $jotnets jot_networks mod/editlayout.php $jotnets jot_tool include/conversation.php $jotplugins jot_tool mod/editblock.php $jotplugins jot_tool mod/editpost.php $jotplugins jot_tool mod/editwebpage.php $jotplugins jot_tool mod/editlayout.php $jotplugins load_pdl boot.php $arr local_dir_update include/dir_fns.php $arr logged_in include/oauth.php $a->user logged_in include/api.php $a->user logged_in include/security.php $a->account logged_in include/security.php $user_record logging_out include/auth.php $args login_hook boot.php $o magic_auth mod/magic.php $arr magic_auth_openid_success mod/openid.php $arr magic_auth_openid_success mod/openid.php $arr magic_auth_success mod/post.php $arr main_slider include/widgets.php $arr marital_selector include/profile_selectors.php $select marital_selector_min include/profile_selectors.php $select module_loaded index.php $x mood_verbs include/text.php $arr nav include/nav.php $x network_content_init mod/network.php $arr network_ping mod/ping.php $arr network_tabs include/conversation.php $arr network_to_name include/contact_selectors.php $nets notifier_end include/notifier.php $target_item notifier_hub include/notifier.php $narr notifier_normal include/deliver_hooks.php $r[0] obj_verbs include/taxonomy.php $arr oembed_probe include/oembed.php $x page_content_top index.php $a->page[content] page_end index.php $a->page[content] page_header include/nav.php $a->page[nav] parse_atom include/items.php $arr parse_link mod/linkinfo.php $arr pdl_selector include/comanche.php $arr perm_is_allowed include/permissions.php $arr permissions_create include/notifier.php $perm_update permissions_update include/notifier.php $perm_update personal_xrd mod/xrd.php $arr photo_post_end include/photos.php $ret photo_post_end include/photos.php $ret photo_upload_begin include/attach.php $arr photo_upload_begin include/photos.php $args photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/attach.php $ret photo_upload_end include/photos.php $ret photo_upload_end include/photos.php $ret photo_upload_end include/photos.php $ret photo_upload_end include/photos.php $ret photo_upload_file include/attach.php $f photo_upload_file include/photos.php $f photo_upload_form mod/photos.php $ret poke_verbs include/text.php $arr post_local include/zot.php $arr post_local include/items.php $arr post_local mod/item.php $datarray post_local_end include/items.php $arr post_local_end include/attach.php $arr post_local_end include/attach.php $arr post_local_end extend/addon/matrix/randpost/randpost.php $x post_local_end extend/addon/matrix/randpost/randpost.php $x post_local_end mod/mood.php $arr post_local_end mod/like.php $arr post_local_end mod/item.php $datarray post_local_end mod/subthread.php $arr post_local_start mod/item.php $_REQUEST post_mail include/items.php $arr post_mail_end include/items.php $arr post_remote include/items.php $arr post_remote_end include/items.php $arr post_remote_update include/items.php $arr post_remote_update_end include/items.php $arr prepare_body include/text.php $prep_arr prepare_body_final include/text.php $prep_arr prepare_body_init include/text.php $item probe_well_known include/probe.php $ret proc_run boot.php $arr process_channel_sync_delivery include/zot.php $addon profile_advanced mod/profile.php $o profile_edit mod/profiles.php $arr profile_photo_content_end mod/profile_photo.php $o profile_post mod/profiles.php $_POST profile_sidebar include/channel.php $arr profile_sidebar_enter include/channel.php $profile profile_tabs include/conversation.php $arr register_account include/account.php $result render_location include/conversation.php $locate replace_macros include/text.php $arr reverse_magic_auth mod/rmagic.php $arr settings_account mod/settings.php $_POST settings_form mod/settings.php $o settings_post mod/settings.php $_POST sexpref_selector include/profile_selectors.php $select sexpref_selector_min include/profile_selectors.php $select smilie include/text.php $params smilie extend/addon/matrix/smileybutton/smileybutton.php $params tagged include/items.php $arr validate_channelname include/channel.php $arr webfinger mod/wfinger.php $arr well_known mod/_well_known.php $arr zid include/channel.php $arr zid_init include/channel.php $arr zot_finger include/zot.php $ret
Generated Tue Nov 03 21:19:02 PST 2015
\ No newline at end of file
diff --git a/doc/html/index.php b/doc/html/index.php
deleted file mode 100644
index 2e1b4277c..000000000
--- a/doc/html/index.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- $Projectname Doxygen API Documentation
-
-
-$Projectname Doxygen API Documentation not rendered
-
-To get the Doxygen API Documentation you must render it with the program Doxygen (included in most distributions).
-
-$ doxygen util/Doxyfile
-
-
-back
-
-
diff --git a/doc/roadmap.bb b/doc/roadmap.bb
index f57c76b74..9ef9f146a 100644
--- a/doc/roadmap.bb
+++ b/doc/roadmap.bb
@@ -8,18 +8,8 @@ Roadmap for $Projectname V3
Crypto
Convert E2EE to dynamic loading (on demand) using jQuery.getScript() [or other methods] to only load encryption libs when you require them. This should also support multiple encryption libraries (e.g. SJCL, others) triggered from the choice of algorithm and remain pluggable.
-Diaspora
- Convert core Diaspora federation code into a plugin. This presents a number of challenges since it touches and special cases a lot of core functionality. (HZ - in progress)
-
Subscriptions and business models
- Build enough into core(/addons) to generate income (or at least try and cover costs) out of the box (in progress Habeas Codice)
-
-Merge all uploads into common DAV interface
- Separate photo albums from photos and turn them into file directories. (HZ - done)
- Upload everything direct to /store (HZ - done)
- If photo, generate thumbnails and image resources (HZ - done)
- Provide default upload folders with %y (and other?) macros for both photos and other file resources (HZ - done)
- Allow "media" (anything that we can generate a thumbnail for) in the Photos section (and show thumbnails in the Files section where possible) (HZ - done)
+ Build enough into core(/addons) to generate income (or at least try and cover costs) out of the box
Resolve the "every photo has an item" confusion, perhaps every file should also - but only if we can explain it and separate them conceptually.
diff --git a/doc/roadmapv4.bb b/doc/roadmapv4.bb
index 33a3384c5..419cd8d4c 100644
--- a/doc/roadmapv4.bb
+++ b/doc/roadmapv4.bb
@@ -9,20 +9,20 @@ Goals/Highlights:
Focus on visual website design tools, widgets, and sharing mechanisms
-App organisation.
+[x] App organisation.
-Conversion of core application to a composer format living under the namespace "Zotlabs"
+[x] Conversion of core application to a composer format living under the namespace "Zotlabs"
-Conversion of Modules to a more general purpose Controllers layout with DB/memory based
+[x] Conversion of Modules to a more general purpose Controllers layout with DB/memory based
controller routing as opposed to filesystem routing.
-Conversion of core Zot Protocol to a class library
+[x] (partial) Conversion of core Zot Protocol to a class library
-Abstraction of nomadic identity so that sending/receiving to/from singleton networks to/from any clone works flawlessly - [b]provided[/b] the clone physically connected to that singleton identity is up.
+[x] Abstraction of nomadic identity so that sending/receiving to/from singleton networks to/from any clone works flawlessly - [b]provided[/b] the clone physically connected to that singleton identity is up.
[h3]Community Development[/h3]
-CalDAV/CardDAV
+[x] CalDAV/CardDAV
E-Commerce
diff --git a/doc/sv/main.bb b/doc/sv/main.bb
index 26d9c78f6..a5c1d4f7a 100644
--- a/doc/sv/main.bb
+++ b/doc/sv/main.bb
@@ -67,9 +67,6 @@ Zot är en fantastisk ny kommunikationsprotokoll uppfunnit speciellt för $Proje
[zrl=[baseurl]/help/git_for_non_developers]Git for Non-Developers[/zrl]
[zrl=[baseurl]/help/dev_beginner]Sep-for-step manual for beginning developers[/zrl]
-[h3]FAQ för utvecklare[/h3]
-[zrl=[baseurl]/help/faq_developers]FAQ For Developers[/zrl]
-
[h3]Externa resurser[/h3]
[zrl=[baseurl]/help/external-resource-links]External Resource Links[/zrl]
[url=https://github.com/friendica/red]Main Website[/url]
diff --git a/doc/to_do_code.bb b/doc/to_do_code.bb
index 577d0e66f..b1c4923b1 100644
--- a/doc/to_do_code.bb
+++ b/doc/to_do_code.bb
@@ -6,6 +6,7 @@ We need much more than this, but here are areas where developers can help. Pleas
[li]Include TOS link in registration/verification email[/li]
[li]Auto preview posts/comments (configurable timer kicks in the preview if not 0)[/li]
[li]SAML 2.0 and OpenID Connect provider functionality[/li]
+[li]relmeauth (aka indieauth) support[/li]
[li]Create bug tracker module[/li]
[li]Filing posts - provide a dropdown menu integrated with the 'post actions menu'[/li]
[li]translation plugins - moses or apertium[/li]
@@ -17,7 +18,6 @@ We need much more than this, but here are areas where developers can help. Pleas
[li]Integrate the "open site" list with the register page[/li]
[li]Support comments and member notes on documentation pages (to achieve an effect similar to php.net)[/li]
[li]Support comments on webpages[/li]
-[li]refactor the oembed client interface so that we can safely sandbox remote content[/li]
[li]Write more webpage layouts[/li]
[li]Write more webpage widgets[/li]
[li]restricted access OAuth clients[/li]
@@ -27,14 +27,11 @@ We need much more than this, but here are areas where developers can help. Pleas
[li]External post connectors, add popular services[/li]
[li]service classes - provide a pluggable subscription payment gateway for premium accounts[/li]
[li]service classes - account overview page showing resources consumed by channel. With special consideration this page can also be accessed at a meta level by the site admin to drill down on problematic accounts/channels.[/li]
-[li]implement CalDAV/CardDAV sync[/li]
[li]Uploads - integrate #^[url=https://github.com/blueimp/jQuery-File-Upload]https://github.com/blueimp/jQuery-File-Upload[/url][/li]
[li]API extensions, for Twitter API - search, friending, threading. For Red API, lots of stuff[/li]
[li]Import channel from Diaspora/Friendica (Diaspora partially done)[/li]
[li]MediaGoblin photo "crosspost" connector[/li]
-[li]App taxonomy[/li]
-[li]Customisable App collection pages[/li]
-[li]replace the tinymce visual editor and/or make the visual editor pluggable and responsive to different output formats. We probably want library/bbedit for bbcode. This needs a fair bit of work to catch up with our "enhanced bbcode", but start with images, links, bold and highlight and work from there.[/li]
+[li]provide a visual editor[/li]
[li]Create mobile clients for the top platforms - which involves extending the API so that we can do stuff far beyond the current crop of Twitter/Statusnet clients. Ditto for mobile themes. We can probably use something like the Friendica Android app as a base to start from.[/li]
[li]Implement owned and exchangeable "things".[/li]
[li]Family Account creation - using service classes (an account holder can create a certain number of sub-accounts which are all tied to their subscription - if the subscription lapses they all go away).[/li]
diff --git a/doc/zot.md b/doc/zot.md
index f8881c551..1e454e495 100644
--- a/doc/zot.md
+++ b/doc/zot.md
@@ -140,6 +140,8 @@ target_sig => an RSA signature (base64url encoded) of the guid
key => The public key needed to verify the signature
+token => a string (possibly random) chosen by the requesting service. If provided, an entry in the discovered packet will be provided called 'signed_token' which consists of the base64url_encoded RSA signature of the concatenation of the string 'token.' and the provided token using the private key of the discovered channel. This can be verified using the provided 'key' entry, and provides assurance that the server is in possession of the private key for the discovered identity. After 2017-01-01 it is **required** that a server provide a signed_token *if* a token was provided in the request.
+
With no target provided, the permissions returned will be generic permissions
for unknown or unauthenticated observers
@@ -148,6 +150,7 @@ Example of discovery packet for 'mike@zothub.com'
{
"success": true,
+ "signed_token": "KBJrKTq1qrctNuxF3GwVh3GAGRqmgkirlXANPcJZAeWlvSt_9TMV097slR4AYnYCBEushbVqHEJ9Rb5wHTa0HzMbfRo8cRdl2yAirvvv5d98dtwHddQgX1jB0xEypXtmIYMdPGDLvhI1RNdIBhHkkrRcNreRzoy4xD--HM6m1W0-A8PJJJ9BcNxmGPcBtLzW08wzoP9trJ3M7DQ6Gkk6j7iwVsyApw1ZBaDvabGTdc_SFV-Iegtqw3rjzT_xXWsfzMlKBy-019MYn_KS-gu23YzjvGu5tS_zDfkQb8DMUlPLz5yyxM0yOMlUDtG2qQgIJAU2O0X6T5xDdJ6mtolNyhepg845PvFDEqBQGMIH1nc47CNumeudDi8IWymEALhjG_U8KAK7JVlQTJj2EKUb0au1g6fpiBFab5mmxCMtZEX3Jreyak5GOcFFz-WpxuXJD9TdSoIvaBfBFOoJnXkg2zE4RHXeQzZ2FotmrbBG5dm8B-_6byYGoHBc08ZsWze1K96JIeRnLpBaj6ifUDcVHxZMPcGHHT27dvU2PNbgLiBjlAsxhYqkhN5qOHN8XBcg2KRjcMBaI3V0YMxlzXz5MztmZq3fcB1p-ccIoIyMPMzSj3yMB7J9CEU2LYPSTHMdPkIeDE6GaCkQKviaQQJQde346tK_YjA2k7_SOBmvPYE",
"guid": "sebQ-IC4rmFn9d9iu17m4BXO-kHuNutWo2ySjeV2SIW1LzksUkss12xVo3m3fykYxN5HMcc7gUZVYv26asx-Pg",
"guid_sig": "Llenlbl4zHo6-g4sa63MlQmTP5dRCrsPmXHHFmoCHG63BLq5CUZJRLS1vRrrr_MNxr7zob_Ykt_m5xPKe5H0_i4pDj-UdP8dPZqH2fqhhx00kuYL4YUMJ8gRr5eO17vsZQ3XxTcyKewtgeW0j7ytwMp6-hFVUx_Cq08MrXas429ZrjzaEwgTfxGnbgeQYQ0R5EXpHpEmoERnZx77VaEahftmdjAUx9R4YKAp13pGYadJOX5xnLfqofHQD8DyRHWeMJ4G1OfWPSOlXfRayrV_jhnFlZjMU7vOdQwHoCMoR5TFsRsHuzd-qepbvo3pzvQZRWnTNu6oPucgbf94p13QbalYRpBXKOxdTXJrGdESNhGvhtaZnpT9c1QVqC46jdfP0LOX2xrVdbvvG2JMWFv7XJUVjLSk_yjzY6or2VD4V6ztYcjpCi9d_WoNHruoxro_br1YO3KatySxJs-LQ7SOkQI60FpysfbphNyvYMkotwUFI59G08IGKTMu3-GPnV1wp7NOQD1yzJbGGEGSEEysmEP0SO9vnN45kp3MiqbffBGc1r4_YM4e7DPmqOGM94qksOcLOJk1HNESw2dQYWxWQTBXPfOJT6jW9_crGLMEOsZ3Jcss0XS9KzBUA2p_9osvvhUKuKXbNztqH0oZIWlg37FEVsDs_hUwUJpv2Ar09k4",
"key": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7QCwvuEIwCHjhjbpz3Oc\ntyei/Pz9nDksNbsc44Cm8jxYGMXsTPFXDZYCcCB5rcAhPPdZSlzaPkv4vPVcMIrw\n5cdX0tvbwa3rNTng6uFE7qkt15D3YCTkwF0Y9FVZiZ2Ko+G23QeBt9wqb9dlDN1d\nuPmu9BLYXIT/JXoBwf0vjIPFM9WBi5W/EHGaiuqw7lt0qI7zDGw77yO5yehKE4cu\n7dt3SakrXphL70LGiZh2XGoLg9Gmpz98t+gvPAUEotAJxIUqnoiTA8jlxoiQjeRK\nHlJkwMOGmRNPS33awPos0kcSxAywuBbh2X3aSqUMjcbE4cGJ++/13zoa6RUZRObC\nZnaLYJxqYBh13/N8SfH7d005hecDxWnoYXeYuuMeT3a2hV0J84ztkJX5OoxIwk7S\nWmvBq4+m66usn6LNL+p5IAcs93KbvOxxrjtQrzohBXc6+elfLVSQ1Rr9g5xbgpub\npSc+hvzbB6p0tleDRzwAy9X16NI4DYiTj4nkmVjigNo9v2VPnAle5zSam86eiYLO\nt2u9YRqysMLPKevNdj3CIvst+BaGGQONlQalRdIcq8Lin+BhuX+1TBgqyav4XD9K\nd+JHMb1aBk/rFLI9/f2S3BJ1XqpbjXz7AbYlaCwKiJ836+HS8PmLKxwVOnpLMbfH\nPYM8k83Lip4bEKIyAuf02qkCAwEAAQ==\n-----END PUBLIC KEY-----\n",
@@ -217,6 +220,8 @@ Discovery returns a JSON array with the following components:
'success' => ('1' or '') Operation was successful if '1'. Otherwise an optional 'message' may be present indicating the source of error.
+'signed_token' => If a token parameter was provided in the request, it is prepended with the text 'token.' and then RSA signed with the channel private key and base64url encoded and returned as 'signed_token'.
+
'guid' => the guid of the address on the target system
'guid_sig' => the base64url encoded RSA signature of the guid, signed with the private key associated with that guid.
diff --git a/images/emoji/0023-20e3.png b/images/emoji/0023-20e3.png
new file mode 100644
index 000000000..6e26f0070
Binary files /dev/null and b/images/emoji/0023-20e3.png differ
diff --git a/images/emoji/0023.png b/images/emoji/0023.png
new file mode 100644
index 000000000..811f22af8
Binary files /dev/null and b/images/emoji/0023.png differ
diff --git a/images/emoji/002a-20e3.png b/images/emoji/002a-20e3.png
new file mode 100644
index 000000000..2f8e51138
Binary files /dev/null and b/images/emoji/002a-20e3.png differ
diff --git a/images/emoji/002a.png b/images/emoji/002a.png
new file mode 100644
index 000000000..c39443e24
Binary files /dev/null and b/images/emoji/002a.png differ
diff --git a/images/emoji/0030-20e3.png b/images/emoji/0030-20e3.png
new file mode 100644
index 000000000..13aca83e0
Binary files /dev/null and b/images/emoji/0030-20e3.png differ
diff --git a/images/emoji/0030.png b/images/emoji/0030.png
new file mode 100644
index 000000000..e730b28df
Binary files /dev/null and b/images/emoji/0030.png differ
diff --git a/images/emoji/0031-20e3.png b/images/emoji/0031-20e3.png
new file mode 100644
index 000000000..e6d84b801
Binary files /dev/null and b/images/emoji/0031-20e3.png differ
diff --git a/images/emoji/0031.png b/images/emoji/0031.png
new file mode 100644
index 000000000..9c4cbd6f7
Binary files /dev/null and b/images/emoji/0031.png differ
diff --git a/images/emoji/0032-20e3.png b/images/emoji/0032-20e3.png
new file mode 100644
index 000000000..927339c9b
Binary files /dev/null and b/images/emoji/0032-20e3.png differ
diff --git a/images/emoji/0032.png b/images/emoji/0032.png
new file mode 100644
index 000000000..9a0b49a0e
Binary files /dev/null and b/images/emoji/0032.png differ
diff --git a/images/emoji/0033-20e3.png b/images/emoji/0033-20e3.png
new file mode 100644
index 000000000..dbaa6183e
Binary files /dev/null and b/images/emoji/0033-20e3.png differ
diff --git a/images/emoji/0033.png b/images/emoji/0033.png
new file mode 100644
index 000000000..bc898b986
Binary files /dev/null and b/images/emoji/0033.png differ
diff --git a/images/emoji/0034-20e3.png b/images/emoji/0034-20e3.png
new file mode 100644
index 000000000..b0e914aac
Binary files /dev/null and b/images/emoji/0034-20e3.png differ
diff --git a/images/emoji/0034.png b/images/emoji/0034.png
new file mode 100644
index 000000000..7216ee32b
Binary files /dev/null and b/images/emoji/0034.png differ
diff --git a/images/emoji/0035-20e3.png b/images/emoji/0035-20e3.png
new file mode 100644
index 000000000..d14371f3f
Binary files /dev/null and b/images/emoji/0035-20e3.png differ
diff --git a/images/emoji/0035.png b/images/emoji/0035.png
new file mode 100644
index 000000000..c64709a7e
Binary files /dev/null and b/images/emoji/0035.png differ
diff --git a/images/emoji/0036-20e3.png b/images/emoji/0036-20e3.png
new file mode 100644
index 000000000..371b3acef
Binary files /dev/null and b/images/emoji/0036-20e3.png differ
diff --git a/images/emoji/0036.png b/images/emoji/0036.png
new file mode 100644
index 000000000..68e1e71e4
Binary files /dev/null and b/images/emoji/0036.png differ
diff --git a/images/emoji/0037-20e3.png b/images/emoji/0037-20e3.png
new file mode 100644
index 000000000..9b3476ae7
Binary files /dev/null and b/images/emoji/0037-20e3.png differ
diff --git a/images/emoji/0037.png b/images/emoji/0037.png
new file mode 100644
index 000000000..e4aa065c6
Binary files /dev/null and b/images/emoji/0037.png differ
diff --git a/images/emoji/0038-20e3.png b/images/emoji/0038-20e3.png
new file mode 100644
index 000000000..8c95874d4
Binary files /dev/null and b/images/emoji/0038-20e3.png differ
diff --git a/images/emoji/0038.png b/images/emoji/0038.png
new file mode 100644
index 000000000..27eae28e6
Binary files /dev/null and b/images/emoji/0038.png differ
diff --git a/images/emoji/0039-20e3.png b/images/emoji/0039-20e3.png
new file mode 100644
index 000000000..9fce3d1ec
Binary files /dev/null and b/images/emoji/0039-20e3.png differ
diff --git a/images/emoji/0039.png b/images/emoji/0039.png
new file mode 100644
index 000000000..fd9e98055
Binary files /dev/null and b/images/emoji/0039.png differ
diff --git a/images/emoji/00a9.png b/images/emoji/00a9.png
new file mode 100644
index 000000000..6b9a6adbf
Binary files /dev/null and b/images/emoji/00a9.png differ
diff --git a/images/emoji/00ae.png b/images/emoji/00ae.png
new file mode 100644
index 000000000..53ef9f2d4
Binary files /dev/null and b/images/emoji/00ae.png differ
diff --git a/images/emoji/1f004.png b/images/emoji/1f004.png
new file mode 100644
index 000000000..66fd32025
Binary files /dev/null and b/images/emoji/1f004.png differ
diff --git a/images/emoji/1f0cf.png b/images/emoji/1f0cf.png
new file mode 100644
index 000000000..3d0924b68
Binary files /dev/null and b/images/emoji/1f0cf.png differ
diff --git a/images/emoji/1f170.png b/images/emoji/1f170.png
new file mode 100644
index 000000000..8603ff05a
Binary files /dev/null and b/images/emoji/1f170.png differ
diff --git a/images/emoji/1f171.png b/images/emoji/1f171.png
new file mode 100644
index 000000000..25875bc6a
Binary files /dev/null and b/images/emoji/1f171.png differ
diff --git a/images/emoji/1f17e.png b/images/emoji/1f17e.png
new file mode 100644
index 000000000..73278ba19
Binary files /dev/null and b/images/emoji/1f17e.png differ
diff --git a/images/emoji/1f17f.png b/images/emoji/1f17f.png
new file mode 100644
index 000000000..7be7dac27
Binary files /dev/null and b/images/emoji/1f17f.png differ
diff --git a/images/emoji/1f18e.png b/images/emoji/1f18e.png
new file mode 100644
index 000000000..d9f2d17de
Binary files /dev/null and b/images/emoji/1f18e.png differ
diff --git a/images/emoji/1f191.png b/images/emoji/1f191.png
new file mode 100644
index 000000000..8b01b4343
Binary files /dev/null and b/images/emoji/1f191.png differ
diff --git a/images/emoji/1f192.png b/images/emoji/1f192.png
new file mode 100644
index 000000000..74674978d
Binary files /dev/null and b/images/emoji/1f192.png differ
diff --git a/images/emoji/1f193.png b/images/emoji/1f193.png
new file mode 100644
index 000000000..b71956eb4
Binary files /dev/null and b/images/emoji/1f193.png differ
diff --git a/images/emoji/1f194.png b/images/emoji/1f194.png
new file mode 100644
index 000000000..5bf69bf7b
Binary files /dev/null and b/images/emoji/1f194.png differ
diff --git a/images/emoji/1f195.png b/images/emoji/1f195.png
new file mode 100644
index 000000000..b4f85488d
Binary files /dev/null and b/images/emoji/1f195.png differ
diff --git a/images/emoji/1f196.png b/images/emoji/1f196.png
new file mode 100644
index 000000000..ee8d20f5e
Binary files /dev/null and b/images/emoji/1f196.png differ
diff --git a/images/emoji/1f197.png b/images/emoji/1f197.png
new file mode 100644
index 000000000..d0d775532
Binary files /dev/null and b/images/emoji/1f197.png differ
diff --git a/images/emoji/1f198.png b/images/emoji/1f198.png
new file mode 100644
index 000000000..d7d8c9953
Binary files /dev/null and b/images/emoji/1f198.png differ
diff --git a/images/emoji/1f199.png b/images/emoji/1f199.png
new file mode 100644
index 000000000..0d42142ba
Binary files /dev/null and b/images/emoji/1f199.png differ
diff --git a/images/emoji/1f19a.png b/images/emoji/1f19a.png
new file mode 100644
index 000000000..e1180f4a4
Binary files /dev/null and b/images/emoji/1f19a.png differ
diff --git a/images/emoji/1f1e6-1f1e8.png b/images/emoji/1f1e6-1f1e8.png
new file mode 100644
index 000000000..b939efeab
Binary files /dev/null and b/images/emoji/1f1e6-1f1e8.png differ
diff --git a/images/emoji/1f1e6-1f1e9.png b/images/emoji/1f1e6-1f1e9.png
new file mode 100644
index 000000000..20f4b14e8
Binary files /dev/null and b/images/emoji/1f1e6-1f1e9.png differ
diff --git a/images/emoji/1f1e6-1f1ea.png b/images/emoji/1f1e6-1f1ea.png
new file mode 100644
index 000000000..d16ffe4b8
Binary files /dev/null and b/images/emoji/1f1e6-1f1ea.png differ
diff --git a/images/emoji/1f1e6-1f1eb.png b/images/emoji/1f1e6-1f1eb.png
new file mode 100644
index 000000000..a51533b55
Binary files /dev/null and b/images/emoji/1f1e6-1f1eb.png differ
diff --git a/images/emoji/1f1e6-1f1ec.png b/images/emoji/1f1e6-1f1ec.png
new file mode 100644
index 000000000..07f2ce397
Binary files /dev/null and b/images/emoji/1f1e6-1f1ec.png differ
diff --git a/images/emoji/1f1e6-1f1ee.png b/images/emoji/1f1e6-1f1ee.png
new file mode 100644
index 000000000..500b5ab09
Binary files /dev/null and b/images/emoji/1f1e6-1f1ee.png differ
diff --git a/images/emoji/1f1e6-1f1f1.png b/images/emoji/1f1e6-1f1f1.png
new file mode 100644
index 000000000..03a20132c
Binary files /dev/null and b/images/emoji/1f1e6-1f1f1.png differ
diff --git a/images/emoji/1f1e6-1f1f2.png b/images/emoji/1f1e6-1f1f2.png
new file mode 100644
index 000000000..2ad60a273
Binary files /dev/null and b/images/emoji/1f1e6-1f1f2.png differ
diff --git a/images/emoji/1f1e6-1f1f4.png b/images/emoji/1f1e6-1f1f4.png
new file mode 100644
index 000000000..cb46c31f8
Binary files /dev/null and b/images/emoji/1f1e6-1f1f4.png differ
diff --git a/images/emoji/1f1e6-1f1f6.png b/images/emoji/1f1e6-1f1f6.png
new file mode 100644
index 000000000..b272021d3
Binary files /dev/null and b/images/emoji/1f1e6-1f1f6.png differ
diff --git a/images/emoji/1f1e6-1f1f7.png b/images/emoji/1f1e6-1f1f7.png
new file mode 100644
index 000000000..73136caf3
Binary files /dev/null and b/images/emoji/1f1e6-1f1f7.png differ
diff --git a/images/emoji/1f1e6-1f1f8.png b/images/emoji/1f1e6-1f1f8.png
new file mode 100644
index 000000000..3db45a0d9
Binary files /dev/null and b/images/emoji/1f1e6-1f1f8.png differ
diff --git a/images/emoji/1f1e6-1f1f9.png b/images/emoji/1f1e6-1f1f9.png
new file mode 100644
index 000000000..c43769dcb
Binary files /dev/null and b/images/emoji/1f1e6-1f1f9.png differ
diff --git a/images/emoji/1f1e6-1f1fa.png b/images/emoji/1f1e6-1f1fa.png
new file mode 100644
index 000000000..7794309c7
Binary files /dev/null and b/images/emoji/1f1e6-1f1fa.png differ
diff --git a/images/emoji/1f1e6-1f1fc.png b/images/emoji/1f1e6-1f1fc.png
new file mode 100644
index 000000000..02c840d12
Binary files /dev/null and b/images/emoji/1f1e6-1f1fc.png differ
diff --git a/images/emoji/1f1e6-1f1fd.png b/images/emoji/1f1e6-1f1fd.png
new file mode 100644
index 000000000..fc5466174
Binary files /dev/null and b/images/emoji/1f1e6-1f1fd.png differ
diff --git a/images/emoji/1f1e6-1f1ff.png b/images/emoji/1f1e6-1f1ff.png
new file mode 100644
index 000000000..89d3d15fd
Binary files /dev/null and b/images/emoji/1f1e6-1f1ff.png differ
diff --git a/images/emoji/1f1e7-1f1e6.png b/images/emoji/1f1e7-1f1e6.png
new file mode 100644
index 000000000..25fe407e1
Binary files /dev/null and b/images/emoji/1f1e7-1f1e6.png differ
diff --git a/images/emoji/1f1e7-1f1e7.png b/images/emoji/1f1e7-1f1e7.png
new file mode 100644
index 000000000..bccd8c5c9
Binary files /dev/null and b/images/emoji/1f1e7-1f1e7.png differ
diff --git a/images/emoji/1f1e7-1f1e9.png b/images/emoji/1f1e7-1f1e9.png
new file mode 100644
index 000000000..b0597a314
Binary files /dev/null and b/images/emoji/1f1e7-1f1e9.png differ
diff --git a/images/emoji/1f1e7-1f1ea.png b/images/emoji/1f1e7-1f1ea.png
new file mode 100644
index 000000000..551f086e3
Binary files /dev/null and b/images/emoji/1f1e7-1f1ea.png differ
diff --git a/images/emoji/1f1e7-1f1eb.png b/images/emoji/1f1e7-1f1eb.png
new file mode 100644
index 000000000..444d4829f
Binary files /dev/null and b/images/emoji/1f1e7-1f1eb.png differ
diff --git a/images/emoji/1f1e7-1f1ec.png b/images/emoji/1f1e7-1f1ec.png
new file mode 100644
index 000000000..821eee5e1
Binary files /dev/null and b/images/emoji/1f1e7-1f1ec.png differ
diff --git a/images/emoji/1f1e7-1f1ed.png b/images/emoji/1f1e7-1f1ed.png
new file mode 100644
index 000000000..f33724249
Binary files /dev/null and b/images/emoji/1f1e7-1f1ed.png differ
diff --git a/images/emoji/1f1e7-1f1ee.png b/images/emoji/1f1e7-1f1ee.png
new file mode 100644
index 000000000..ea20ac932
Binary files /dev/null and b/images/emoji/1f1e7-1f1ee.png differ
diff --git a/images/emoji/1f1e7-1f1ef.png b/images/emoji/1f1e7-1f1ef.png
new file mode 100644
index 000000000..7cca4f804
Binary files /dev/null and b/images/emoji/1f1e7-1f1ef.png differ
diff --git a/images/emoji/1f1e7-1f1f1.png b/images/emoji/1f1e7-1f1f1.png
new file mode 100644
index 000000000..0316ac99d
Binary files /dev/null and b/images/emoji/1f1e7-1f1f1.png differ
diff --git a/images/emoji/1f1e7-1f1f2.png b/images/emoji/1f1e7-1f1f2.png
new file mode 100644
index 000000000..ab8cafdac
Binary files /dev/null and b/images/emoji/1f1e7-1f1f2.png differ
diff --git a/images/emoji/1f1e7-1f1f3.png b/images/emoji/1f1e7-1f1f3.png
new file mode 100644
index 000000000..16a58f8f6
Binary files /dev/null and b/images/emoji/1f1e7-1f1f3.png differ
diff --git a/images/emoji/1f1e7-1f1f4.png b/images/emoji/1f1e7-1f1f4.png
new file mode 100644
index 000000000..98af62b3d
Binary files /dev/null and b/images/emoji/1f1e7-1f1f4.png differ
diff --git a/images/emoji/1f1e7-1f1f6.png b/images/emoji/1f1e7-1f1f6.png
new file mode 100644
index 000000000..cb978ef9d
Binary files /dev/null and b/images/emoji/1f1e7-1f1f6.png differ
diff --git a/images/emoji/1f1e7-1f1f7.png b/images/emoji/1f1e7-1f1f7.png
new file mode 100644
index 000000000..b139366a4
Binary files /dev/null and b/images/emoji/1f1e7-1f1f7.png differ
diff --git a/images/emoji/1f1e7-1f1f8.png b/images/emoji/1f1e7-1f1f8.png
new file mode 100644
index 000000000..d36bcd2fb
Binary files /dev/null and b/images/emoji/1f1e7-1f1f8.png differ
diff --git a/images/emoji/1f1e7-1f1f9.png b/images/emoji/1f1e7-1f1f9.png
new file mode 100644
index 000000000..b571dce1a
Binary files /dev/null and b/images/emoji/1f1e7-1f1f9.png differ
diff --git a/images/emoji/1f1e7-1f1fb.png b/images/emoji/1f1e7-1f1fb.png
new file mode 100644
index 000000000..5884e6482
Binary files /dev/null and b/images/emoji/1f1e7-1f1fb.png differ
diff --git a/images/emoji/1f1e7-1f1fc.png b/images/emoji/1f1e7-1f1fc.png
new file mode 100644
index 000000000..cb12f3473
Binary files /dev/null and b/images/emoji/1f1e7-1f1fc.png differ
diff --git a/images/emoji/1f1e7-1f1fe.png b/images/emoji/1f1e7-1f1fe.png
new file mode 100644
index 000000000..859c05beb
Binary files /dev/null and b/images/emoji/1f1e7-1f1fe.png differ
diff --git a/images/emoji/1f1e7-1f1ff.png b/images/emoji/1f1e7-1f1ff.png
new file mode 100644
index 000000000..db2c28bd7
Binary files /dev/null and b/images/emoji/1f1e7-1f1ff.png differ
diff --git a/images/emoji/1f1e7.png b/images/emoji/1f1e7.png
new file mode 100644
index 000000000..8f69fa973
Binary files /dev/null and b/images/emoji/1f1e7.png differ
diff --git a/images/emoji/1f1e8-1f1e6.png b/images/emoji/1f1e8-1f1e6.png
new file mode 100644
index 000000000..7c5b390e8
Binary files /dev/null and b/images/emoji/1f1e8-1f1e6.png differ
diff --git a/images/emoji/1f1e8-1f1e8.png b/images/emoji/1f1e8-1f1e8.png
new file mode 100644
index 000000000..b6555a23d
Binary files /dev/null and b/images/emoji/1f1e8-1f1e8.png differ
diff --git a/images/emoji/1f1e8-1f1e9.png b/images/emoji/1f1e8-1f1e9.png
new file mode 100644
index 000000000..fa9200977
Binary files /dev/null and b/images/emoji/1f1e8-1f1e9.png differ
diff --git a/images/emoji/1f1e8-1f1eb.png b/images/emoji/1f1e8-1f1eb.png
new file mode 100644
index 000000000..b969ae29e
Binary files /dev/null and b/images/emoji/1f1e8-1f1eb.png differ
diff --git a/images/emoji/1f1e8-1f1ec.png b/images/emoji/1f1e8-1f1ec.png
new file mode 100644
index 000000000..3a38a40a9
Binary files /dev/null and b/images/emoji/1f1e8-1f1ec.png differ
diff --git a/images/emoji/1f1e8-1f1ed.png b/images/emoji/1f1e8-1f1ed.png
new file mode 100644
index 000000000..5ff86b8a3
Binary files /dev/null and b/images/emoji/1f1e8-1f1ed.png differ
diff --git a/images/emoji/1f1e8-1f1ee.png b/images/emoji/1f1e8-1f1ee.png
new file mode 100644
index 000000000..e3b4d15c7
Binary files /dev/null and b/images/emoji/1f1e8-1f1ee.png differ
diff --git a/images/emoji/1f1e8-1f1f0.png b/images/emoji/1f1e8-1f1f0.png
new file mode 100644
index 000000000..b6b53dbc1
Binary files /dev/null and b/images/emoji/1f1e8-1f1f0.png differ
diff --git a/images/emoji/1f1e8-1f1f1.png b/images/emoji/1f1e8-1f1f1.png
new file mode 100644
index 000000000..c9390da54
Binary files /dev/null and b/images/emoji/1f1e8-1f1f1.png differ
diff --git a/images/emoji/1f1e8-1f1f2.png b/images/emoji/1f1e8-1f1f2.png
new file mode 100644
index 000000000..2d3f6ec45
Binary files /dev/null and b/images/emoji/1f1e8-1f1f2.png differ
diff --git a/images/emoji/1f1e8-1f1f3.png b/images/emoji/1f1e8-1f1f3.png
new file mode 100644
index 000000000..0a7f350a6
Binary files /dev/null and b/images/emoji/1f1e8-1f1f3.png differ
diff --git a/images/emoji/1f1e8-1f1f4.png b/images/emoji/1f1e8-1f1f4.png
new file mode 100644
index 000000000..7e0f5e0dc
Binary files /dev/null and b/images/emoji/1f1e8-1f1f4.png differ
diff --git a/images/emoji/1f1e8-1f1f5.png b/images/emoji/1f1e8-1f1f5.png
new file mode 100644
index 000000000..70c761036
Binary files /dev/null and b/images/emoji/1f1e8-1f1f5.png differ
diff --git a/images/emoji/1f1e8-1f1f7.png b/images/emoji/1f1e8-1f1f7.png
new file mode 100644
index 000000000..a5fce1265
Binary files /dev/null and b/images/emoji/1f1e8-1f1f7.png differ
diff --git a/images/emoji/1f1e8-1f1fa.png b/images/emoji/1f1e8-1f1fa.png
new file mode 100644
index 000000000..447328f7d
Binary files /dev/null and b/images/emoji/1f1e8-1f1fa.png differ
diff --git a/images/emoji/1f1e8-1f1fb.png b/images/emoji/1f1e8-1f1fb.png
new file mode 100644
index 000000000..43faf4d64
Binary files /dev/null and b/images/emoji/1f1e8-1f1fb.png differ
diff --git a/images/emoji/1f1e8-1f1fc.png b/images/emoji/1f1e8-1f1fc.png
new file mode 100644
index 000000000..eb39e8d00
Binary files /dev/null and b/images/emoji/1f1e8-1f1fc.png differ
diff --git a/images/emoji/1f1e8-1f1fd.png b/images/emoji/1f1e8-1f1fd.png
new file mode 100644
index 000000000..09d21359f
Binary files /dev/null and b/images/emoji/1f1e8-1f1fd.png differ
diff --git a/images/emoji/1f1e8-1f1fe.png b/images/emoji/1f1e8-1f1fe.png
new file mode 100644
index 000000000..154a7aa31
Binary files /dev/null and b/images/emoji/1f1e8-1f1fe.png differ
diff --git a/images/emoji/1f1e8-1f1ff.png b/images/emoji/1f1e8-1f1ff.png
new file mode 100644
index 000000000..9737ca223
Binary files /dev/null and b/images/emoji/1f1e8-1f1ff.png differ
diff --git a/images/emoji/1f1e8.png b/images/emoji/1f1e8.png
new file mode 100644
index 000000000..f94e668a2
Binary files /dev/null and b/images/emoji/1f1e8.png differ
diff --git a/images/emoji/1f1e9-1f1ea.png b/images/emoji/1f1e9-1f1ea.png
new file mode 100644
index 000000000..98ed76b3b
Binary files /dev/null and b/images/emoji/1f1e9-1f1ea.png differ
diff --git a/images/emoji/1f1e9-1f1ec.png b/images/emoji/1f1e9-1f1ec.png
new file mode 100644
index 000000000..fb6cc3cd4
Binary files /dev/null and b/images/emoji/1f1e9-1f1ec.png differ
diff --git a/images/emoji/1f1e9-1f1ef.png b/images/emoji/1f1e9-1f1ef.png
new file mode 100644
index 000000000..73c2a2acb
Binary files /dev/null and b/images/emoji/1f1e9-1f1ef.png differ
diff --git a/images/emoji/1f1e9-1f1f0.png b/images/emoji/1f1e9-1f1f0.png
new file mode 100644
index 000000000..e5a60b062
Binary files /dev/null and b/images/emoji/1f1e9-1f1f0.png differ
diff --git a/images/emoji/1f1e9-1f1f2.png b/images/emoji/1f1e9-1f1f2.png
new file mode 100644
index 000000000..4d4cf6444
Binary files /dev/null and b/images/emoji/1f1e9-1f1f2.png differ
diff --git a/images/emoji/1f1e9-1f1f4.png b/images/emoji/1f1e9-1f1f4.png
new file mode 100644
index 000000000..037a45d7c
Binary files /dev/null and b/images/emoji/1f1e9-1f1f4.png differ
diff --git a/images/emoji/1f1e9-1f1ff.png b/images/emoji/1f1e9-1f1ff.png
new file mode 100644
index 000000000..24945b10f
Binary files /dev/null and b/images/emoji/1f1e9-1f1ff.png differ
diff --git a/images/emoji/1f1e9.png b/images/emoji/1f1e9.png
new file mode 100644
index 000000000..4a36666e5
Binary files /dev/null and b/images/emoji/1f1e9.png differ
diff --git a/images/emoji/1f1ea-1f1e6.png b/images/emoji/1f1ea-1f1e6.png
new file mode 100644
index 000000000..9d05e1b0d
Binary files /dev/null and b/images/emoji/1f1ea-1f1e6.png differ
diff --git a/images/emoji/1f1ea-1f1e8.png b/images/emoji/1f1ea-1f1e8.png
new file mode 100644
index 000000000..138145946
Binary files /dev/null and b/images/emoji/1f1ea-1f1e8.png differ
diff --git a/images/emoji/1f1ea-1f1ea.png b/images/emoji/1f1ea-1f1ea.png
new file mode 100644
index 000000000..84f317e77
Binary files /dev/null and b/images/emoji/1f1ea-1f1ea.png differ
diff --git a/images/emoji/1f1ea-1f1ec.png b/images/emoji/1f1ea-1f1ec.png
new file mode 100644
index 000000000..57786064a
Binary files /dev/null and b/images/emoji/1f1ea-1f1ec.png differ
diff --git a/images/emoji/1f1ea-1f1ed.png b/images/emoji/1f1ea-1f1ed.png
new file mode 100644
index 000000000..4d7a76687
Binary files /dev/null and b/images/emoji/1f1ea-1f1ed.png differ
diff --git a/images/emoji/1f1ea-1f1f7.png b/images/emoji/1f1ea-1f1f7.png
new file mode 100644
index 000000000..0c3c724c1
Binary files /dev/null and b/images/emoji/1f1ea-1f1f7.png differ
diff --git a/images/emoji/1f1ea-1f1f8.png b/images/emoji/1f1ea-1f1f8.png
new file mode 100644
index 000000000..c37fdfe5c
Binary files /dev/null and b/images/emoji/1f1ea-1f1f8.png differ
diff --git a/images/emoji/1f1ea-1f1f9.png b/images/emoji/1f1ea-1f1f9.png
new file mode 100644
index 000000000..9560a134c
Binary files /dev/null and b/images/emoji/1f1ea-1f1f9.png differ
diff --git a/images/emoji/1f1ea-1f1fa.png b/images/emoji/1f1ea-1f1fa.png
new file mode 100644
index 000000000..0b456cf33
Binary files /dev/null and b/images/emoji/1f1ea-1f1fa.png differ
diff --git a/images/emoji/1f1ea.png b/images/emoji/1f1ea.png
new file mode 100644
index 000000000..66f7e8d8c
Binary files /dev/null and b/images/emoji/1f1ea.png differ
diff --git a/images/emoji/1f1eb-1f1ee.png b/images/emoji/1f1eb-1f1ee.png
new file mode 100644
index 000000000..ebcf58abf
Binary files /dev/null and b/images/emoji/1f1eb-1f1ee.png differ
diff --git a/images/emoji/1f1eb-1f1ef.png b/images/emoji/1f1eb-1f1ef.png
new file mode 100644
index 000000000..9cc8c37fe
Binary files /dev/null and b/images/emoji/1f1eb-1f1ef.png differ
diff --git a/images/emoji/1f1eb-1f1f0.png b/images/emoji/1f1eb-1f1f0.png
new file mode 100644
index 000000000..61372fd25
Binary files /dev/null and b/images/emoji/1f1eb-1f1f0.png differ
diff --git a/images/emoji/1f1eb-1f1f2.png b/images/emoji/1f1eb-1f1f2.png
new file mode 100644
index 000000000..0889825c8
Binary files /dev/null and b/images/emoji/1f1eb-1f1f2.png differ
diff --git a/images/emoji/1f1eb-1f1f4.png b/images/emoji/1f1eb-1f1f4.png
new file mode 100644
index 000000000..9a4431b08
Binary files /dev/null and b/images/emoji/1f1eb-1f1f4.png differ
diff --git a/images/emoji/1f1eb-1f1f7.png b/images/emoji/1f1eb-1f1f7.png
new file mode 100644
index 000000000..62ca19c3f
Binary files /dev/null and b/images/emoji/1f1eb-1f1f7.png differ
diff --git a/images/emoji/1f1eb.png b/images/emoji/1f1eb.png
new file mode 100644
index 000000000..913b230fd
Binary files /dev/null and b/images/emoji/1f1eb.png differ
diff --git a/images/emoji/1f1ec-1f1e6.png b/images/emoji/1f1ec-1f1e6.png
new file mode 100644
index 000000000..2e68e527a
Binary files /dev/null and b/images/emoji/1f1ec-1f1e6.png differ
diff --git a/images/emoji/1f1ec-1f1e7.png b/images/emoji/1f1ec-1f1e7.png
new file mode 100644
index 000000000..3ed10f623
Binary files /dev/null and b/images/emoji/1f1ec-1f1e7.png differ
diff --git a/images/emoji/1f1ec-1f1e9.png b/images/emoji/1f1ec-1f1e9.png
new file mode 100644
index 000000000..527aad338
Binary files /dev/null and b/images/emoji/1f1ec-1f1e9.png differ
diff --git a/images/emoji/1f1ec-1f1ea.png b/images/emoji/1f1ec-1f1ea.png
new file mode 100644
index 000000000..a75d14248
Binary files /dev/null and b/images/emoji/1f1ec-1f1ea.png differ
diff --git a/images/emoji/1f1ec-1f1eb.png b/images/emoji/1f1ec-1f1eb.png
new file mode 100644
index 000000000..0cf96f327
Binary files /dev/null and b/images/emoji/1f1ec-1f1eb.png differ
diff --git a/images/emoji/1f1ec-1f1ec.png b/images/emoji/1f1ec-1f1ec.png
new file mode 100644
index 000000000..970002c7f
Binary files /dev/null and b/images/emoji/1f1ec-1f1ec.png differ
diff --git a/images/emoji/1f1ec-1f1ed.png b/images/emoji/1f1ec-1f1ed.png
new file mode 100644
index 000000000..f31b5eb7b
Binary files /dev/null and b/images/emoji/1f1ec-1f1ed.png differ
diff --git a/images/emoji/1f1ec-1f1ee.png b/images/emoji/1f1ec-1f1ee.png
new file mode 100644
index 000000000..e554a2a1d
Binary files /dev/null and b/images/emoji/1f1ec-1f1ee.png differ
diff --git a/images/emoji/1f1ec-1f1f1.png b/images/emoji/1f1ec-1f1f1.png
new file mode 100644
index 000000000..2e795dd4e
Binary files /dev/null and b/images/emoji/1f1ec-1f1f1.png differ
diff --git a/images/emoji/1f1ec-1f1f2.png b/images/emoji/1f1ec-1f1f2.png
new file mode 100644
index 000000000..bb69c0975
Binary files /dev/null and b/images/emoji/1f1ec-1f1f2.png differ
diff --git a/images/emoji/1f1ec-1f1f3.png b/images/emoji/1f1ec-1f1f3.png
new file mode 100644
index 000000000..1981f61db
Binary files /dev/null and b/images/emoji/1f1ec-1f1f3.png differ
diff --git a/images/emoji/1f1ec-1f1f5.png b/images/emoji/1f1ec-1f1f5.png
new file mode 100644
index 000000000..10e42e672
Binary files /dev/null and b/images/emoji/1f1ec-1f1f5.png differ
diff --git a/images/emoji/1f1ec-1f1f6.png b/images/emoji/1f1ec-1f1f6.png
new file mode 100644
index 000000000..11475e61e
Binary files /dev/null and b/images/emoji/1f1ec-1f1f6.png differ
diff --git a/images/emoji/1f1ec-1f1f7.png b/images/emoji/1f1ec-1f1f7.png
new file mode 100644
index 000000000..0f6bb1b6b
Binary files /dev/null and b/images/emoji/1f1ec-1f1f7.png differ
diff --git a/images/emoji/1f1ec-1f1f8.png b/images/emoji/1f1ec-1f1f8.png
new file mode 100644
index 000000000..6fc927804
Binary files /dev/null and b/images/emoji/1f1ec-1f1f8.png differ
diff --git a/images/emoji/1f1ec-1f1f9.png b/images/emoji/1f1ec-1f1f9.png
new file mode 100644
index 000000000..7213d4139
Binary files /dev/null and b/images/emoji/1f1ec-1f1f9.png differ
diff --git a/images/emoji/1f1ec-1f1fa.png b/images/emoji/1f1ec-1f1fa.png
new file mode 100644
index 000000000..4027549ca
Binary files /dev/null and b/images/emoji/1f1ec-1f1fa.png differ
diff --git a/images/emoji/1f1ec-1f1fc.png b/images/emoji/1f1ec-1f1fc.png
new file mode 100644
index 000000000..6357f6225
Binary files /dev/null and b/images/emoji/1f1ec-1f1fc.png differ
diff --git a/images/emoji/1f1ec-1f1fe.png b/images/emoji/1f1ec-1f1fe.png
new file mode 100644
index 000000000..746e2fb7e
Binary files /dev/null and b/images/emoji/1f1ec-1f1fe.png differ
diff --git a/images/emoji/1f1ec.png b/images/emoji/1f1ec.png
new file mode 100644
index 000000000..271163075
Binary files /dev/null and b/images/emoji/1f1ec.png differ
diff --git a/images/emoji/1f1ed-1f1f0.png b/images/emoji/1f1ed-1f1f0.png
new file mode 100644
index 000000000..cf0c7151b
Binary files /dev/null and b/images/emoji/1f1ed-1f1f0.png differ
diff --git a/images/emoji/1f1ed-1f1f2.png b/images/emoji/1f1ed-1f1f2.png
new file mode 100644
index 000000000..b613509e4
Binary files /dev/null and b/images/emoji/1f1ed-1f1f2.png differ
diff --git a/images/emoji/1f1ed-1f1f3.png b/images/emoji/1f1ed-1f1f3.png
new file mode 100644
index 000000000..402cdcefd
Binary files /dev/null and b/images/emoji/1f1ed-1f1f3.png differ
diff --git a/images/emoji/1f1ed-1f1f7.png b/images/emoji/1f1ed-1f1f7.png
new file mode 100644
index 000000000..46f4f06b4
Binary files /dev/null and b/images/emoji/1f1ed-1f1f7.png differ
diff --git a/images/emoji/1f1ed-1f1f9.png b/images/emoji/1f1ed-1f1f9.png
new file mode 100644
index 000000000..d8d0c8884
Binary files /dev/null and b/images/emoji/1f1ed-1f1f9.png differ
diff --git a/images/emoji/1f1ed-1f1fa.png b/images/emoji/1f1ed-1f1fa.png
new file mode 100644
index 000000000..a898de636
Binary files /dev/null and b/images/emoji/1f1ed-1f1fa.png differ
diff --git a/images/emoji/1f1ed.png b/images/emoji/1f1ed.png
new file mode 100644
index 000000000..ca88e46bf
Binary files /dev/null and b/images/emoji/1f1ed.png differ
diff --git a/images/emoji/1f1ee-1f1e8.png b/images/emoji/1f1ee-1f1e8.png
new file mode 100644
index 000000000..69fd990aa
Binary files /dev/null and b/images/emoji/1f1ee-1f1e8.png differ
diff --git a/images/emoji/1f1ee-1f1e9.png b/images/emoji/1f1ee-1f1e9.png
new file mode 100644
index 000000000..85b4c063a
Binary files /dev/null and b/images/emoji/1f1ee-1f1e9.png differ
diff --git a/images/emoji/1f1ee-1f1ea.png b/images/emoji/1f1ee-1f1ea.png
new file mode 100644
index 000000000..a28295838
Binary files /dev/null and b/images/emoji/1f1ee-1f1ea.png differ
diff --git a/images/emoji/1f1ee-1f1f1.png b/images/emoji/1f1ee-1f1f1.png
new file mode 100644
index 000000000..85c410d45
Binary files /dev/null and b/images/emoji/1f1ee-1f1f1.png differ
diff --git a/images/emoji/1f1ee-1f1f2.png b/images/emoji/1f1ee-1f1f2.png
new file mode 100644
index 000000000..60a2458e3
Binary files /dev/null and b/images/emoji/1f1ee-1f1f2.png differ
diff --git a/images/emoji/1f1ee-1f1f3.png b/images/emoji/1f1ee-1f1f3.png
new file mode 100644
index 000000000..feccc8952
Binary files /dev/null and b/images/emoji/1f1ee-1f1f3.png differ
diff --git a/images/emoji/1f1ee-1f1f4.png b/images/emoji/1f1ee-1f1f4.png
new file mode 100644
index 000000000..fb6cc3cd4
Binary files /dev/null and b/images/emoji/1f1ee-1f1f4.png differ
diff --git a/images/emoji/1f1ee-1f1f6.png b/images/emoji/1f1ee-1f1f6.png
new file mode 100644
index 000000000..41fd1db6f
Binary files /dev/null and b/images/emoji/1f1ee-1f1f6.png differ
diff --git a/images/emoji/1f1ee-1f1f7.png b/images/emoji/1f1ee-1f1f7.png
new file mode 100644
index 000000000..ff7aaf62b
Binary files /dev/null and b/images/emoji/1f1ee-1f1f7.png differ
diff --git a/images/emoji/1f1ee-1f1f8.png b/images/emoji/1f1ee-1f1f8.png
new file mode 100644
index 000000000..ad8d4131d
Binary files /dev/null and b/images/emoji/1f1ee-1f1f8.png differ
diff --git a/images/emoji/1f1ee-1f1f9.png b/images/emoji/1f1ee-1f1f9.png
new file mode 100644
index 000000000..f21563ec5
Binary files /dev/null and b/images/emoji/1f1ee-1f1f9.png differ
diff --git a/images/emoji/1f1ee.png b/images/emoji/1f1ee.png
new file mode 100644
index 000000000..48dc16788
Binary files /dev/null and b/images/emoji/1f1ee.png differ
diff --git a/images/emoji/1f1ef-1f1ea.png b/images/emoji/1f1ef-1f1ea.png
new file mode 100644
index 000000000..198a918f6
Binary files /dev/null and b/images/emoji/1f1ef-1f1ea.png differ
diff --git a/images/emoji/1f1ef-1f1f2.png b/images/emoji/1f1ef-1f1f2.png
new file mode 100644
index 000000000..f84e4f9e8
Binary files /dev/null and b/images/emoji/1f1ef-1f1f2.png differ
diff --git a/images/emoji/1f1ef-1f1f4.png b/images/emoji/1f1ef-1f1f4.png
new file mode 100644
index 000000000..20bfa147e
Binary files /dev/null and b/images/emoji/1f1ef-1f1f4.png differ
diff --git a/images/emoji/1f1ef-1f1f5.png b/images/emoji/1f1ef-1f1f5.png
new file mode 100644
index 000000000..8d8838e47
Binary files /dev/null and b/images/emoji/1f1ef-1f1f5.png differ
diff --git a/images/emoji/1f1ef.png b/images/emoji/1f1ef.png
new file mode 100644
index 000000000..16599daa7
Binary files /dev/null and b/images/emoji/1f1ef.png differ
diff --git a/images/emoji/1f1f0-1f1ea.png b/images/emoji/1f1f0-1f1ea.png
new file mode 100644
index 000000000..9e417ab30
Binary files /dev/null and b/images/emoji/1f1f0-1f1ea.png differ
diff --git a/images/emoji/1f1f0-1f1ec.png b/images/emoji/1f1f0-1f1ec.png
new file mode 100644
index 000000000..b3eaf7e57
Binary files /dev/null and b/images/emoji/1f1f0-1f1ec.png differ
diff --git a/images/emoji/1f1f0-1f1ed.png b/images/emoji/1f1f0-1f1ed.png
new file mode 100644
index 000000000..9a2877dd6
Binary files /dev/null and b/images/emoji/1f1f0-1f1ed.png differ
diff --git a/images/emoji/1f1f0-1f1ee.png b/images/emoji/1f1f0-1f1ee.png
new file mode 100644
index 000000000..9a5abed3f
Binary files /dev/null and b/images/emoji/1f1f0-1f1ee.png differ
diff --git a/images/emoji/1f1f0-1f1f2.png b/images/emoji/1f1f0-1f1f2.png
new file mode 100644
index 000000000..bd5a0588e
Binary files /dev/null and b/images/emoji/1f1f0-1f1f2.png differ
diff --git a/images/emoji/1f1f0-1f1f3.png b/images/emoji/1f1f0-1f1f3.png
new file mode 100644
index 000000000..776207c96
Binary files /dev/null and b/images/emoji/1f1f0-1f1f3.png differ
diff --git a/images/emoji/1f1f0-1f1f5.png b/images/emoji/1f1f0-1f1f5.png
new file mode 100644
index 000000000..6b3fd89ea
Binary files /dev/null and b/images/emoji/1f1f0-1f1f5.png differ
diff --git a/images/emoji/1f1f0-1f1f7.png b/images/emoji/1f1f0-1f1f7.png
new file mode 100644
index 000000000..faa466f2d
Binary files /dev/null and b/images/emoji/1f1f0-1f1f7.png differ
diff --git a/images/emoji/1f1f0-1f1fc.png b/images/emoji/1f1f0-1f1fc.png
new file mode 100644
index 000000000..4d19bfa6c
Binary files /dev/null and b/images/emoji/1f1f0-1f1fc.png differ
diff --git a/images/emoji/1f1f0-1f1fe.png b/images/emoji/1f1f0-1f1fe.png
new file mode 100644
index 000000000..40daa4da5
Binary files /dev/null and b/images/emoji/1f1f0-1f1fe.png differ
diff --git a/images/emoji/1f1f0-1f1ff.png b/images/emoji/1f1f0-1f1ff.png
new file mode 100644
index 000000000..2f97a8fd3
Binary files /dev/null and b/images/emoji/1f1f0-1f1ff.png differ
diff --git a/images/emoji/1f1f0.png b/images/emoji/1f1f0.png
new file mode 100644
index 000000000..204b95d1b
Binary files /dev/null and b/images/emoji/1f1f0.png differ
diff --git a/images/emoji/1f1f1-1f1e6.png b/images/emoji/1f1f1-1f1e6.png
new file mode 100644
index 000000000..4d4179f34
Binary files /dev/null and b/images/emoji/1f1f1-1f1e6.png differ
diff --git a/images/emoji/1f1f1-1f1e7.png b/images/emoji/1f1f1-1f1e7.png
new file mode 100644
index 000000000..3d5944670
Binary files /dev/null and b/images/emoji/1f1f1-1f1e7.png differ
diff --git a/images/emoji/1f1f1-1f1e8.png b/images/emoji/1f1f1-1f1e8.png
new file mode 100644
index 000000000..45547b1e4
Binary files /dev/null and b/images/emoji/1f1f1-1f1e8.png differ
diff --git a/images/emoji/1f1f1-1f1ee.png b/images/emoji/1f1f1-1f1ee.png
new file mode 100644
index 000000000..0eafa6a22
Binary files /dev/null and b/images/emoji/1f1f1-1f1ee.png differ
diff --git a/images/emoji/1f1f1-1f1f0.png b/images/emoji/1f1f1-1f1f0.png
new file mode 100644
index 000000000..ab4fe10c4
Binary files /dev/null and b/images/emoji/1f1f1-1f1f0.png differ
diff --git a/images/emoji/1f1f1-1f1f7.png b/images/emoji/1f1f1-1f1f7.png
new file mode 100644
index 000000000..f66f267fe
Binary files /dev/null and b/images/emoji/1f1f1-1f1f7.png differ
diff --git a/images/emoji/1f1f1-1f1f8.png b/images/emoji/1f1f1-1f1f8.png
new file mode 100644
index 000000000..24745631e
Binary files /dev/null and b/images/emoji/1f1f1-1f1f8.png differ
diff --git a/images/emoji/1f1f1-1f1f9.png b/images/emoji/1f1f1-1f1f9.png
new file mode 100644
index 000000000..d644b56d6
Binary files /dev/null and b/images/emoji/1f1f1-1f1f9.png differ
diff --git a/images/emoji/1f1f1-1f1fa.png b/images/emoji/1f1f1-1f1fa.png
new file mode 100644
index 000000000..a2df9c929
Binary files /dev/null and b/images/emoji/1f1f1-1f1fa.png differ
diff --git a/images/emoji/1f1f1-1f1fb.png b/images/emoji/1f1f1-1f1fb.png
new file mode 100644
index 000000000..ae680d5f0
Binary files /dev/null and b/images/emoji/1f1f1-1f1fb.png differ
diff --git a/images/emoji/1f1f1-1f1fe.png b/images/emoji/1f1f1-1f1fe.png
new file mode 100644
index 000000000..f6e77b0f3
Binary files /dev/null and b/images/emoji/1f1f1-1f1fe.png differ
diff --git a/images/emoji/1f1f1.png b/images/emoji/1f1f1.png
new file mode 100644
index 000000000..7992b4f68
Binary files /dev/null and b/images/emoji/1f1f1.png differ
diff --git a/images/emoji/1f1f2-1f1e6.png b/images/emoji/1f1f2-1f1e6.png
new file mode 100644
index 000000000..c4a056722
Binary files /dev/null and b/images/emoji/1f1f2-1f1e6.png differ
diff --git a/images/emoji/1f1f2-1f1e8.png b/images/emoji/1f1f2-1f1e8.png
new file mode 100644
index 000000000..d479eab98
Binary files /dev/null and b/images/emoji/1f1f2-1f1e8.png differ
diff --git a/images/emoji/1f1f2-1f1e9.png b/images/emoji/1f1f2-1f1e9.png
new file mode 100644
index 000000000..a7a725398
Binary files /dev/null and b/images/emoji/1f1f2-1f1e9.png differ
diff --git a/images/emoji/1f1f2-1f1ea.png b/images/emoji/1f1f2-1f1ea.png
new file mode 100644
index 000000000..7c771e7e1
Binary files /dev/null and b/images/emoji/1f1f2-1f1ea.png differ
diff --git a/images/emoji/1f1f2-1f1eb.png b/images/emoji/1f1f2-1f1eb.png
new file mode 100644
index 000000000..70c761036
Binary files /dev/null and b/images/emoji/1f1f2-1f1eb.png differ
diff --git a/images/emoji/1f1f2-1f1ec.png b/images/emoji/1f1f2-1f1ec.png
new file mode 100644
index 000000000..2f3ccdda7
Binary files /dev/null and b/images/emoji/1f1f2-1f1ec.png differ
diff --git a/images/emoji/1f1f2-1f1ed.png b/images/emoji/1f1f2-1f1ed.png
new file mode 100644
index 000000000..598016481
Binary files /dev/null and b/images/emoji/1f1f2-1f1ed.png differ
diff --git a/images/emoji/1f1f2-1f1f0.png b/images/emoji/1f1f2-1f1f0.png
new file mode 100644
index 000000000..7ba775ee7
Binary files /dev/null and b/images/emoji/1f1f2-1f1f0.png differ
diff --git a/images/emoji/1f1f2-1f1f1.png b/images/emoji/1f1f2-1f1f1.png
new file mode 100644
index 000000000..683437854
Binary files /dev/null and b/images/emoji/1f1f2-1f1f1.png differ
diff --git a/images/emoji/1f1f2-1f1f2.png b/images/emoji/1f1f2-1f1f2.png
new file mode 100644
index 000000000..37dc7d715
Binary files /dev/null and b/images/emoji/1f1f2-1f1f2.png differ
diff --git a/images/emoji/1f1f2-1f1f3.png b/images/emoji/1f1f2-1f1f3.png
new file mode 100644
index 000000000..1f146bbcd
Binary files /dev/null and b/images/emoji/1f1f2-1f1f3.png differ
diff --git a/images/emoji/1f1f2-1f1f4.png b/images/emoji/1f1f2-1f1f4.png
new file mode 100644
index 000000000..7edde31f6
Binary files /dev/null and b/images/emoji/1f1f2-1f1f4.png differ
diff --git a/images/emoji/1f1f2-1f1f5.png b/images/emoji/1f1f2-1f1f5.png
new file mode 100644
index 000000000..17ec1c441
Binary files /dev/null and b/images/emoji/1f1f2-1f1f5.png differ
diff --git a/images/emoji/1f1f2-1f1f6.png b/images/emoji/1f1f2-1f1f6.png
new file mode 100644
index 000000000..1e672dc90
Binary files /dev/null and b/images/emoji/1f1f2-1f1f6.png differ
diff --git a/images/emoji/1f1f2-1f1f7.png b/images/emoji/1f1f2-1f1f7.png
new file mode 100644
index 000000000..f87de46ef
Binary files /dev/null and b/images/emoji/1f1f2-1f1f7.png differ
diff --git a/images/emoji/1f1f2-1f1f8.png b/images/emoji/1f1f2-1f1f8.png
new file mode 100644
index 000000000..480b0d4eb
Binary files /dev/null and b/images/emoji/1f1f2-1f1f8.png differ
diff --git a/images/emoji/1f1f2-1f1f9.png b/images/emoji/1f1f2-1f1f9.png
new file mode 100644
index 000000000..c9e1dbdce
Binary files /dev/null and b/images/emoji/1f1f2-1f1f9.png differ
diff --git a/images/emoji/1f1f2-1f1fa.png b/images/emoji/1f1f2-1f1fa.png
new file mode 100644
index 000000000..55b33cb7c
Binary files /dev/null and b/images/emoji/1f1f2-1f1fa.png differ
diff --git a/images/emoji/1f1f2-1f1fb.png b/images/emoji/1f1f2-1f1fb.png
new file mode 100644
index 000000000..ce5867126
Binary files /dev/null and b/images/emoji/1f1f2-1f1fb.png differ
diff --git a/images/emoji/1f1f2-1f1fc.png b/images/emoji/1f1f2-1f1fc.png
new file mode 100644
index 000000000..003d85484
Binary files /dev/null and b/images/emoji/1f1f2-1f1fc.png differ
diff --git a/images/emoji/1f1f2-1f1fd.png b/images/emoji/1f1f2-1f1fd.png
new file mode 100644
index 000000000..42572bcd0
Binary files /dev/null and b/images/emoji/1f1f2-1f1fd.png differ
diff --git a/images/emoji/1f1f2-1f1fe.png b/images/emoji/1f1f2-1f1fe.png
new file mode 100644
index 000000000..17526c267
Binary files /dev/null and b/images/emoji/1f1f2-1f1fe.png differ
diff --git a/images/emoji/1f1f2-1f1ff.png b/images/emoji/1f1f2-1f1ff.png
new file mode 100644
index 000000000..2352a78e7
Binary files /dev/null and b/images/emoji/1f1f2-1f1ff.png differ
diff --git a/images/emoji/1f1f2.png b/images/emoji/1f1f2.png
new file mode 100644
index 000000000..7b848b2ce
Binary files /dev/null and b/images/emoji/1f1f2.png differ
diff --git a/images/emoji/1f1f3-1f1e6.png b/images/emoji/1f1f3-1f1e6.png
new file mode 100644
index 000000000..ed31c3df0
Binary files /dev/null and b/images/emoji/1f1f3-1f1e6.png differ
diff --git a/images/emoji/1f1f3-1f1e8.png b/images/emoji/1f1f3-1f1e8.png
new file mode 100644
index 000000000..3c57ee942
Binary files /dev/null and b/images/emoji/1f1f3-1f1e8.png differ
diff --git a/images/emoji/1f1f3-1f1ea.png b/images/emoji/1f1f3-1f1ea.png
new file mode 100644
index 000000000..f98a1173c
Binary files /dev/null and b/images/emoji/1f1f3-1f1ea.png differ
diff --git a/images/emoji/1f1f3-1f1eb.png b/images/emoji/1f1f3-1f1eb.png
new file mode 100644
index 000000000..9099e7674
Binary files /dev/null and b/images/emoji/1f1f3-1f1eb.png differ
diff --git a/images/emoji/1f1f3-1f1ec.png b/images/emoji/1f1f3-1f1ec.png
new file mode 100644
index 000000000..ea0abeff1
Binary files /dev/null and b/images/emoji/1f1f3-1f1ec.png differ
diff --git a/images/emoji/1f1f3-1f1ee.png b/images/emoji/1f1f3-1f1ee.png
new file mode 100644
index 000000000..772920dfa
Binary files /dev/null and b/images/emoji/1f1f3-1f1ee.png differ
diff --git a/images/emoji/1f1f3-1f1f1.png b/images/emoji/1f1f3-1f1f1.png
new file mode 100644
index 000000000..83a0e817e
Binary files /dev/null and b/images/emoji/1f1f3-1f1f1.png differ
diff --git a/images/emoji/1f1f3-1f1f4.png b/images/emoji/1f1f3-1f1f4.png
new file mode 100644
index 000000000..99d3142eb
Binary files /dev/null and b/images/emoji/1f1f3-1f1f4.png differ
diff --git a/images/emoji/1f1f3-1f1f5.png b/images/emoji/1f1f3-1f1f5.png
new file mode 100644
index 000000000..87425a8df
Binary files /dev/null and b/images/emoji/1f1f3-1f1f5.png differ
diff --git a/images/emoji/1f1f3-1f1f7.png b/images/emoji/1f1f3-1f1f7.png
new file mode 100644
index 000000000..b3e3a5d56
Binary files /dev/null and b/images/emoji/1f1f3-1f1f7.png differ
diff --git a/images/emoji/1f1f3-1f1fa.png b/images/emoji/1f1f3-1f1fa.png
new file mode 100644
index 000000000..f03614443
Binary files /dev/null and b/images/emoji/1f1f3-1f1fa.png differ
diff --git a/images/emoji/1f1f3-1f1ff.png b/images/emoji/1f1f3-1f1ff.png
new file mode 100644
index 000000000..a4eeeab9c
Binary files /dev/null and b/images/emoji/1f1f3-1f1ff.png differ
diff --git a/images/emoji/1f1f3.png b/images/emoji/1f1f3.png
new file mode 100644
index 000000000..4a11e5043
Binary files /dev/null and b/images/emoji/1f1f3.png differ
diff --git a/images/emoji/1f1f4-1f1f2.png b/images/emoji/1f1f4-1f1f2.png
new file mode 100644
index 000000000..ea824ba31
Binary files /dev/null and b/images/emoji/1f1f4-1f1f2.png differ
diff --git a/images/emoji/1f1f4.png b/images/emoji/1f1f4.png
new file mode 100644
index 000000000..2a0760b31
Binary files /dev/null and b/images/emoji/1f1f4.png differ
diff --git a/images/emoji/1f1f5-1f1e6.png b/images/emoji/1f1f5-1f1e6.png
new file mode 100644
index 000000000..c3091d898
Binary files /dev/null and b/images/emoji/1f1f5-1f1e6.png differ
diff --git a/images/emoji/1f1f5-1f1ea.png b/images/emoji/1f1f5-1f1ea.png
new file mode 100644
index 000000000..39223aa9d
Binary files /dev/null and b/images/emoji/1f1f5-1f1ea.png differ
diff --git a/images/emoji/1f1f5-1f1eb.png b/images/emoji/1f1f5-1f1eb.png
new file mode 100644
index 000000000..113445f8f
Binary files /dev/null and b/images/emoji/1f1f5-1f1eb.png differ
diff --git a/images/emoji/1f1f5-1f1ec.png b/images/emoji/1f1f5-1f1ec.png
new file mode 100644
index 000000000..825e9dcb7
Binary files /dev/null and b/images/emoji/1f1f5-1f1ec.png differ
diff --git a/images/emoji/1f1f5-1f1ed.png b/images/emoji/1f1f5-1f1ed.png
new file mode 100644
index 000000000..8260e15bd
Binary files /dev/null and b/images/emoji/1f1f5-1f1ed.png differ
diff --git a/images/emoji/1f1f5-1f1f0.png b/images/emoji/1f1f5-1f1f0.png
new file mode 100644
index 000000000..a7b6a1c50
Binary files /dev/null and b/images/emoji/1f1f5-1f1f0.png differ
diff --git a/images/emoji/1f1f5-1f1f1.png b/images/emoji/1f1f5-1f1f1.png
new file mode 100644
index 000000000..19de2edec
Binary files /dev/null and b/images/emoji/1f1f5-1f1f1.png differ
diff --git a/images/emoji/1f1f5-1f1f2.png b/images/emoji/1f1f5-1f1f2.png
new file mode 100644
index 000000000..2ca605541
Binary files /dev/null and b/images/emoji/1f1f5-1f1f2.png differ
diff --git a/images/emoji/1f1f5-1f1f3.png b/images/emoji/1f1f5-1f1f3.png
new file mode 100644
index 000000000..9a6327847
Binary files /dev/null and b/images/emoji/1f1f5-1f1f3.png differ
diff --git a/images/emoji/1f1f5-1f1f7.png b/images/emoji/1f1f5-1f1f7.png
new file mode 100644
index 000000000..d0209cddb
Binary files /dev/null and b/images/emoji/1f1f5-1f1f7.png differ
diff --git a/images/emoji/1f1f5-1f1f8.png b/images/emoji/1f1f5-1f1f8.png
new file mode 100644
index 000000000..7ccab0977
Binary files /dev/null and b/images/emoji/1f1f5-1f1f8.png differ
diff --git a/images/emoji/1f1f5-1f1f9.png b/images/emoji/1f1f5-1f1f9.png
new file mode 100644
index 000000000..cc93f27c6
Binary files /dev/null and b/images/emoji/1f1f5-1f1f9.png differ
diff --git a/images/emoji/1f1f5-1f1fc.png b/images/emoji/1f1f5-1f1fc.png
new file mode 100644
index 000000000..154b2f12d
Binary files /dev/null and b/images/emoji/1f1f5-1f1fc.png differ
diff --git a/images/emoji/1f1f5-1f1fe.png b/images/emoji/1f1f5-1f1fe.png
new file mode 100644
index 000000000..662ad2f6f
Binary files /dev/null and b/images/emoji/1f1f5-1f1fe.png differ
diff --git a/images/emoji/1f1f5.png b/images/emoji/1f1f5.png
new file mode 100644
index 000000000..bcb3298f9
Binary files /dev/null and b/images/emoji/1f1f5.png differ
diff --git a/images/emoji/1f1f6-1f1e6.png b/images/emoji/1f1f6-1f1e6.png
new file mode 100644
index 000000000..a01d8b05c
Binary files /dev/null and b/images/emoji/1f1f6-1f1e6.png differ
diff --git a/images/emoji/1f1f6.png b/images/emoji/1f1f6.png
new file mode 100644
index 000000000..6c92a9dfb
Binary files /dev/null and b/images/emoji/1f1f6.png differ
diff --git a/images/emoji/1f1f7-1f1ea.png b/images/emoji/1f1f7-1f1ea.png
new file mode 100644
index 000000000..57f2bbe9d
Binary files /dev/null and b/images/emoji/1f1f7-1f1ea.png differ
diff --git a/images/emoji/1f1f7-1f1f4.png b/images/emoji/1f1f7-1f1f4.png
new file mode 100644
index 000000000..3e48c4477
Binary files /dev/null and b/images/emoji/1f1f7-1f1f4.png differ
diff --git a/images/emoji/1f1f7-1f1f8.png b/images/emoji/1f1f7-1f1f8.png
new file mode 100644
index 000000000..9df6c9a52
Binary files /dev/null and b/images/emoji/1f1f7-1f1f8.png differ
diff --git a/images/emoji/1f1f7-1f1fa.png b/images/emoji/1f1f7-1f1fa.png
new file mode 100644
index 000000000..e50c9db90
Binary files /dev/null and b/images/emoji/1f1f7-1f1fa.png differ
diff --git a/images/emoji/1f1f7-1f1fc.png b/images/emoji/1f1f7-1f1fc.png
new file mode 100644
index 000000000..c238c874e
Binary files /dev/null and b/images/emoji/1f1f7-1f1fc.png differ
diff --git a/images/emoji/1f1f7.png b/images/emoji/1f1f7.png
new file mode 100644
index 000000000..627892c91
Binary files /dev/null and b/images/emoji/1f1f7.png differ
diff --git a/images/emoji/1f1f8-1f1e6.png b/images/emoji/1f1f8-1f1e6.png
new file mode 100644
index 000000000..4941be7d1
Binary files /dev/null and b/images/emoji/1f1f8-1f1e6.png differ
diff --git a/images/emoji/1f1f8-1f1e7.png b/images/emoji/1f1f8-1f1e7.png
new file mode 100644
index 000000000..7d8f1ac61
Binary files /dev/null and b/images/emoji/1f1f8-1f1e7.png differ
diff --git a/images/emoji/1f1f8-1f1e8.png b/images/emoji/1f1f8-1f1e8.png
new file mode 100644
index 000000000..6ae4d9076
Binary files /dev/null and b/images/emoji/1f1f8-1f1e8.png differ
diff --git a/images/emoji/1f1f8-1f1e9.png b/images/emoji/1f1f8-1f1e9.png
new file mode 100644
index 000000000..963be1b36
Binary files /dev/null and b/images/emoji/1f1f8-1f1e9.png differ
diff --git a/images/emoji/1f1f8-1f1ea.png b/images/emoji/1f1f8-1f1ea.png
new file mode 100644
index 000000000..fc0d0e0ce
Binary files /dev/null and b/images/emoji/1f1f8-1f1ea.png differ
diff --git a/images/emoji/1f1f8-1f1ec.png b/images/emoji/1f1f8-1f1ec.png
new file mode 100644
index 000000000..de3c7737c
Binary files /dev/null and b/images/emoji/1f1f8-1f1ec.png differ
diff --git a/images/emoji/1f1f8-1f1ed.png b/images/emoji/1f1f8-1f1ed.png
new file mode 100644
index 000000000..40cd9e44e
Binary files /dev/null and b/images/emoji/1f1f8-1f1ed.png differ
diff --git a/images/emoji/1f1f8-1f1ee.png b/images/emoji/1f1f8-1f1ee.png
new file mode 100644
index 000000000..e308999db
Binary files /dev/null and b/images/emoji/1f1f8-1f1ee.png differ
diff --git a/images/emoji/1f1f8-1f1ef.png b/images/emoji/1f1f8-1f1ef.png
new file mode 100644
index 000000000..5884e6482
Binary files /dev/null and b/images/emoji/1f1f8-1f1ef.png differ
diff --git a/images/emoji/1f1f8-1f1f0.png b/images/emoji/1f1f8-1f1f0.png
new file mode 100644
index 000000000..4259d0e14
Binary files /dev/null and b/images/emoji/1f1f8-1f1f0.png differ
diff --git a/images/emoji/1f1f8-1f1f1.png b/images/emoji/1f1f8-1f1f1.png
new file mode 100644
index 000000000..d2cc68830
Binary files /dev/null and b/images/emoji/1f1f8-1f1f1.png differ
diff --git a/images/emoji/1f1f8-1f1f2.png b/images/emoji/1f1f8-1f1f2.png
new file mode 100644
index 000000000..b96ba87d0
Binary files /dev/null and b/images/emoji/1f1f8-1f1f2.png differ
diff --git a/images/emoji/1f1f8-1f1f3.png b/images/emoji/1f1f8-1f1f3.png
new file mode 100644
index 000000000..5368bbe93
Binary files /dev/null and b/images/emoji/1f1f8-1f1f3.png differ
diff --git a/images/emoji/1f1f8-1f1f4.png b/images/emoji/1f1f8-1f1f4.png
new file mode 100644
index 000000000..68a059736
Binary files /dev/null and b/images/emoji/1f1f8-1f1f4.png differ
diff --git a/images/emoji/1f1f8-1f1f7.png b/images/emoji/1f1f8-1f1f7.png
new file mode 100644
index 000000000..d32513270
Binary files /dev/null and b/images/emoji/1f1f8-1f1f7.png differ
diff --git a/images/emoji/1f1f8-1f1f8.png b/images/emoji/1f1f8-1f1f8.png
new file mode 100644
index 000000000..122977e79
Binary files /dev/null and b/images/emoji/1f1f8-1f1f8.png differ
diff --git a/images/emoji/1f1f8-1f1f9.png b/images/emoji/1f1f8-1f1f9.png
new file mode 100644
index 000000000..f83a863d6
Binary files /dev/null and b/images/emoji/1f1f8-1f1f9.png differ
diff --git a/images/emoji/1f1f8-1f1fb.png b/images/emoji/1f1f8-1f1fb.png
new file mode 100644
index 000000000..efb83e2f2
Binary files /dev/null and b/images/emoji/1f1f8-1f1fb.png differ
diff --git a/images/emoji/1f1f8-1f1fd.png b/images/emoji/1f1f8-1f1fd.png
new file mode 100644
index 000000000..94b760fbe
Binary files /dev/null and b/images/emoji/1f1f8-1f1fd.png differ
diff --git a/images/emoji/1f1f8-1f1fe.png b/images/emoji/1f1f8-1f1fe.png
new file mode 100644
index 000000000..09a8ee8f7
Binary files /dev/null and b/images/emoji/1f1f8-1f1fe.png differ
diff --git a/images/emoji/1f1f8-1f1ff.png b/images/emoji/1f1f8-1f1ff.png
new file mode 100644
index 000000000..f74e82ea1
Binary files /dev/null and b/images/emoji/1f1f8-1f1ff.png differ
diff --git a/images/emoji/1f1f8.png b/images/emoji/1f1f8.png
new file mode 100644
index 000000000..9d0dbf93a
Binary files /dev/null and b/images/emoji/1f1f8.png differ
diff --git a/images/emoji/1f1f9-1f1e6.png b/images/emoji/1f1f9-1f1e6.png
new file mode 100644
index 000000000..b44283e90
Binary files /dev/null and b/images/emoji/1f1f9-1f1e6.png differ
diff --git a/images/emoji/1f1f9-1f1e8.png b/images/emoji/1f1f9-1f1e8.png
new file mode 100644
index 000000000..156b33d1b
Binary files /dev/null and b/images/emoji/1f1f9-1f1e8.png differ
diff --git a/images/emoji/1f1f9-1f1e9.png b/images/emoji/1f1f9-1f1e9.png
new file mode 100644
index 000000000..ebe7f5928
Binary files /dev/null and b/images/emoji/1f1f9-1f1e9.png differ
diff --git a/images/emoji/1f1f9-1f1eb.png b/images/emoji/1f1f9-1f1eb.png
new file mode 100644
index 000000000..a1a3ad68e
Binary files /dev/null and b/images/emoji/1f1f9-1f1eb.png differ
diff --git a/images/emoji/1f1f9-1f1ec.png b/images/emoji/1f1f9-1f1ec.png
new file mode 100644
index 000000000..826b73c9a
Binary files /dev/null and b/images/emoji/1f1f9-1f1ec.png differ
diff --git a/images/emoji/1f1f9-1f1ed.png b/images/emoji/1f1f9-1f1ed.png
new file mode 100644
index 000000000..93ff542c5
Binary files /dev/null and b/images/emoji/1f1f9-1f1ed.png differ
diff --git a/images/emoji/1f1f9-1f1ef.png b/images/emoji/1f1f9-1f1ef.png
new file mode 100644
index 000000000..7a8a0b619
Binary files /dev/null and b/images/emoji/1f1f9-1f1ef.png differ
diff --git a/images/emoji/1f1f9-1f1f0.png b/images/emoji/1f1f9-1f1f0.png
new file mode 100644
index 000000000..2fa5a21b1
Binary files /dev/null and b/images/emoji/1f1f9-1f1f0.png differ
diff --git a/images/emoji/1f1f9-1f1f1.png b/images/emoji/1f1f9-1f1f1.png
new file mode 100644
index 000000000..5b120eccc
Binary files /dev/null and b/images/emoji/1f1f9-1f1f1.png differ
diff --git a/images/emoji/1f1f9-1f1f2.png b/images/emoji/1f1f9-1f1f2.png
new file mode 100644
index 000000000..c3c4f5323
Binary files /dev/null and b/images/emoji/1f1f9-1f1f2.png differ
diff --git a/images/emoji/1f1f9-1f1f3.png b/images/emoji/1f1f9-1f1f3.png
new file mode 100644
index 000000000..58ef16122
Binary files /dev/null and b/images/emoji/1f1f9-1f1f3.png differ
diff --git a/images/emoji/1f1f9-1f1f4.png b/images/emoji/1f1f9-1f1f4.png
new file mode 100644
index 000000000..1ffa7bb9d
Binary files /dev/null and b/images/emoji/1f1f9-1f1f4.png differ
diff --git a/images/emoji/1f1f9-1f1f7.png b/images/emoji/1f1f9-1f1f7.png
new file mode 100644
index 000000000..325251fae
Binary files /dev/null and b/images/emoji/1f1f9-1f1f7.png differ
diff --git a/images/emoji/1f1f9-1f1f9.png b/images/emoji/1f1f9-1f1f9.png
new file mode 100644
index 000000000..ed3bb39a3
Binary files /dev/null and b/images/emoji/1f1f9-1f1f9.png differ
diff --git a/images/emoji/1f1f9-1f1fb.png b/images/emoji/1f1f9-1f1fb.png
new file mode 100644
index 000000000..e82c65c7b
Binary files /dev/null and b/images/emoji/1f1f9-1f1fb.png differ
diff --git a/images/emoji/1f1f9-1f1fc.png b/images/emoji/1f1f9-1f1fc.png
new file mode 100644
index 000000000..3a8f00b59
Binary files /dev/null and b/images/emoji/1f1f9-1f1fc.png differ
diff --git a/images/emoji/1f1f9-1f1ff.png b/images/emoji/1f1f9-1f1ff.png
new file mode 100644
index 000000000..2a020853d
Binary files /dev/null and b/images/emoji/1f1f9-1f1ff.png differ
diff --git a/images/emoji/1f1f9.png b/images/emoji/1f1f9.png
new file mode 100644
index 000000000..2d882f66b
Binary files /dev/null and b/images/emoji/1f1f9.png differ
diff --git a/images/emoji/1f1fa-1f1e6.png b/images/emoji/1f1fa-1f1e6.png
new file mode 100644
index 000000000..cd84d1bbd
Binary files /dev/null and b/images/emoji/1f1fa-1f1e6.png differ
diff --git a/images/emoji/1f1fa-1f1ec.png b/images/emoji/1f1fa-1f1ec.png
new file mode 100644
index 000000000..dc97690eb
Binary files /dev/null and b/images/emoji/1f1fa-1f1ec.png differ
diff --git a/images/emoji/1f1fa-1f1f2.png b/images/emoji/1f1fa-1f1f2.png
new file mode 100644
index 000000000..4a7ee3cdf
Binary files /dev/null and b/images/emoji/1f1fa-1f1f2.png differ
diff --git a/images/emoji/1f1fa-1f1f8.png b/images/emoji/1f1fa-1f1f8.png
new file mode 100644
index 000000000..9f7303058
Binary files /dev/null and b/images/emoji/1f1fa-1f1f8.png differ
diff --git a/images/emoji/1f1fa-1f1fe.png b/images/emoji/1f1fa-1f1fe.png
new file mode 100644
index 000000000..b8002a697
Binary files /dev/null and b/images/emoji/1f1fa-1f1fe.png differ
diff --git a/images/emoji/1f1fa-1f1ff.png b/images/emoji/1f1fa-1f1ff.png
new file mode 100644
index 000000000..d56ca9bc4
Binary files /dev/null and b/images/emoji/1f1fa-1f1ff.png differ
diff --git a/images/emoji/1f1fa.png b/images/emoji/1f1fa.png
new file mode 100644
index 000000000..ae0cabeb1
Binary files /dev/null and b/images/emoji/1f1fa.png differ
diff --git a/images/emoji/1f1fb-1f1e6.png b/images/emoji/1f1fb-1f1e6.png
new file mode 100644
index 000000000..7f0676fc8
Binary files /dev/null and b/images/emoji/1f1fb-1f1e6.png differ
diff --git a/images/emoji/1f1fb-1f1e8.png b/images/emoji/1f1fb-1f1e8.png
new file mode 100644
index 000000000..43703c62a
Binary files /dev/null and b/images/emoji/1f1fb-1f1e8.png differ
diff --git a/images/emoji/1f1fb-1f1ea.png b/images/emoji/1f1fb-1f1ea.png
new file mode 100644
index 000000000..1b6279682
Binary files /dev/null and b/images/emoji/1f1fb-1f1ea.png differ
diff --git a/images/emoji/1f1fb-1f1ec.png b/images/emoji/1f1fb-1f1ec.png
new file mode 100644
index 000000000..536f780f1
Binary files /dev/null and b/images/emoji/1f1fb-1f1ec.png differ
diff --git a/images/emoji/1f1fb-1f1ee.png b/images/emoji/1f1fb-1f1ee.png
new file mode 100644
index 000000000..1b4219cb9
Binary files /dev/null and b/images/emoji/1f1fb-1f1ee.png differ
diff --git a/images/emoji/1f1fb-1f1f3.png b/images/emoji/1f1fb-1f1f3.png
new file mode 100644
index 000000000..427036046
Binary files /dev/null and b/images/emoji/1f1fb-1f1f3.png differ
diff --git a/images/emoji/1f1fb-1f1fa.png b/images/emoji/1f1fb-1f1fa.png
new file mode 100644
index 000000000..706eba440
Binary files /dev/null and b/images/emoji/1f1fb-1f1fa.png differ
diff --git a/images/emoji/1f1fb.png b/images/emoji/1f1fb.png
new file mode 100644
index 000000000..e01e179b4
Binary files /dev/null and b/images/emoji/1f1fb.png differ
diff --git a/images/emoji/1f1fc-1f1eb.png b/images/emoji/1f1fc-1f1eb.png
new file mode 100644
index 000000000..70c761036
Binary files /dev/null and b/images/emoji/1f1fc-1f1eb.png differ
diff --git a/images/emoji/1f1fc-1f1f8.png b/images/emoji/1f1fc-1f1f8.png
new file mode 100644
index 000000000..a1ea07031
Binary files /dev/null and b/images/emoji/1f1fc-1f1f8.png differ
diff --git a/images/emoji/1f1fc.png b/images/emoji/1f1fc.png
new file mode 100644
index 000000000..e8f614ac8
Binary files /dev/null and b/images/emoji/1f1fc.png differ
diff --git a/images/emoji/1f1fd-1f1f0.png b/images/emoji/1f1fd-1f1f0.png
new file mode 100644
index 000000000..e587a4466
Binary files /dev/null and b/images/emoji/1f1fd-1f1f0.png differ
diff --git a/images/emoji/1f1fd.png b/images/emoji/1f1fd.png
new file mode 100644
index 000000000..e3bedba0b
Binary files /dev/null and b/images/emoji/1f1fd.png differ
diff --git a/images/emoji/1f1fe-1f1ea.png b/images/emoji/1f1fe-1f1ea.png
new file mode 100644
index 000000000..eadfebd5f
Binary files /dev/null and b/images/emoji/1f1fe-1f1ea.png differ
diff --git a/images/emoji/1f1fe-1f1f9.png b/images/emoji/1f1fe-1f1f9.png
new file mode 100644
index 000000000..e55fd8d85
Binary files /dev/null and b/images/emoji/1f1fe-1f1f9.png differ
diff --git a/images/emoji/1f1fe.png b/images/emoji/1f1fe.png
new file mode 100644
index 000000000..9bfa7f2db
Binary files /dev/null and b/images/emoji/1f1fe.png differ
diff --git a/images/emoji/1f1ff-1f1e6.png b/images/emoji/1f1ff-1f1e6.png
new file mode 100644
index 000000000..f397ef507
Binary files /dev/null and b/images/emoji/1f1ff-1f1e6.png differ
diff --git a/images/emoji/1f1ff-1f1f2.png b/images/emoji/1f1ff-1f1f2.png
new file mode 100644
index 000000000..2494a31f6
Binary files /dev/null and b/images/emoji/1f1ff-1f1f2.png differ
diff --git a/images/emoji/1f1ff-1f1fc.png b/images/emoji/1f1ff-1f1fc.png
new file mode 100644
index 000000000..e09b9652b
Binary files /dev/null and b/images/emoji/1f1ff-1f1fc.png differ
diff --git a/images/emoji/1f1ff.png b/images/emoji/1f1ff.png
new file mode 100644
index 000000000..5bf03f100
Binary files /dev/null and b/images/emoji/1f1ff.png differ
diff --git a/images/emoji/1f201.png b/images/emoji/1f201.png
new file mode 100644
index 000000000..6450eb44d
Binary files /dev/null and b/images/emoji/1f201.png differ
diff --git a/images/emoji/1f202.png b/images/emoji/1f202.png
new file mode 100644
index 000000000..900f96332
Binary files /dev/null and b/images/emoji/1f202.png differ
diff --git a/images/emoji/1f21a.png b/images/emoji/1f21a.png
new file mode 100644
index 000000000..d3a19b420
Binary files /dev/null and b/images/emoji/1f21a.png differ
diff --git a/images/emoji/1f22f.png b/images/emoji/1f22f.png
new file mode 100644
index 000000000..078e23e4f
Binary files /dev/null and b/images/emoji/1f22f.png differ
diff --git a/images/emoji/1f232.png b/images/emoji/1f232.png
new file mode 100644
index 000000000..4c704e034
Binary files /dev/null and b/images/emoji/1f232.png differ
diff --git a/images/emoji/1f233.png b/images/emoji/1f233.png
new file mode 100644
index 000000000..47966c1ea
Binary files /dev/null and b/images/emoji/1f233.png differ
diff --git a/images/emoji/1f234.png b/images/emoji/1f234.png
new file mode 100644
index 000000000..8375ad9d9
Binary files /dev/null and b/images/emoji/1f234.png differ
diff --git a/images/emoji/1f235.png b/images/emoji/1f235.png
new file mode 100644
index 000000000..f9dea8b88
Binary files /dev/null and b/images/emoji/1f235.png differ
diff --git a/images/emoji/1f236.png b/images/emoji/1f236.png
new file mode 100644
index 000000000..a4510de41
Binary files /dev/null and b/images/emoji/1f236.png differ
diff --git a/images/emoji/1f237.png b/images/emoji/1f237.png
new file mode 100644
index 000000000..c41bd36a2
Binary files /dev/null and b/images/emoji/1f237.png differ
diff --git a/images/emoji/1f238.png b/images/emoji/1f238.png
new file mode 100644
index 000000000..6b7af0ee2
Binary files /dev/null and b/images/emoji/1f238.png differ
diff --git a/images/emoji/1f239.png b/images/emoji/1f239.png
new file mode 100644
index 000000000..c4f837fe6
Binary files /dev/null and b/images/emoji/1f239.png differ
diff --git a/images/emoji/1f23a.png b/images/emoji/1f23a.png
new file mode 100644
index 000000000..d21cb30ea
Binary files /dev/null and b/images/emoji/1f23a.png differ
diff --git a/images/emoji/1f250.png b/images/emoji/1f250.png
new file mode 100644
index 000000000..0c0d589ca
Binary files /dev/null and b/images/emoji/1f250.png differ
diff --git a/images/emoji/1f251.png b/images/emoji/1f251.png
new file mode 100644
index 000000000..8afd7ce99
Binary files /dev/null and b/images/emoji/1f251.png differ
diff --git a/images/emoji/1f300.png b/images/emoji/1f300.png
new file mode 100644
index 000000000..ff00b1afe
Binary files /dev/null and b/images/emoji/1f300.png differ
diff --git a/images/emoji/1f301.png b/images/emoji/1f301.png
new file mode 100644
index 000000000..57702d8d3
Binary files /dev/null and b/images/emoji/1f301.png differ
diff --git a/images/emoji/1f302.png b/images/emoji/1f302.png
new file mode 100644
index 000000000..ecefba9e4
Binary files /dev/null and b/images/emoji/1f302.png differ
diff --git a/images/emoji/1f303.png b/images/emoji/1f303.png
new file mode 100644
index 000000000..ca2018f45
Binary files /dev/null and b/images/emoji/1f303.png differ
diff --git a/images/emoji/1f304.png b/images/emoji/1f304.png
new file mode 100644
index 000000000..39c57c86a
Binary files /dev/null and b/images/emoji/1f304.png differ
diff --git a/images/emoji/1f305.png b/images/emoji/1f305.png
new file mode 100644
index 000000000..4ad36003c
Binary files /dev/null and b/images/emoji/1f305.png differ
diff --git a/images/emoji/1f306.png b/images/emoji/1f306.png
new file mode 100644
index 000000000..80cdff7cf
Binary files /dev/null and b/images/emoji/1f306.png differ
diff --git a/images/emoji/1f307.png b/images/emoji/1f307.png
new file mode 100644
index 000000000..7cded0ba5
Binary files /dev/null and b/images/emoji/1f307.png differ
diff --git a/images/emoji/1f308.png b/images/emoji/1f308.png
new file mode 100644
index 000000000..154735d71
Binary files /dev/null and b/images/emoji/1f308.png differ
diff --git a/images/emoji/1f309.png b/images/emoji/1f309.png
new file mode 100644
index 000000000..1d444e0be
Binary files /dev/null and b/images/emoji/1f309.png differ
diff --git a/images/emoji/1f30a.png b/images/emoji/1f30a.png
new file mode 100644
index 000000000..45ff1e877
Binary files /dev/null and b/images/emoji/1f30a.png differ
diff --git a/images/emoji/1f30b.png b/images/emoji/1f30b.png
new file mode 100644
index 000000000..adb522980
Binary files /dev/null and b/images/emoji/1f30b.png differ
diff --git a/images/emoji/1f30c.png b/images/emoji/1f30c.png
new file mode 100644
index 000000000..b2b8ac59c
Binary files /dev/null and b/images/emoji/1f30c.png differ
diff --git a/images/emoji/1f30d.png b/images/emoji/1f30d.png
new file mode 100644
index 000000000..66c3348c2
Binary files /dev/null and b/images/emoji/1f30d.png differ
diff --git a/images/emoji/1f30e.png b/images/emoji/1f30e.png
new file mode 100644
index 000000000..538c3cddd
Binary files /dev/null and b/images/emoji/1f30e.png differ
diff --git a/images/emoji/1f30f.png b/images/emoji/1f30f.png
new file mode 100644
index 000000000..d8df97fec
Binary files /dev/null and b/images/emoji/1f30f.png differ
diff --git a/images/emoji/1f310.png b/images/emoji/1f310.png
new file mode 100644
index 000000000..82450c1a4
Binary files /dev/null and b/images/emoji/1f310.png differ
diff --git a/images/emoji/1f311.png b/images/emoji/1f311.png
new file mode 100644
index 000000000..ecff72caa
Binary files /dev/null and b/images/emoji/1f311.png differ
diff --git a/images/emoji/1f312.png b/images/emoji/1f312.png
new file mode 100644
index 000000000..921224a34
Binary files /dev/null and b/images/emoji/1f312.png differ
diff --git a/images/emoji/1f313.png b/images/emoji/1f313.png
new file mode 100644
index 000000000..5dccaf72a
Binary files /dev/null and b/images/emoji/1f313.png differ
diff --git a/images/emoji/1f314.png b/images/emoji/1f314.png
new file mode 100644
index 000000000..3a8081563
Binary files /dev/null and b/images/emoji/1f314.png differ
diff --git a/images/emoji/1f315.png b/images/emoji/1f315.png
new file mode 100644
index 000000000..c9a2d6aa7
Binary files /dev/null and b/images/emoji/1f315.png differ
diff --git a/images/emoji/1f316.png b/images/emoji/1f316.png
new file mode 100644
index 000000000..741bd5931
Binary files /dev/null and b/images/emoji/1f316.png differ
diff --git a/images/emoji/1f317.png b/images/emoji/1f317.png
new file mode 100644
index 000000000..0842a0dd4
Binary files /dev/null and b/images/emoji/1f317.png differ
diff --git a/images/emoji/1f318.png b/images/emoji/1f318.png
new file mode 100644
index 000000000..cf68706b8
Binary files /dev/null and b/images/emoji/1f318.png differ
diff --git a/images/emoji/1f319.png b/images/emoji/1f319.png
new file mode 100644
index 000000000..765420ece
Binary files /dev/null and b/images/emoji/1f319.png differ
diff --git a/images/emoji/1f31a.png b/images/emoji/1f31a.png
new file mode 100644
index 000000000..150dd1240
Binary files /dev/null and b/images/emoji/1f31a.png differ
diff --git a/images/emoji/1f31b.png b/images/emoji/1f31b.png
new file mode 100644
index 000000000..cd8a3d7ac
Binary files /dev/null and b/images/emoji/1f31b.png differ
diff --git a/images/emoji/1f31c.png b/images/emoji/1f31c.png
new file mode 100644
index 000000000..94099343c
Binary files /dev/null and b/images/emoji/1f31c.png differ
diff --git a/images/emoji/1f31d.png b/images/emoji/1f31d.png
new file mode 100644
index 000000000..a5c25bbaf
Binary files /dev/null and b/images/emoji/1f31d.png differ
diff --git a/images/emoji/1f31e.png b/images/emoji/1f31e.png
new file mode 100644
index 000000000..14a4ea971
Binary files /dev/null and b/images/emoji/1f31e.png differ
diff --git a/images/emoji/1f31f.png b/images/emoji/1f31f.png
new file mode 100644
index 000000000..2f5cba592
Binary files /dev/null and b/images/emoji/1f31f.png differ
diff --git a/images/emoji/1f320.png b/images/emoji/1f320.png
new file mode 100644
index 000000000..aa45384d1
Binary files /dev/null and b/images/emoji/1f320.png differ
diff --git a/images/emoji/1f321.png b/images/emoji/1f321.png
new file mode 100644
index 000000000..b11473924
Binary files /dev/null and b/images/emoji/1f321.png differ
diff --git a/images/emoji/1f324.png b/images/emoji/1f324.png
new file mode 100644
index 000000000..cead0bfa5
Binary files /dev/null and b/images/emoji/1f324.png differ
diff --git a/images/emoji/1f325.png b/images/emoji/1f325.png
new file mode 100644
index 000000000..0a4cc1002
Binary files /dev/null and b/images/emoji/1f325.png differ
diff --git a/images/emoji/1f326.png b/images/emoji/1f326.png
new file mode 100644
index 000000000..491f9ca48
Binary files /dev/null and b/images/emoji/1f326.png differ
diff --git a/images/emoji/1f327.png b/images/emoji/1f327.png
new file mode 100644
index 000000000..385685e05
Binary files /dev/null and b/images/emoji/1f327.png differ
diff --git a/images/emoji/1f328.png b/images/emoji/1f328.png
new file mode 100644
index 000000000..9720384eb
Binary files /dev/null and b/images/emoji/1f328.png differ
diff --git a/images/emoji/1f329.png b/images/emoji/1f329.png
new file mode 100644
index 000000000..0831e88aa
Binary files /dev/null and b/images/emoji/1f329.png differ
diff --git a/images/emoji/1f32a.png b/images/emoji/1f32a.png
new file mode 100644
index 000000000..4821c89da
Binary files /dev/null and b/images/emoji/1f32a.png differ
diff --git a/images/emoji/1f32b.png b/images/emoji/1f32b.png
new file mode 100644
index 000000000..4e73c2de2
Binary files /dev/null and b/images/emoji/1f32b.png differ
diff --git a/images/emoji/1f32c.png b/images/emoji/1f32c.png
new file mode 100644
index 000000000..df81b652e
Binary files /dev/null and b/images/emoji/1f32c.png differ
diff --git a/images/emoji/1f32d.png b/images/emoji/1f32d.png
new file mode 100644
index 000000000..3c3354d94
Binary files /dev/null and b/images/emoji/1f32d.png differ
diff --git a/images/emoji/1f32e.png b/images/emoji/1f32e.png
new file mode 100644
index 000000000..10e847a46
Binary files /dev/null and b/images/emoji/1f32e.png differ
diff --git a/images/emoji/1f32f.png b/images/emoji/1f32f.png
new file mode 100644
index 000000000..02bd5601d
Binary files /dev/null and b/images/emoji/1f32f.png differ
diff --git a/images/emoji/1f330.png b/images/emoji/1f330.png
new file mode 100644
index 000000000..f8a01e281
Binary files /dev/null and b/images/emoji/1f330.png differ
diff --git a/images/emoji/1f331.png b/images/emoji/1f331.png
new file mode 100644
index 000000000..ae0948bcf
Binary files /dev/null and b/images/emoji/1f331.png differ
diff --git a/images/emoji/1f332.png b/images/emoji/1f332.png
new file mode 100644
index 000000000..f679d8dd7
Binary files /dev/null and b/images/emoji/1f332.png differ
diff --git a/images/emoji/1f333.png b/images/emoji/1f333.png
new file mode 100644
index 000000000..7cd2bc708
Binary files /dev/null and b/images/emoji/1f333.png differ
diff --git a/images/emoji/1f334.png b/images/emoji/1f334.png
new file mode 100644
index 000000000..aaaa6aec3
Binary files /dev/null and b/images/emoji/1f334.png differ
diff --git a/images/emoji/1f335.png b/images/emoji/1f335.png
new file mode 100644
index 000000000..9b48ccf3d
Binary files /dev/null and b/images/emoji/1f335.png differ
diff --git a/images/emoji/1f336.png b/images/emoji/1f336.png
new file mode 100644
index 000000000..266675bd5
Binary files /dev/null and b/images/emoji/1f336.png differ
diff --git a/images/emoji/1f337.png b/images/emoji/1f337.png
new file mode 100644
index 000000000..f799d75c1
Binary files /dev/null and b/images/emoji/1f337.png differ
diff --git a/images/emoji/1f338.png b/images/emoji/1f338.png
new file mode 100644
index 000000000..282f3e7bc
Binary files /dev/null and b/images/emoji/1f338.png differ
diff --git a/images/emoji/1f339.png b/images/emoji/1f339.png
new file mode 100644
index 000000000..52c286d31
Binary files /dev/null and b/images/emoji/1f339.png differ
diff --git a/images/emoji/1f33a.png b/images/emoji/1f33a.png
new file mode 100644
index 000000000..39dd35242
Binary files /dev/null and b/images/emoji/1f33a.png differ
diff --git a/images/emoji/1f33b.png b/images/emoji/1f33b.png
new file mode 100644
index 000000000..08cc07761
Binary files /dev/null and b/images/emoji/1f33b.png differ
diff --git a/images/emoji/1f33c.png b/images/emoji/1f33c.png
new file mode 100644
index 000000000..4083026c1
Binary files /dev/null and b/images/emoji/1f33c.png differ
diff --git a/images/emoji/1f33d.png b/images/emoji/1f33d.png
new file mode 100644
index 000000000..36e201279
Binary files /dev/null and b/images/emoji/1f33d.png differ
diff --git a/images/emoji/1f33e.png b/images/emoji/1f33e.png
new file mode 100644
index 000000000..3564d9d64
Binary files /dev/null and b/images/emoji/1f33e.png differ
diff --git a/images/emoji/1f33f.png b/images/emoji/1f33f.png
new file mode 100644
index 000000000..d984d1562
Binary files /dev/null and b/images/emoji/1f33f.png differ
diff --git a/images/emoji/1f340.png b/images/emoji/1f340.png
new file mode 100644
index 000000000..fdedfcc2b
Binary files /dev/null and b/images/emoji/1f340.png differ
diff --git a/images/emoji/1f341.png b/images/emoji/1f341.png
new file mode 100644
index 000000000..c49acea67
Binary files /dev/null and b/images/emoji/1f341.png differ
diff --git a/images/emoji/1f342.png b/images/emoji/1f342.png
new file mode 100644
index 000000000..0d60e7bdf
Binary files /dev/null and b/images/emoji/1f342.png differ
diff --git a/images/emoji/1f343.png b/images/emoji/1f343.png
new file mode 100644
index 000000000..1e43e1af8
Binary files /dev/null and b/images/emoji/1f343.png differ
diff --git a/images/emoji/1f344.png b/images/emoji/1f344.png
new file mode 100644
index 000000000..dd85742ba
Binary files /dev/null and b/images/emoji/1f344.png differ
diff --git a/images/emoji/1f345.png b/images/emoji/1f345.png
new file mode 100644
index 000000000..497da8f6b
Binary files /dev/null and b/images/emoji/1f345.png differ
diff --git a/images/emoji/1f346.png b/images/emoji/1f346.png
new file mode 100644
index 000000000..fafd7c1a1
Binary files /dev/null and b/images/emoji/1f346.png differ
diff --git a/images/emoji/1f347.png b/images/emoji/1f347.png
new file mode 100644
index 000000000..30d222188
Binary files /dev/null and b/images/emoji/1f347.png differ
diff --git a/images/emoji/1f348.png b/images/emoji/1f348.png
new file mode 100644
index 000000000..c01232d41
Binary files /dev/null and b/images/emoji/1f348.png differ
diff --git a/images/emoji/1f349.png b/images/emoji/1f349.png
new file mode 100644
index 000000000..0761488b4
Binary files /dev/null and b/images/emoji/1f349.png differ
diff --git a/images/emoji/1f34a.png b/images/emoji/1f34a.png
new file mode 100644
index 000000000..ab14e5378
Binary files /dev/null and b/images/emoji/1f34a.png differ
diff --git a/images/emoji/1f34b.png b/images/emoji/1f34b.png
new file mode 100644
index 000000000..9a7d95ca2
Binary files /dev/null and b/images/emoji/1f34b.png differ
diff --git a/images/emoji/1f34c.png b/images/emoji/1f34c.png
new file mode 100644
index 000000000..f49872795
Binary files /dev/null and b/images/emoji/1f34c.png differ
diff --git a/images/emoji/1f34d.png b/images/emoji/1f34d.png
new file mode 100644
index 000000000..d30d73307
Binary files /dev/null and b/images/emoji/1f34d.png differ
diff --git a/images/emoji/1f34e.png b/images/emoji/1f34e.png
new file mode 100644
index 000000000..da650c60f
Binary files /dev/null and b/images/emoji/1f34e.png differ
diff --git a/images/emoji/1f34f.png b/images/emoji/1f34f.png
new file mode 100644
index 000000000..5fd51bd39
Binary files /dev/null and b/images/emoji/1f34f.png differ
diff --git a/images/emoji/1f350.png b/images/emoji/1f350.png
new file mode 100644
index 000000000..3869f718b
Binary files /dev/null and b/images/emoji/1f350.png differ
diff --git a/images/emoji/1f351.png b/images/emoji/1f351.png
new file mode 100644
index 000000000..9ab57cbb7
Binary files /dev/null and b/images/emoji/1f351.png differ
diff --git a/images/emoji/1f352.png b/images/emoji/1f352.png
new file mode 100644
index 000000000..9b10cbaac
Binary files /dev/null and b/images/emoji/1f352.png differ
diff --git a/images/emoji/1f353.png b/images/emoji/1f353.png
new file mode 100644
index 000000000..7bb86f0b2
Binary files /dev/null and b/images/emoji/1f353.png differ
diff --git a/images/emoji/1f354.png b/images/emoji/1f354.png
new file mode 100644
index 000000000..4b13f3b8d
Binary files /dev/null and b/images/emoji/1f354.png differ
diff --git a/images/emoji/1f355.png b/images/emoji/1f355.png
new file mode 100644
index 000000000..240d5c469
Binary files /dev/null and b/images/emoji/1f355.png differ
diff --git a/images/emoji/1f356.png b/images/emoji/1f356.png
new file mode 100644
index 000000000..b20a59d16
Binary files /dev/null and b/images/emoji/1f356.png differ
diff --git a/images/emoji/1f357.png b/images/emoji/1f357.png
new file mode 100644
index 000000000..eea4a53a2
Binary files /dev/null and b/images/emoji/1f357.png differ
diff --git a/images/emoji/1f358.png b/images/emoji/1f358.png
new file mode 100644
index 000000000..7fbd08e4f
Binary files /dev/null and b/images/emoji/1f358.png differ
diff --git a/images/emoji/1f359.png b/images/emoji/1f359.png
new file mode 100644
index 000000000..d3d8ee25c
Binary files /dev/null and b/images/emoji/1f359.png differ
diff --git a/images/emoji/1f35a.png b/images/emoji/1f35a.png
new file mode 100644
index 000000000..6e3ac7956
Binary files /dev/null and b/images/emoji/1f35a.png differ
diff --git a/images/emoji/1f35b.png b/images/emoji/1f35b.png
new file mode 100644
index 000000000..69657ca81
Binary files /dev/null and b/images/emoji/1f35b.png differ
diff --git a/images/emoji/1f35c.png b/images/emoji/1f35c.png
new file mode 100644
index 000000000..c1cb7cd73
Binary files /dev/null and b/images/emoji/1f35c.png differ
diff --git a/images/emoji/1f35d.png b/images/emoji/1f35d.png
new file mode 100644
index 000000000..4f0b7ed07
Binary files /dev/null and b/images/emoji/1f35d.png differ
diff --git a/images/emoji/1f35e.png b/images/emoji/1f35e.png
new file mode 100644
index 000000000..6676510aa
Binary files /dev/null and b/images/emoji/1f35e.png differ
diff --git a/images/emoji/1f35f.png b/images/emoji/1f35f.png
new file mode 100644
index 000000000..3a0899d5a
Binary files /dev/null and b/images/emoji/1f35f.png differ
diff --git a/images/emoji/1f360.png b/images/emoji/1f360.png
new file mode 100644
index 000000000..92a425f2e
Binary files /dev/null and b/images/emoji/1f360.png differ
diff --git a/images/emoji/1f361.png b/images/emoji/1f361.png
new file mode 100644
index 000000000..f73f37b01
Binary files /dev/null and b/images/emoji/1f361.png differ
diff --git a/images/emoji/1f362.png b/images/emoji/1f362.png
new file mode 100644
index 000000000..d38a849fe
Binary files /dev/null and b/images/emoji/1f362.png differ
diff --git a/images/emoji/1f363.png b/images/emoji/1f363.png
new file mode 100644
index 000000000..f171fd2f7
Binary files /dev/null and b/images/emoji/1f363.png differ
diff --git a/images/emoji/1f364.png b/images/emoji/1f364.png
new file mode 100644
index 000000000..752ba7f13
Binary files /dev/null and b/images/emoji/1f364.png differ
diff --git a/images/emoji/1f365.png b/images/emoji/1f365.png
new file mode 100644
index 000000000..157bded65
Binary files /dev/null and b/images/emoji/1f365.png differ
diff --git a/images/emoji/1f366.png b/images/emoji/1f366.png
new file mode 100644
index 000000000..f1f21a3b8
Binary files /dev/null and b/images/emoji/1f366.png differ
diff --git a/images/emoji/1f367.png b/images/emoji/1f367.png
new file mode 100644
index 000000000..36dfb53ca
Binary files /dev/null and b/images/emoji/1f367.png differ
diff --git a/images/emoji/1f368.png b/images/emoji/1f368.png
new file mode 100644
index 000000000..720ae7428
Binary files /dev/null and b/images/emoji/1f368.png differ
diff --git a/images/emoji/1f369.png b/images/emoji/1f369.png
new file mode 100644
index 000000000..0ca4cd0bd
Binary files /dev/null and b/images/emoji/1f369.png differ
diff --git a/images/emoji/1f36a.png b/images/emoji/1f36a.png
new file mode 100644
index 000000000..1b6bcb155
Binary files /dev/null and b/images/emoji/1f36a.png differ
diff --git a/images/emoji/1f36b.png b/images/emoji/1f36b.png
new file mode 100644
index 000000000..318bbd40e
Binary files /dev/null and b/images/emoji/1f36b.png differ
diff --git a/images/emoji/1f36c.png b/images/emoji/1f36c.png
new file mode 100644
index 000000000..8c67ace3a
Binary files /dev/null and b/images/emoji/1f36c.png differ
diff --git a/images/emoji/1f36d.png b/images/emoji/1f36d.png
new file mode 100644
index 000000000..ad76d7bf9
Binary files /dev/null and b/images/emoji/1f36d.png differ
diff --git a/images/emoji/1f36e.png b/images/emoji/1f36e.png
new file mode 100644
index 000000000..fa3df67b8
Binary files /dev/null and b/images/emoji/1f36e.png differ
diff --git a/images/emoji/1f36f.png b/images/emoji/1f36f.png
new file mode 100644
index 000000000..9d8f59295
Binary files /dev/null and b/images/emoji/1f36f.png differ
diff --git a/images/emoji/1f370.png b/images/emoji/1f370.png
new file mode 100644
index 000000000..4368177be
Binary files /dev/null and b/images/emoji/1f370.png differ
diff --git a/images/emoji/1f371.png b/images/emoji/1f371.png
new file mode 100644
index 000000000..92cd17233
Binary files /dev/null and b/images/emoji/1f371.png differ
diff --git a/images/emoji/1f372.png b/images/emoji/1f372.png
new file mode 100644
index 000000000..6b3f010c1
Binary files /dev/null and b/images/emoji/1f372.png differ
diff --git a/images/emoji/1f373.png b/images/emoji/1f373.png
new file mode 100644
index 000000000..918c98057
Binary files /dev/null and b/images/emoji/1f373.png differ
diff --git a/images/emoji/1f374.png b/images/emoji/1f374.png
new file mode 100644
index 000000000..09f1feaea
Binary files /dev/null and b/images/emoji/1f374.png differ
diff --git a/images/emoji/1f375.png b/images/emoji/1f375.png
new file mode 100644
index 000000000..b53b98f0c
Binary files /dev/null and b/images/emoji/1f375.png differ
diff --git a/images/emoji/1f376.png b/images/emoji/1f376.png
new file mode 100644
index 000000000..2933f5672
Binary files /dev/null and b/images/emoji/1f376.png differ
diff --git a/images/emoji/1f377.png b/images/emoji/1f377.png
new file mode 100644
index 000000000..3cc986891
Binary files /dev/null and b/images/emoji/1f377.png differ
diff --git a/images/emoji/1f378.png b/images/emoji/1f378.png
new file mode 100644
index 000000000..2e50c57e9
Binary files /dev/null and b/images/emoji/1f378.png differ
diff --git a/images/emoji/1f379.png b/images/emoji/1f379.png
new file mode 100644
index 000000000..cd714f81b
Binary files /dev/null and b/images/emoji/1f379.png differ
diff --git a/images/emoji/1f37a.png b/images/emoji/1f37a.png
new file mode 100644
index 000000000..894da40a7
Binary files /dev/null and b/images/emoji/1f37a.png differ
diff --git a/images/emoji/1f37b.png b/images/emoji/1f37b.png
new file mode 100644
index 000000000..b55deb66b
Binary files /dev/null and b/images/emoji/1f37b.png differ
diff --git a/images/emoji/1f37c.png b/images/emoji/1f37c.png
new file mode 100644
index 000000000..2bd105241
Binary files /dev/null and b/images/emoji/1f37c.png differ
diff --git a/images/emoji/1f37d.png b/images/emoji/1f37d.png
new file mode 100644
index 000000000..7411755f7
Binary files /dev/null and b/images/emoji/1f37d.png differ
diff --git a/images/emoji/1f37e.png b/images/emoji/1f37e.png
new file mode 100644
index 000000000..285a79a93
Binary files /dev/null and b/images/emoji/1f37e.png differ
diff --git a/images/emoji/1f37f.png b/images/emoji/1f37f.png
new file mode 100644
index 000000000..573ab05af
Binary files /dev/null and b/images/emoji/1f37f.png differ
diff --git a/images/emoji/1f380.png b/images/emoji/1f380.png
new file mode 100644
index 000000000..0f253c3d8
Binary files /dev/null and b/images/emoji/1f380.png differ
diff --git a/images/emoji/1f381.png b/images/emoji/1f381.png
new file mode 100644
index 000000000..844e21645
Binary files /dev/null and b/images/emoji/1f381.png differ
diff --git a/images/emoji/1f382.png b/images/emoji/1f382.png
new file mode 100644
index 000000000..317e9a419
Binary files /dev/null and b/images/emoji/1f382.png differ
diff --git a/images/emoji/1f383.png b/images/emoji/1f383.png
new file mode 100644
index 000000000..44c3fc0ae
Binary files /dev/null and b/images/emoji/1f383.png differ
diff --git a/images/emoji/1f384.png b/images/emoji/1f384.png
new file mode 100644
index 000000000..4197d37a5
Binary files /dev/null and b/images/emoji/1f384.png differ
diff --git a/images/emoji/1f385-1f3fb.png b/images/emoji/1f385-1f3fb.png
new file mode 100644
index 000000000..2052920ab
Binary files /dev/null and b/images/emoji/1f385-1f3fb.png differ
diff --git a/images/emoji/1f385-1f3fc.png b/images/emoji/1f385-1f3fc.png
new file mode 100644
index 000000000..ec9375e14
Binary files /dev/null and b/images/emoji/1f385-1f3fc.png differ
diff --git a/images/emoji/1f385-1f3fd.png b/images/emoji/1f385-1f3fd.png
new file mode 100644
index 000000000..d1d16bceb
Binary files /dev/null and b/images/emoji/1f385-1f3fd.png differ
diff --git a/images/emoji/1f385-1f3fe.png b/images/emoji/1f385-1f3fe.png
new file mode 100644
index 000000000..1088f1c07
Binary files /dev/null and b/images/emoji/1f385-1f3fe.png differ
diff --git a/images/emoji/1f385-1f3ff.png b/images/emoji/1f385-1f3ff.png
new file mode 100644
index 000000000..c92daf749
Binary files /dev/null and b/images/emoji/1f385-1f3ff.png differ
diff --git a/images/emoji/1f385.png b/images/emoji/1f385.png
new file mode 100644
index 000000000..8bf8757a3
Binary files /dev/null and b/images/emoji/1f385.png differ
diff --git a/images/emoji/1f386.png b/images/emoji/1f386.png
new file mode 100644
index 000000000..e0a6c6a7c
Binary files /dev/null and b/images/emoji/1f386.png differ
diff --git a/images/emoji/1f387.png b/images/emoji/1f387.png
new file mode 100644
index 000000000..30339cd6e
Binary files /dev/null and b/images/emoji/1f387.png differ
diff --git a/images/emoji/1f388.png b/images/emoji/1f388.png
new file mode 100644
index 000000000..07916fe6d
Binary files /dev/null and b/images/emoji/1f388.png differ
diff --git a/images/emoji/1f389.png b/images/emoji/1f389.png
new file mode 100644
index 000000000..0244d60f2
Binary files /dev/null and b/images/emoji/1f389.png differ
diff --git a/images/emoji/1f38a.png b/images/emoji/1f38a.png
new file mode 100644
index 000000000..ba4fd9b12
Binary files /dev/null and b/images/emoji/1f38a.png differ
diff --git a/images/emoji/1f38b.png b/images/emoji/1f38b.png
new file mode 100644
index 000000000..46fcb3a1a
Binary files /dev/null and b/images/emoji/1f38b.png differ
diff --git a/images/emoji/1f38c.png b/images/emoji/1f38c.png
new file mode 100644
index 000000000..273bd0f0f
Binary files /dev/null and b/images/emoji/1f38c.png differ
diff --git a/images/emoji/1f38d.png b/images/emoji/1f38d.png
new file mode 100644
index 000000000..769f5ffae
Binary files /dev/null and b/images/emoji/1f38d.png differ
diff --git a/images/emoji/1f38e.png b/images/emoji/1f38e.png
new file mode 100644
index 000000000..109556151
Binary files /dev/null and b/images/emoji/1f38e.png differ
diff --git a/images/emoji/1f38f.png b/images/emoji/1f38f.png
new file mode 100644
index 000000000..5443bab90
Binary files /dev/null and b/images/emoji/1f38f.png differ
diff --git a/images/emoji/1f390.png b/images/emoji/1f390.png
new file mode 100644
index 000000000..3c9ef3a95
Binary files /dev/null and b/images/emoji/1f390.png differ
diff --git a/images/emoji/1f391.png b/images/emoji/1f391.png
new file mode 100644
index 000000000..9bdc9d8d7
Binary files /dev/null and b/images/emoji/1f391.png differ
diff --git a/images/emoji/1f392.png b/images/emoji/1f392.png
new file mode 100644
index 000000000..9997c86e7
Binary files /dev/null and b/images/emoji/1f392.png differ
diff --git a/images/emoji/1f393.png b/images/emoji/1f393.png
new file mode 100644
index 000000000..8b17ddd9d
Binary files /dev/null and b/images/emoji/1f393.png differ
diff --git a/images/emoji/1f396.png b/images/emoji/1f396.png
new file mode 100644
index 000000000..ecd3fb035
Binary files /dev/null and b/images/emoji/1f396.png differ
diff --git a/images/emoji/1f397.png b/images/emoji/1f397.png
new file mode 100644
index 000000000..3988bbd09
Binary files /dev/null and b/images/emoji/1f397.png differ
diff --git a/images/emoji/1f399.png b/images/emoji/1f399.png
new file mode 100644
index 000000000..cd9167654
Binary files /dev/null and b/images/emoji/1f399.png differ
diff --git a/images/emoji/1f39a.png b/images/emoji/1f39a.png
new file mode 100644
index 000000000..720a3b341
Binary files /dev/null and b/images/emoji/1f39a.png differ
diff --git a/images/emoji/1f39b.png b/images/emoji/1f39b.png
new file mode 100644
index 000000000..6635ac93b
Binary files /dev/null and b/images/emoji/1f39b.png differ
diff --git a/images/emoji/1f39e.png b/images/emoji/1f39e.png
new file mode 100644
index 000000000..30143aedb
Binary files /dev/null and b/images/emoji/1f39e.png differ
diff --git a/images/emoji/1f39f.png b/images/emoji/1f39f.png
new file mode 100644
index 000000000..e510f4a7a
Binary files /dev/null and b/images/emoji/1f39f.png differ
diff --git a/images/emoji/1f3a0.png b/images/emoji/1f3a0.png
new file mode 100644
index 000000000..a17074edf
Binary files /dev/null and b/images/emoji/1f3a0.png differ
diff --git a/images/emoji/1f3a1.png b/images/emoji/1f3a1.png
new file mode 100644
index 000000000..55c8ff047
Binary files /dev/null and b/images/emoji/1f3a1.png differ
diff --git a/images/emoji/1f3a2.png b/images/emoji/1f3a2.png
new file mode 100644
index 000000000..7d187be0c
Binary files /dev/null and b/images/emoji/1f3a2.png differ
diff --git a/images/emoji/1f3a3.png b/images/emoji/1f3a3.png
new file mode 100644
index 000000000..dfcdf07eb
Binary files /dev/null and b/images/emoji/1f3a3.png differ
diff --git a/images/emoji/1f3a4.png b/images/emoji/1f3a4.png
new file mode 100644
index 000000000..d4e6b0def
Binary files /dev/null and b/images/emoji/1f3a4.png differ
diff --git a/images/emoji/1f3a5.png b/images/emoji/1f3a5.png
new file mode 100644
index 000000000..4e73b1301
Binary files /dev/null and b/images/emoji/1f3a5.png differ
diff --git a/images/emoji/1f3a6.png b/images/emoji/1f3a6.png
new file mode 100644
index 000000000..65f27b386
Binary files /dev/null and b/images/emoji/1f3a6.png differ
diff --git a/images/emoji/1f3a7.png b/images/emoji/1f3a7.png
new file mode 100644
index 000000000..e9fd34041
Binary files /dev/null and b/images/emoji/1f3a7.png differ
diff --git a/images/emoji/1f3a8.png b/images/emoji/1f3a8.png
new file mode 100644
index 000000000..bd6afe9ff
Binary files /dev/null and b/images/emoji/1f3a8.png differ
diff --git a/images/emoji/1f3a9.png b/images/emoji/1f3a9.png
new file mode 100644
index 000000000..131b657b1
Binary files /dev/null and b/images/emoji/1f3a9.png differ
diff --git a/images/emoji/1f3aa.png b/images/emoji/1f3aa.png
new file mode 100644
index 000000000..b0379775b
Binary files /dev/null and b/images/emoji/1f3aa.png differ
diff --git a/images/emoji/1f3ab.png b/images/emoji/1f3ab.png
new file mode 100644
index 000000000..605936bb6
Binary files /dev/null and b/images/emoji/1f3ab.png differ
diff --git a/images/emoji/1f3ac.png b/images/emoji/1f3ac.png
new file mode 100644
index 000000000..813908831
Binary files /dev/null and b/images/emoji/1f3ac.png differ
diff --git a/images/emoji/1f3ad.png b/images/emoji/1f3ad.png
new file mode 100644
index 000000000..685441fda
Binary files /dev/null and b/images/emoji/1f3ad.png differ
diff --git a/images/emoji/1f3ae.png b/images/emoji/1f3ae.png
new file mode 100644
index 000000000..316a9106a
Binary files /dev/null and b/images/emoji/1f3ae.png differ
diff --git a/images/emoji/1f3af.png b/images/emoji/1f3af.png
new file mode 100644
index 000000000..f6704aeb8
Binary files /dev/null and b/images/emoji/1f3af.png differ
diff --git a/images/emoji/1f3b0.png b/images/emoji/1f3b0.png
new file mode 100644
index 000000000..ee71b6c26
Binary files /dev/null and b/images/emoji/1f3b0.png differ
diff --git a/images/emoji/1f3b1.png b/images/emoji/1f3b1.png
new file mode 100644
index 000000000..38ca662ed
Binary files /dev/null and b/images/emoji/1f3b1.png differ
diff --git a/images/emoji/1f3b2.png b/images/emoji/1f3b2.png
new file mode 100644
index 000000000..ad3626fe5
Binary files /dev/null and b/images/emoji/1f3b2.png differ
diff --git a/images/emoji/1f3b3.png b/images/emoji/1f3b3.png
new file mode 100644
index 000000000..63add89e5
Binary files /dev/null and b/images/emoji/1f3b3.png differ
diff --git a/images/emoji/1f3b4.png b/images/emoji/1f3b4.png
new file mode 100644
index 000000000..6766b044d
Binary files /dev/null and b/images/emoji/1f3b4.png differ
diff --git a/images/emoji/1f3b5.png b/images/emoji/1f3b5.png
new file mode 100644
index 000000000..06691ef61
Binary files /dev/null and b/images/emoji/1f3b5.png differ
diff --git a/images/emoji/1f3b6.png b/images/emoji/1f3b6.png
new file mode 100644
index 000000000..57d499aa1
Binary files /dev/null and b/images/emoji/1f3b6.png differ
diff --git a/images/emoji/1f3b7.png b/images/emoji/1f3b7.png
new file mode 100644
index 000000000..a392faec2
Binary files /dev/null and b/images/emoji/1f3b7.png differ
diff --git a/images/emoji/1f3b8.png b/images/emoji/1f3b8.png
new file mode 100644
index 000000000..43d752f1e
Binary files /dev/null and b/images/emoji/1f3b8.png differ
diff --git a/images/emoji/1f3b9.png b/images/emoji/1f3b9.png
new file mode 100644
index 000000000..442b74568
Binary files /dev/null and b/images/emoji/1f3b9.png differ
diff --git a/images/emoji/1f3ba.png b/images/emoji/1f3ba.png
new file mode 100644
index 000000000..87674cf78
Binary files /dev/null and b/images/emoji/1f3ba.png differ
diff --git a/images/emoji/1f3bb.png b/images/emoji/1f3bb.png
new file mode 100644
index 000000000..e1e76cce2
Binary files /dev/null and b/images/emoji/1f3bb.png differ
diff --git a/images/emoji/1f3bc.png b/images/emoji/1f3bc.png
new file mode 100644
index 000000000..47dc05a8e
Binary files /dev/null and b/images/emoji/1f3bc.png differ
diff --git a/images/emoji/1f3bd.png b/images/emoji/1f3bd.png
new file mode 100644
index 000000000..6d83c06b8
Binary files /dev/null and b/images/emoji/1f3bd.png differ
diff --git a/images/emoji/1f3be.png b/images/emoji/1f3be.png
new file mode 100644
index 000000000..7e68ba8f3
Binary files /dev/null and b/images/emoji/1f3be.png differ
diff --git a/images/emoji/1f3bf.png b/images/emoji/1f3bf.png
new file mode 100644
index 000000000..4a2d2c123
Binary files /dev/null and b/images/emoji/1f3bf.png differ
diff --git a/images/emoji/1f3c0.png b/images/emoji/1f3c0.png
new file mode 100644
index 000000000..64c76b79c
Binary files /dev/null and b/images/emoji/1f3c0.png differ
diff --git a/images/emoji/1f3c1.png b/images/emoji/1f3c1.png
new file mode 100644
index 000000000..5a71eecb8
Binary files /dev/null and b/images/emoji/1f3c1.png differ
diff --git a/images/emoji/1f3c2.png b/images/emoji/1f3c2.png
new file mode 100644
index 000000000..6361c0f2c
Binary files /dev/null and b/images/emoji/1f3c2.png differ
diff --git a/images/emoji/1f3c3-1f3fb.png b/images/emoji/1f3c3-1f3fb.png
new file mode 100644
index 000000000..9355239a5
Binary files /dev/null and b/images/emoji/1f3c3-1f3fb.png differ
diff --git a/images/emoji/1f3c3-1f3fc.png b/images/emoji/1f3c3-1f3fc.png
new file mode 100644
index 000000000..6112fd5c3
Binary files /dev/null and b/images/emoji/1f3c3-1f3fc.png differ
diff --git a/images/emoji/1f3c3-1f3fd.png b/images/emoji/1f3c3-1f3fd.png
new file mode 100644
index 000000000..625ec708f
Binary files /dev/null and b/images/emoji/1f3c3-1f3fd.png differ
diff --git a/images/emoji/1f3c3-1f3fe.png b/images/emoji/1f3c3-1f3fe.png
new file mode 100644
index 000000000..242f1b563
Binary files /dev/null and b/images/emoji/1f3c3-1f3fe.png differ
diff --git a/images/emoji/1f3c3-1f3ff.png b/images/emoji/1f3c3-1f3ff.png
new file mode 100644
index 000000000..2976c6f01
Binary files /dev/null and b/images/emoji/1f3c3-1f3ff.png differ
diff --git a/images/emoji/1f3c3.png b/images/emoji/1f3c3.png
new file mode 100644
index 000000000..e91491597
Binary files /dev/null and b/images/emoji/1f3c3.png differ
diff --git a/images/emoji/1f3c4-1f3fb.png b/images/emoji/1f3c4-1f3fb.png
new file mode 100644
index 000000000..b5faaa524
Binary files /dev/null and b/images/emoji/1f3c4-1f3fb.png differ
diff --git a/images/emoji/1f3c4-1f3fc.png b/images/emoji/1f3c4-1f3fc.png
new file mode 100644
index 000000000..6d92e412f
Binary files /dev/null and b/images/emoji/1f3c4-1f3fc.png differ
diff --git a/images/emoji/1f3c4-1f3fd.png b/images/emoji/1f3c4-1f3fd.png
new file mode 100644
index 000000000..f05ef5949
Binary files /dev/null and b/images/emoji/1f3c4-1f3fd.png differ
diff --git a/images/emoji/1f3c4-1f3fe.png b/images/emoji/1f3c4-1f3fe.png
new file mode 100644
index 000000000..35e143d19
Binary files /dev/null and b/images/emoji/1f3c4-1f3fe.png differ
diff --git a/images/emoji/1f3c4-1f3ff.png b/images/emoji/1f3c4-1f3ff.png
new file mode 100644
index 000000000..38917658e
Binary files /dev/null and b/images/emoji/1f3c4-1f3ff.png differ
diff --git a/images/emoji/1f3c4.png b/images/emoji/1f3c4.png
new file mode 100644
index 000000000..3ab017adf
Binary files /dev/null and b/images/emoji/1f3c4.png differ
diff --git a/images/emoji/1f3c5.png b/images/emoji/1f3c5.png
new file mode 100644
index 000000000..09718d001
Binary files /dev/null and b/images/emoji/1f3c5.png differ
diff --git a/images/emoji/1f3c6.png b/images/emoji/1f3c6.png
new file mode 100644
index 000000000..ac2895c18
Binary files /dev/null and b/images/emoji/1f3c6.png differ
diff --git a/images/emoji/1f3c7-1f3fb.png b/images/emoji/1f3c7-1f3fb.png
new file mode 100644
index 000000000..e9bf4092e
Binary files /dev/null and b/images/emoji/1f3c7-1f3fb.png differ
diff --git a/images/emoji/1f3c7-1f3fc.png b/images/emoji/1f3c7-1f3fc.png
new file mode 100644
index 000000000..031bbc3d8
Binary files /dev/null and b/images/emoji/1f3c7-1f3fc.png differ
diff --git a/images/emoji/1f3c7-1f3fd.png b/images/emoji/1f3c7-1f3fd.png
new file mode 100644
index 000000000..b40ef891f
Binary files /dev/null and b/images/emoji/1f3c7-1f3fd.png differ
diff --git a/images/emoji/1f3c7-1f3fe.png b/images/emoji/1f3c7-1f3fe.png
new file mode 100644
index 000000000..e286cb850
Binary files /dev/null and b/images/emoji/1f3c7-1f3fe.png differ
diff --git a/images/emoji/1f3c7-1f3ff.png b/images/emoji/1f3c7-1f3ff.png
new file mode 100644
index 000000000..453c51c60
Binary files /dev/null and b/images/emoji/1f3c7-1f3ff.png differ
diff --git a/images/emoji/1f3c7.png b/images/emoji/1f3c7.png
new file mode 100644
index 000000000..addf9edac
Binary files /dev/null and b/images/emoji/1f3c7.png differ
diff --git a/images/emoji/1f3c8.png b/images/emoji/1f3c8.png
new file mode 100644
index 000000000..909ddf95d
Binary files /dev/null and b/images/emoji/1f3c8.png differ
diff --git a/images/emoji/1f3c9.png b/images/emoji/1f3c9.png
new file mode 100644
index 000000000..659e134f7
Binary files /dev/null and b/images/emoji/1f3c9.png differ
diff --git a/images/emoji/1f3ca-1f3fb.png b/images/emoji/1f3ca-1f3fb.png
new file mode 100644
index 000000000..38441c9ca
Binary files /dev/null and b/images/emoji/1f3ca-1f3fb.png differ
diff --git a/images/emoji/1f3ca-1f3fc.png b/images/emoji/1f3ca-1f3fc.png
new file mode 100644
index 000000000..b0d431124
Binary files /dev/null and b/images/emoji/1f3ca-1f3fc.png differ
diff --git a/images/emoji/1f3ca-1f3fd.png b/images/emoji/1f3ca-1f3fd.png
new file mode 100644
index 000000000..211e77e2a
Binary files /dev/null and b/images/emoji/1f3ca-1f3fd.png differ
diff --git a/images/emoji/1f3ca-1f3fe.png b/images/emoji/1f3ca-1f3fe.png
new file mode 100644
index 000000000..f34c34db9
Binary files /dev/null and b/images/emoji/1f3ca-1f3fe.png differ
diff --git a/images/emoji/1f3ca-1f3ff.png b/images/emoji/1f3ca-1f3ff.png
new file mode 100644
index 000000000..3e9231ff8
Binary files /dev/null and b/images/emoji/1f3ca-1f3ff.png differ
diff --git a/images/emoji/1f3ca.png b/images/emoji/1f3ca.png
new file mode 100644
index 000000000..55b4d72f9
Binary files /dev/null and b/images/emoji/1f3ca.png differ
diff --git a/images/emoji/1f3cb-1f3fb.png b/images/emoji/1f3cb-1f3fb.png
new file mode 100644
index 000000000..febaad123
Binary files /dev/null and b/images/emoji/1f3cb-1f3fb.png differ
diff --git a/images/emoji/1f3cb-1f3fc.png b/images/emoji/1f3cb-1f3fc.png
new file mode 100644
index 000000000..27ae794a1
Binary files /dev/null and b/images/emoji/1f3cb-1f3fc.png differ
diff --git a/images/emoji/1f3cb-1f3fd.png b/images/emoji/1f3cb-1f3fd.png
new file mode 100644
index 000000000..45c4c22c7
Binary files /dev/null and b/images/emoji/1f3cb-1f3fd.png differ
diff --git a/images/emoji/1f3cb-1f3fe.png b/images/emoji/1f3cb-1f3fe.png
new file mode 100644
index 000000000..67dd21d24
Binary files /dev/null and b/images/emoji/1f3cb-1f3fe.png differ
diff --git a/images/emoji/1f3cb-1f3ff.png b/images/emoji/1f3cb-1f3ff.png
new file mode 100644
index 000000000..fa0152038
Binary files /dev/null and b/images/emoji/1f3cb-1f3ff.png differ
diff --git a/images/emoji/1f3cb.png b/images/emoji/1f3cb.png
new file mode 100644
index 000000000..afdeaa476
Binary files /dev/null and b/images/emoji/1f3cb.png differ
diff --git a/images/emoji/1f3cc.png b/images/emoji/1f3cc.png
new file mode 100644
index 000000000..39c552de8
Binary files /dev/null and b/images/emoji/1f3cc.png differ
diff --git a/images/emoji/1f3cd.png b/images/emoji/1f3cd.png
new file mode 100644
index 000000000..3d1d567e8
Binary files /dev/null and b/images/emoji/1f3cd.png differ
diff --git a/images/emoji/1f3ce.png b/images/emoji/1f3ce.png
new file mode 100644
index 000000000..fe3f045f4
Binary files /dev/null and b/images/emoji/1f3ce.png differ
diff --git a/images/emoji/1f3cf.png b/images/emoji/1f3cf.png
new file mode 100644
index 000000000..d602294a2
Binary files /dev/null and b/images/emoji/1f3cf.png differ
diff --git a/images/emoji/1f3d0.png b/images/emoji/1f3d0.png
new file mode 100644
index 000000000..ce89e6d74
Binary files /dev/null and b/images/emoji/1f3d0.png differ
diff --git a/images/emoji/1f3d1.png b/images/emoji/1f3d1.png
new file mode 100644
index 000000000..839637716
Binary files /dev/null and b/images/emoji/1f3d1.png differ
diff --git a/images/emoji/1f3d2.png b/images/emoji/1f3d2.png
new file mode 100644
index 000000000..be94e9cbf
Binary files /dev/null and b/images/emoji/1f3d2.png differ
diff --git a/images/emoji/1f3d3.png b/images/emoji/1f3d3.png
new file mode 100644
index 000000000..ff3c51727
Binary files /dev/null and b/images/emoji/1f3d3.png differ
diff --git a/images/emoji/1f3d4.png b/images/emoji/1f3d4.png
new file mode 100644
index 000000000..f63a205dc
Binary files /dev/null and b/images/emoji/1f3d4.png differ
diff --git a/images/emoji/1f3d5.png b/images/emoji/1f3d5.png
new file mode 100644
index 000000000..7da5a756e
Binary files /dev/null and b/images/emoji/1f3d5.png differ
diff --git a/images/emoji/1f3d6.png b/images/emoji/1f3d6.png
new file mode 100644
index 000000000..69108c8ea
Binary files /dev/null and b/images/emoji/1f3d6.png differ
diff --git a/images/emoji/1f3d7.png b/images/emoji/1f3d7.png
new file mode 100644
index 000000000..8206a20f6
Binary files /dev/null and b/images/emoji/1f3d7.png differ
diff --git a/images/emoji/1f3d8.png b/images/emoji/1f3d8.png
new file mode 100644
index 000000000..6ab4a2a26
Binary files /dev/null and b/images/emoji/1f3d8.png differ
diff --git a/images/emoji/1f3d9.png b/images/emoji/1f3d9.png
new file mode 100644
index 000000000..d7b9844a0
Binary files /dev/null and b/images/emoji/1f3d9.png differ
diff --git a/images/emoji/1f3da.png b/images/emoji/1f3da.png
new file mode 100644
index 000000000..c55e81de9
Binary files /dev/null and b/images/emoji/1f3da.png differ
diff --git a/images/emoji/1f3db.png b/images/emoji/1f3db.png
new file mode 100644
index 000000000..de7b559da
Binary files /dev/null and b/images/emoji/1f3db.png differ
diff --git a/images/emoji/1f3dc.png b/images/emoji/1f3dc.png
new file mode 100644
index 000000000..e9966ff8c
Binary files /dev/null and b/images/emoji/1f3dc.png differ
diff --git a/images/emoji/1f3dd.png b/images/emoji/1f3dd.png
new file mode 100644
index 000000000..7fd834389
Binary files /dev/null and b/images/emoji/1f3dd.png differ
diff --git a/images/emoji/1f3de.png b/images/emoji/1f3de.png
new file mode 100644
index 000000000..63ec70163
Binary files /dev/null and b/images/emoji/1f3de.png differ
diff --git a/images/emoji/1f3df.png b/images/emoji/1f3df.png
new file mode 100644
index 000000000..1fee9a34b
Binary files /dev/null and b/images/emoji/1f3df.png differ
diff --git a/images/emoji/1f3e0.png b/images/emoji/1f3e0.png
new file mode 100644
index 000000000..01c98a0ba
Binary files /dev/null and b/images/emoji/1f3e0.png differ
diff --git a/images/emoji/1f3e1.png b/images/emoji/1f3e1.png
new file mode 100644
index 000000000..1a276d153
Binary files /dev/null and b/images/emoji/1f3e1.png differ
diff --git a/images/emoji/1f3e2.png b/images/emoji/1f3e2.png
new file mode 100644
index 000000000..7eee927d1
Binary files /dev/null and b/images/emoji/1f3e2.png differ
diff --git a/images/emoji/1f3e3.png b/images/emoji/1f3e3.png
new file mode 100644
index 000000000..a23848f9a
Binary files /dev/null and b/images/emoji/1f3e3.png differ
diff --git a/images/emoji/1f3e4.png b/images/emoji/1f3e4.png
new file mode 100644
index 000000000..3745aff8d
Binary files /dev/null and b/images/emoji/1f3e4.png differ
diff --git a/images/emoji/1f3e5.png b/images/emoji/1f3e5.png
new file mode 100644
index 000000000..1cbce4ae7
Binary files /dev/null and b/images/emoji/1f3e5.png differ
diff --git a/images/emoji/1f3e6.png b/images/emoji/1f3e6.png
new file mode 100644
index 000000000..dffdcef36
Binary files /dev/null and b/images/emoji/1f3e6.png differ
diff --git a/images/emoji/1f3e7.png b/images/emoji/1f3e7.png
new file mode 100644
index 000000000..4d935307b
Binary files /dev/null and b/images/emoji/1f3e7.png differ
diff --git a/images/emoji/1f3e8.png b/images/emoji/1f3e8.png
new file mode 100644
index 000000000..ea8f4c497
Binary files /dev/null and b/images/emoji/1f3e8.png differ
diff --git a/images/emoji/1f3e9.png b/images/emoji/1f3e9.png
new file mode 100644
index 000000000..5e136be6f
Binary files /dev/null and b/images/emoji/1f3e9.png differ
diff --git a/images/emoji/1f3ea.png b/images/emoji/1f3ea.png
new file mode 100644
index 000000000..26b53b566
Binary files /dev/null and b/images/emoji/1f3ea.png differ
diff --git a/images/emoji/1f3eb.png b/images/emoji/1f3eb.png
new file mode 100644
index 000000000..269759534
Binary files /dev/null and b/images/emoji/1f3eb.png differ
diff --git a/images/emoji/1f3ec.png b/images/emoji/1f3ec.png
new file mode 100644
index 000000000..58867c7a6
Binary files /dev/null and b/images/emoji/1f3ec.png differ
diff --git a/images/emoji/1f3ed.png b/images/emoji/1f3ed.png
new file mode 100644
index 000000000..e1d2ddf4a
Binary files /dev/null and b/images/emoji/1f3ed.png differ
diff --git a/images/emoji/1f3ee.png b/images/emoji/1f3ee.png
new file mode 100644
index 000000000..97cf5dbe1
Binary files /dev/null and b/images/emoji/1f3ee.png differ
diff --git a/images/emoji/1f3ef.png b/images/emoji/1f3ef.png
new file mode 100644
index 000000000..64b4e33a1
Binary files /dev/null and b/images/emoji/1f3ef.png differ
diff --git a/images/emoji/1f3f0.png b/images/emoji/1f3f0.png
new file mode 100644
index 000000000..888d11332
Binary files /dev/null and b/images/emoji/1f3f0.png differ
diff --git a/images/emoji/1f3f3.png b/images/emoji/1f3f3.png
new file mode 100644
index 000000000..86d6e96d5
Binary files /dev/null and b/images/emoji/1f3f3.png differ
diff --git a/images/emoji/1f3f4.png b/images/emoji/1f3f4.png
new file mode 100644
index 000000000..0e28d05d5
Binary files /dev/null and b/images/emoji/1f3f4.png differ
diff --git a/images/emoji/1f3f5.png b/images/emoji/1f3f5.png
new file mode 100644
index 000000000..8030e494b
Binary files /dev/null and b/images/emoji/1f3f5.png differ
diff --git a/images/emoji/1f3f7.png b/images/emoji/1f3f7.png
new file mode 100644
index 000000000..d41c9b4f1
Binary files /dev/null and b/images/emoji/1f3f7.png differ
diff --git a/images/emoji/1f3f8.png b/images/emoji/1f3f8.png
new file mode 100644
index 000000000..e0af4d99b
Binary files /dev/null and b/images/emoji/1f3f8.png differ
diff --git a/images/emoji/1f3f9.png b/images/emoji/1f3f9.png
new file mode 100644
index 000000000..6a538bf47
Binary files /dev/null and b/images/emoji/1f3f9.png differ
diff --git a/images/emoji/1f3fa.png b/images/emoji/1f3fa.png
new file mode 100644
index 000000000..96de50560
Binary files /dev/null and b/images/emoji/1f3fa.png differ
diff --git a/images/emoji/1f400.png b/images/emoji/1f400.png
new file mode 100644
index 000000000..86219144f
Binary files /dev/null and b/images/emoji/1f400.png differ
diff --git a/images/emoji/1f401.png b/images/emoji/1f401.png
new file mode 100644
index 000000000..20fb041f0
Binary files /dev/null and b/images/emoji/1f401.png differ
diff --git a/images/emoji/1f402.png b/images/emoji/1f402.png
new file mode 100644
index 000000000..badf5708f
Binary files /dev/null and b/images/emoji/1f402.png differ
diff --git a/images/emoji/1f403.png b/images/emoji/1f403.png
new file mode 100644
index 000000000..80446615c
Binary files /dev/null and b/images/emoji/1f403.png differ
diff --git a/images/emoji/1f404.png b/images/emoji/1f404.png
new file mode 100644
index 000000000..4d0ca534f
Binary files /dev/null and b/images/emoji/1f404.png differ
diff --git a/images/emoji/1f405.png b/images/emoji/1f405.png
new file mode 100644
index 000000000..871a8b74d
Binary files /dev/null and b/images/emoji/1f405.png differ
diff --git a/images/emoji/1f406.png b/images/emoji/1f406.png
new file mode 100644
index 000000000..8aac3d494
Binary files /dev/null and b/images/emoji/1f406.png differ
diff --git a/images/emoji/1f407.png b/images/emoji/1f407.png
new file mode 100644
index 000000000..2c8a29c64
Binary files /dev/null and b/images/emoji/1f407.png differ
diff --git a/images/emoji/1f408.png b/images/emoji/1f408.png
new file mode 100644
index 000000000..46abe8cbc
Binary files /dev/null and b/images/emoji/1f408.png differ
diff --git a/images/emoji/1f409.png b/images/emoji/1f409.png
new file mode 100644
index 000000000..e298d2f6c
Binary files /dev/null and b/images/emoji/1f409.png differ
diff --git a/images/emoji/1f40a.png b/images/emoji/1f40a.png
new file mode 100644
index 000000000..3005c46f1
Binary files /dev/null and b/images/emoji/1f40a.png differ
diff --git a/images/emoji/1f40b.png b/images/emoji/1f40b.png
new file mode 100644
index 000000000..0df9d3c73
Binary files /dev/null and b/images/emoji/1f40b.png differ
diff --git a/images/emoji/1f40c.png b/images/emoji/1f40c.png
new file mode 100644
index 000000000..f4ea071e2
Binary files /dev/null and b/images/emoji/1f40c.png differ
diff --git a/images/emoji/1f40d.png b/images/emoji/1f40d.png
new file mode 100644
index 000000000..f041d3b2e
Binary files /dev/null and b/images/emoji/1f40d.png differ
diff --git a/images/emoji/1f40e.png b/images/emoji/1f40e.png
new file mode 100644
index 000000000..0b4d8903c
Binary files /dev/null and b/images/emoji/1f40e.png differ
diff --git a/images/emoji/1f40f.png b/images/emoji/1f40f.png
new file mode 100644
index 000000000..52a44464c
Binary files /dev/null and b/images/emoji/1f40f.png differ
diff --git a/images/emoji/1f410.png b/images/emoji/1f410.png
new file mode 100644
index 000000000..f9d9e38a1
Binary files /dev/null and b/images/emoji/1f410.png differ
diff --git a/images/emoji/1f411.png b/images/emoji/1f411.png
new file mode 100644
index 000000000..eea1f2f8d
Binary files /dev/null and b/images/emoji/1f411.png differ
diff --git a/images/emoji/1f412.png b/images/emoji/1f412.png
new file mode 100644
index 000000000..65042c09f
Binary files /dev/null and b/images/emoji/1f412.png differ
diff --git a/images/emoji/1f413.png b/images/emoji/1f413.png
new file mode 100644
index 000000000..bbf2bbff9
Binary files /dev/null and b/images/emoji/1f413.png differ
diff --git a/images/emoji/1f414.png b/images/emoji/1f414.png
new file mode 100644
index 000000000..9a6992e55
Binary files /dev/null and b/images/emoji/1f414.png differ
diff --git a/images/emoji/1f415.png b/images/emoji/1f415.png
new file mode 100644
index 000000000..976143dbd
Binary files /dev/null and b/images/emoji/1f415.png differ
diff --git a/images/emoji/1f416.png b/images/emoji/1f416.png
new file mode 100644
index 000000000..5f31c1a2d
Binary files /dev/null and b/images/emoji/1f416.png differ
diff --git a/images/emoji/1f417.png b/images/emoji/1f417.png
new file mode 100644
index 000000000..3073bf026
Binary files /dev/null and b/images/emoji/1f417.png differ
diff --git a/images/emoji/1f418.png b/images/emoji/1f418.png
new file mode 100644
index 000000000..b8a6d1405
Binary files /dev/null and b/images/emoji/1f418.png differ
diff --git a/images/emoji/1f419.png b/images/emoji/1f419.png
new file mode 100644
index 000000000..72c84074a
Binary files /dev/null and b/images/emoji/1f419.png differ
diff --git a/images/emoji/1f41a.png b/images/emoji/1f41a.png
new file mode 100644
index 000000000..55721629f
Binary files /dev/null and b/images/emoji/1f41a.png differ
diff --git a/images/emoji/1f41b.png b/images/emoji/1f41b.png
new file mode 100644
index 000000000..c9a00cf3e
Binary files /dev/null and b/images/emoji/1f41b.png differ
diff --git a/images/emoji/1f41c.png b/images/emoji/1f41c.png
new file mode 100644
index 000000000..994127ed6
Binary files /dev/null and b/images/emoji/1f41c.png differ
diff --git a/images/emoji/1f41d.png b/images/emoji/1f41d.png
new file mode 100644
index 000000000..6bf6f67e1
Binary files /dev/null and b/images/emoji/1f41d.png differ
diff --git a/images/emoji/1f41e.png b/images/emoji/1f41e.png
new file mode 100644
index 000000000..3d93174d7
Binary files /dev/null and b/images/emoji/1f41e.png differ
diff --git a/images/emoji/1f41f.png b/images/emoji/1f41f.png
new file mode 100644
index 000000000..c2d2faaac
Binary files /dev/null and b/images/emoji/1f41f.png differ
diff --git a/images/emoji/1f420.png b/images/emoji/1f420.png
new file mode 100644
index 000000000..252105235
Binary files /dev/null and b/images/emoji/1f420.png differ
diff --git a/images/emoji/1f421.png b/images/emoji/1f421.png
new file mode 100644
index 000000000..2939344a5
Binary files /dev/null and b/images/emoji/1f421.png differ
diff --git a/images/emoji/1f422.png b/images/emoji/1f422.png
new file mode 100644
index 000000000..46f59337b
Binary files /dev/null and b/images/emoji/1f422.png differ
diff --git a/images/emoji/1f423.png b/images/emoji/1f423.png
new file mode 100644
index 000000000..56515ad34
Binary files /dev/null and b/images/emoji/1f423.png differ
diff --git a/images/emoji/1f424.png b/images/emoji/1f424.png
new file mode 100644
index 000000000..dccd96576
Binary files /dev/null and b/images/emoji/1f424.png differ
diff --git a/images/emoji/1f425.png b/images/emoji/1f425.png
new file mode 100644
index 000000000..31dfb511e
Binary files /dev/null and b/images/emoji/1f425.png differ
diff --git a/images/emoji/1f426.png b/images/emoji/1f426.png
new file mode 100644
index 000000000..e201c22be
Binary files /dev/null and b/images/emoji/1f426.png differ
diff --git a/images/emoji/1f427.png b/images/emoji/1f427.png
new file mode 100644
index 000000000..c0064fb97
Binary files /dev/null and b/images/emoji/1f427.png differ
diff --git a/images/emoji/1f428.png b/images/emoji/1f428.png
new file mode 100644
index 000000000..c846cd223
Binary files /dev/null and b/images/emoji/1f428.png differ
diff --git a/images/emoji/1f429.png b/images/emoji/1f429.png
new file mode 100644
index 000000000..8ec39e396
Binary files /dev/null and b/images/emoji/1f429.png differ
diff --git a/images/emoji/1f42a.png b/images/emoji/1f42a.png
new file mode 100644
index 000000000..5271637c7
Binary files /dev/null and b/images/emoji/1f42a.png differ
diff --git a/images/emoji/1f42b.png b/images/emoji/1f42b.png
new file mode 100644
index 000000000..b421d07a8
Binary files /dev/null and b/images/emoji/1f42b.png differ
diff --git a/images/emoji/1f42c.png b/images/emoji/1f42c.png
new file mode 100644
index 000000000..c2a914f59
Binary files /dev/null and b/images/emoji/1f42c.png differ
diff --git a/images/emoji/1f42d.png b/images/emoji/1f42d.png
new file mode 100644
index 000000000..a52c8414f
Binary files /dev/null and b/images/emoji/1f42d.png differ
diff --git a/images/emoji/1f42e.png b/images/emoji/1f42e.png
new file mode 100644
index 000000000..602495bd9
Binary files /dev/null and b/images/emoji/1f42e.png differ
diff --git a/images/emoji/1f42f.png b/images/emoji/1f42f.png
new file mode 100644
index 000000000..a4d3ef086
Binary files /dev/null and b/images/emoji/1f42f.png differ
diff --git a/images/emoji/1f430.png b/images/emoji/1f430.png
new file mode 100644
index 000000000..20c67d11b
Binary files /dev/null and b/images/emoji/1f430.png differ
diff --git a/images/emoji/1f431.png b/images/emoji/1f431.png
new file mode 100644
index 000000000..10e20b530
Binary files /dev/null and b/images/emoji/1f431.png differ
diff --git a/images/emoji/1f432.png b/images/emoji/1f432.png
new file mode 100644
index 000000000..3c2720446
Binary files /dev/null and b/images/emoji/1f432.png differ
diff --git a/images/emoji/1f433.png b/images/emoji/1f433.png
new file mode 100644
index 000000000..c2f52b443
Binary files /dev/null and b/images/emoji/1f433.png differ
diff --git a/images/emoji/1f434.png b/images/emoji/1f434.png
new file mode 100644
index 000000000..f4f45047c
Binary files /dev/null and b/images/emoji/1f434.png differ
diff --git a/images/emoji/1f435.png b/images/emoji/1f435.png
new file mode 100644
index 000000000..fe49a5467
Binary files /dev/null and b/images/emoji/1f435.png differ
diff --git a/images/emoji/1f436.png b/images/emoji/1f436.png
new file mode 100644
index 000000000..4a5b7b859
Binary files /dev/null and b/images/emoji/1f436.png differ
diff --git a/images/emoji/1f437.png b/images/emoji/1f437.png
new file mode 100644
index 000000000..afe05ca16
Binary files /dev/null and b/images/emoji/1f437.png differ
diff --git a/images/emoji/1f438.png b/images/emoji/1f438.png
new file mode 100644
index 000000000..8825d1ad5
Binary files /dev/null and b/images/emoji/1f438.png differ
diff --git a/images/emoji/1f439.png b/images/emoji/1f439.png
new file mode 100644
index 000000000..376c36b0a
Binary files /dev/null and b/images/emoji/1f439.png differ
diff --git a/images/emoji/1f43a.png b/images/emoji/1f43a.png
new file mode 100644
index 000000000..ba7220f2d
Binary files /dev/null and b/images/emoji/1f43a.png differ
diff --git a/images/emoji/1f43b.png b/images/emoji/1f43b.png
new file mode 100644
index 000000000..272d56bbb
Binary files /dev/null and b/images/emoji/1f43b.png differ
diff --git a/images/emoji/1f43c.png b/images/emoji/1f43c.png
new file mode 100644
index 000000000..978382775
Binary files /dev/null and b/images/emoji/1f43c.png differ
diff --git a/images/emoji/1f43d.png b/images/emoji/1f43d.png
new file mode 100644
index 000000000..3610ae4a9
Binary files /dev/null and b/images/emoji/1f43d.png differ
diff --git a/images/emoji/1f43e.png b/images/emoji/1f43e.png
new file mode 100644
index 000000000..5fe568cee
Binary files /dev/null and b/images/emoji/1f43e.png differ
diff --git a/images/emoji/1f43f.png b/images/emoji/1f43f.png
new file mode 100644
index 000000000..a9ab60f51
Binary files /dev/null and b/images/emoji/1f43f.png differ
diff --git a/images/emoji/1f440.png b/images/emoji/1f440.png
new file mode 100644
index 000000000..2102ada7e
Binary files /dev/null and b/images/emoji/1f440.png differ
diff --git a/images/emoji/1f441-1f5e8.png b/images/emoji/1f441-1f5e8.png
new file mode 100644
index 000000000..21bd22bbc
Binary files /dev/null and b/images/emoji/1f441-1f5e8.png differ
diff --git a/images/emoji/1f441.png b/images/emoji/1f441.png
new file mode 100644
index 000000000..9d989cdd3
Binary files /dev/null and b/images/emoji/1f441.png differ
diff --git a/images/emoji/1f442-1f3fb.png b/images/emoji/1f442-1f3fb.png
new file mode 100644
index 000000000..d09e1e419
Binary files /dev/null and b/images/emoji/1f442-1f3fb.png differ
diff --git a/images/emoji/1f442-1f3fc.png b/images/emoji/1f442-1f3fc.png
new file mode 100644
index 000000000..300d60a99
Binary files /dev/null and b/images/emoji/1f442-1f3fc.png differ
diff --git a/images/emoji/1f442-1f3fd.png b/images/emoji/1f442-1f3fd.png
new file mode 100644
index 000000000..2a56eebe4
Binary files /dev/null and b/images/emoji/1f442-1f3fd.png differ
diff --git a/images/emoji/1f442-1f3fe.png b/images/emoji/1f442-1f3fe.png
new file mode 100644
index 000000000..bd270f776
Binary files /dev/null and b/images/emoji/1f442-1f3fe.png differ
diff --git a/images/emoji/1f442-1f3ff.png b/images/emoji/1f442-1f3ff.png
new file mode 100644
index 000000000..b96bb441d
Binary files /dev/null and b/images/emoji/1f442-1f3ff.png differ
diff --git a/images/emoji/1f442.png b/images/emoji/1f442.png
new file mode 100644
index 000000000..f84f9ff15
Binary files /dev/null and b/images/emoji/1f442.png differ
diff --git a/images/emoji/1f443-1f3fb.png b/images/emoji/1f443-1f3fb.png
new file mode 100644
index 000000000..8008d1750
Binary files /dev/null and b/images/emoji/1f443-1f3fb.png differ
diff --git a/images/emoji/1f443-1f3fc.png b/images/emoji/1f443-1f3fc.png
new file mode 100644
index 000000000..ac17f26e8
Binary files /dev/null and b/images/emoji/1f443-1f3fc.png differ
diff --git a/images/emoji/1f443-1f3fd.png b/images/emoji/1f443-1f3fd.png
new file mode 100644
index 000000000..d8b6cbe0f
Binary files /dev/null and b/images/emoji/1f443-1f3fd.png differ
diff --git a/images/emoji/1f443-1f3fe.png b/images/emoji/1f443-1f3fe.png
new file mode 100644
index 000000000..004b2631e
Binary files /dev/null and b/images/emoji/1f443-1f3fe.png differ
diff --git a/images/emoji/1f443-1f3ff.png b/images/emoji/1f443-1f3ff.png
new file mode 100644
index 000000000..7b33821f6
Binary files /dev/null and b/images/emoji/1f443-1f3ff.png differ
diff --git a/images/emoji/1f443.png b/images/emoji/1f443.png
new file mode 100644
index 000000000..2f04ac5f9
Binary files /dev/null and b/images/emoji/1f443.png differ
diff --git a/images/emoji/1f444.png b/images/emoji/1f444.png
new file mode 100644
index 000000000..35f3cc200
Binary files /dev/null and b/images/emoji/1f444.png differ
diff --git a/images/emoji/1f445.png b/images/emoji/1f445.png
new file mode 100644
index 000000000..70ce9c122
Binary files /dev/null and b/images/emoji/1f445.png differ
diff --git a/images/emoji/1f446-1f3fb.png b/images/emoji/1f446-1f3fb.png
new file mode 100644
index 000000000..a12a7e784
Binary files /dev/null and b/images/emoji/1f446-1f3fb.png differ
diff --git a/images/emoji/1f446-1f3fc.png b/images/emoji/1f446-1f3fc.png
new file mode 100644
index 000000000..cdff40cea
Binary files /dev/null and b/images/emoji/1f446-1f3fc.png differ
diff --git a/images/emoji/1f446-1f3fd.png b/images/emoji/1f446-1f3fd.png
new file mode 100644
index 000000000..a07ce9e5a
Binary files /dev/null and b/images/emoji/1f446-1f3fd.png differ
diff --git a/images/emoji/1f446-1f3fe.png b/images/emoji/1f446-1f3fe.png
new file mode 100644
index 000000000..4f86c88ba
Binary files /dev/null and b/images/emoji/1f446-1f3fe.png differ
diff --git a/images/emoji/1f446-1f3ff.png b/images/emoji/1f446-1f3ff.png
new file mode 100644
index 000000000..ed1b26c35
Binary files /dev/null and b/images/emoji/1f446-1f3ff.png differ
diff --git a/images/emoji/1f446.png b/images/emoji/1f446.png
new file mode 100644
index 000000000..bc496dfea
Binary files /dev/null and b/images/emoji/1f446.png differ
diff --git a/images/emoji/1f447-1f3fb.png b/images/emoji/1f447-1f3fb.png
new file mode 100644
index 000000000..140f157d8
Binary files /dev/null and b/images/emoji/1f447-1f3fb.png differ
diff --git a/images/emoji/1f447-1f3fc.png b/images/emoji/1f447-1f3fc.png
new file mode 100644
index 000000000..d518544f7
Binary files /dev/null and b/images/emoji/1f447-1f3fc.png differ
diff --git a/images/emoji/1f447-1f3fd.png b/images/emoji/1f447-1f3fd.png
new file mode 100644
index 000000000..018b688b8
Binary files /dev/null and b/images/emoji/1f447-1f3fd.png differ
diff --git a/images/emoji/1f447-1f3fe.png b/images/emoji/1f447-1f3fe.png
new file mode 100644
index 000000000..98845bf6f
Binary files /dev/null and b/images/emoji/1f447-1f3fe.png differ
diff --git a/images/emoji/1f447-1f3ff.png b/images/emoji/1f447-1f3ff.png
new file mode 100644
index 000000000..9a9b039a9
Binary files /dev/null and b/images/emoji/1f447-1f3ff.png differ
diff --git a/images/emoji/1f447.png b/images/emoji/1f447.png
new file mode 100644
index 000000000..00d3d13ab
Binary files /dev/null and b/images/emoji/1f447.png differ
diff --git a/images/emoji/1f448-1f3fb.png b/images/emoji/1f448-1f3fb.png
new file mode 100644
index 000000000..88e2c3060
Binary files /dev/null and b/images/emoji/1f448-1f3fb.png differ
diff --git a/images/emoji/1f448-1f3fc.png b/images/emoji/1f448-1f3fc.png
new file mode 100644
index 000000000..d3c89d87c
Binary files /dev/null and b/images/emoji/1f448-1f3fc.png differ
diff --git a/images/emoji/1f448-1f3fd.png b/images/emoji/1f448-1f3fd.png
new file mode 100644
index 000000000..b23b91673
Binary files /dev/null and b/images/emoji/1f448-1f3fd.png differ
diff --git a/images/emoji/1f448-1f3fe.png b/images/emoji/1f448-1f3fe.png
new file mode 100644
index 000000000..3093f325c
Binary files /dev/null and b/images/emoji/1f448-1f3fe.png differ
diff --git a/images/emoji/1f448-1f3ff.png b/images/emoji/1f448-1f3ff.png
new file mode 100644
index 000000000..2b4cbfa12
Binary files /dev/null and b/images/emoji/1f448-1f3ff.png differ
diff --git a/images/emoji/1f448.png b/images/emoji/1f448.png
new file mode 100644
index 000000000..599fa2e3c
Binary files /dev/null and b/images/emoji/1f448.png differ
diff --git a/images/emoji/1f449-1f3fb.png b/images/emoji/1f449-1f3fb.png
new file mode 100644
index 000000000..4a28c6bbc
Binary files /dev/null and b/images/emoji/1f449-1f3fb.png differ
diff --git a/images/emoji/1f449-1f3fc.png b/images/emoji/1f449-1f3fc.png
new file mode 100644
index 000000000..7cb132317
Binary files /dev/null and b/images/emoji/1f449-1f3fc.png differ
diff --git a/images/emoji/1f449-1f3fd.png b/images/emoji/1f449-1f3fd.png
new file mode 100644
index 000000000..5514807d7
Binary files /dev/null and b/images/emoji/1f449-1f3fd.png differ
diff --git a/images/emoji/1f449-1f3fe.png b/images/emoji/1f449-1f3fe.png
new file mode 100644
index 000000000..b8541d644
Binary files /dev/null and b/images/emoji/1f449-1f3fe.png differ
diff --git a/images/emoji/1f449-1f3ff.png b/images/emoji/1f449-1f3ff.png
new file mode 100644
index 000000000..1b7aab07b
Binary files /dev/null and b/images/emoji/1f449-1f3ff.png differ
diff --git a/images/emoji/1f449.png b/images/emoji/1f449.png
new file mode 100644
index 000000000..93a3cd34a
Binary files /dev/null and b/images/emoji/1f449.png differ
diff --git a/images/emoji/1f44a-1f3fb.png b/images/emoji/1f44a-1f3fb.png
new file mode 100644
index 000000000..93c7d17fb
Binary files /dev/null and b/images/emoji/1f44a-1f3fb.png differ
diff --git a/images/emoji/1f44a-1f3fc.png b/images/emoji/1f44a-1f3fc.png
new file mode 100644
index 000000000..c0a1af6e1
Binary files /dev/null and b/images/emoji/1f44a-1f3fc.png differ
diff --git a/images/emoji/1f44a-1f3fd.png b/images/emoji/1f44a-1f3fd.png
new file mode 100644
index 000000000..1458b0212
Binary files /dev/null and b/images/emoji/1f44a-1f3fd.png differ
diff --git a/images/emoji/1f44a-1f3fe.png b/images/emoji/1f44a-1f3fe.png
new file mode 100644
index 000000000..c1466bfcd
Binary files /dev/null and b/images/emoji/1f44a-1f3fe.png differ
diff --git a/images/emoji/1f44a-1f3ff.png b/images/emoji/1f44a-1f3ff.png
new file mode 100644
index 000000000..00b4ddb89
Binary files /dev/null and b/images/emoji/1f44a-1f3ff.png differ
diff --git a/images/emoji/1f44a.png b/images/emoji/1f44a.png
new file mode 100644
index 000000000..b14ca5f52
Binary files /dev/null and b/images/emoji/1f44a.png differ
diff --git a/images/emoji/1f44b-1f3fb.png b/images/emoji/1f44b-1f3fb.png
new file mode 100644
index 000000000..beea09dda
Binary files /dev/null and b/images/emoji/1f44b-1f3fb.png differ
diff --git a/images/emoji/1f44b-1f3fc.png b/images/emoji/1f44b-1f3fc.png
new file mode 100644
index 000000000..a7679d5fe
Binary files /dev/null and b/images/emoji/1f44b-1f3fc.png differ
diff --git a/images/emoji/1f44b-1f3fd.png b/images/emoji/1f44b-1f3fd.png
new file mode 100644
index 000000000..6283b670f
Binary files /dev/null and b/images/emoji/1f44b-1f3fd.png differ
diff --git a/images/emoji/1f44b-1f3fe.png b/images/emoji/1f44b-1f3fe.png
new file mode 100644
index 000000000..b771b52c3
Binary files /dev/null and b/images/emoji/1f44b-1f3fe.png differ
diff --git a/images/emoji/1f44b-1f3ff.png b/images/emoji/1f44b-1f3ff.png
new file mode 100644
index 000000000..6bbedc9b5
Binary files /dev/null and b/images/emoji/1f44b-1f3ff.png differ
diff --git a/images/emoji/1f44b.png b/images/emoji/1f44b.png
new file mode 100644
index 000000000..02ae68b85
Binary files /dev/null and b/images/emoji/1f44b.png differ
diff --git a/images/emoji/1f44c-1f3fb.png b/images/emoji/1f44c-1f3fb.png
new file mode 100644
index 000000000..cecf7b2ab
Binary files /dev/null and b/images/emoji/1f44c-1f3fb.png differ
diff --git a/images/emoji/1f44c-1f3fc.png b/images/emoji/1f44c-1f3fc.png
new file mode 100644
index 000000000..c19239bcd
Binary files /dev/null and b/images/emoji/1f44c-1f3fc.png differ
diff --git a/images/emoji/1f44c-1f3fd.png b/images/emoji/1f44c-1f3fd.png
new file mode 100644
index 000000000..94b65b03e
Binary files /dev/null and b/images/emoji/1f44c-1f3fd.png differ
diff --git a/images/emoji/1f44c-1f3fe.png b/images/emoji/1f44c-1f3fe.png
new file mode 100644
index 000000000..03d26f08e
Binary files /dev/null and b/images/emoji/1f44c-1f3fe.png differ
diff --git a/images/emoji/1f44c-1f3ff.png b/images/emoji/1f44c-1f3ff.png
new file mode 100644
index 000000000..d4b240863
Binary files /dev/null and b/images/emoji/1f44c-1f3ff.png differ
diff --git a/images/emoji/1f44c.png b/images/emoji/1f44c.png
new file mode 100644
index 000000000..028d69b0d
Binary files /dev/null and b/images/emoji/1f44c.png differ
diff --git a/images/emoji/1f44d-1f3fb.png b/images/emoji/1f44d-1f3fb.png
new file mode 100644
index 000000000..39684cd5c
Binary files /dev/null and b/images/emoji/1f44d-1f3fb.png differ
diff --git a/images/emoji/1f44d-1f3fc.png b/images/emoji/1f44d-1f3fc.png
new file mode 100644
index 000000000..a9b597235
Binary files /dev/null and b/images/emoji/1f44d-1f3fc.png differ
diff --git a/images/emoji/1f44d-1f3fd.png b/images/emoji/1f44d-1f3fd.png
new file mode 100644
index 000000000..c5e291670
Binary files /dev/null and b/images/emoji/1f44d-1f3fd.png differ
diff --git a/images/emoji/1f44d-1f3fe.png b/images/emoji/1f44d-1f3fe.png
new file mode 100644
index 000000000..5bf4857a8
Binary files /dev/null and b/images/emoji/1f44d-1f3fe.png differ
diff --git a/images/emoji/1f44d-1f3ff.png b/images/emoji/1f44d-1f3ff.png
new file mode 100644
index 000000000..d829f787c
Binary files /dev/null and b/images/emoji/1f44d-1f3ff.png differ
diff --git a/images/emoji/1f44d.png b/images/emoji/1f44d.png
new file mode 100644
index 000000000..f9e6f13a3
Binary files /dev/null and b/images/emoji/1f44d.png differ
diff --git a/images/emoji/1f44e-1f3fb.png b/images/emoji/1f44e-1f3fb.png
new file mode 100644
index 000000000..a1631af8e
Binary files /dev/null and b/images/emoji/1f44e-1f3fb.png differ
diff --git a/images/emoji/1f44e-1f3fc.png b/images/emoji/1f44e-1f3fc.png
new file mode 100644
index 000000000..85fff82d5
Binary files /dev/null and b/images/emoji/1f44e-1f3fc.png differ
diff --git a/images/emoji/1f44e-1f3fd.png b/images/emoji/1f44e-1f3fd.png
new file mode 100644
index 000000000..eeba3be80
Binary files /dev/null and b/images/emoji/1f44e-1f3fd.png differ
diff --git a/images/emoji/1f44e-1f3fe.png b/images/emoji/1f44e-1f3fe.png
new file mode 100644
index 000000000..1addafdae
Binary files /dev/null and b/images/emoji/1f44e-1f3fe.png differ
diff --git a/images/emoji/1f44e-1f3ff.png b/images/emoji/1f44e-1f3ff.png
new file mode 100644
index 000000000..37ec07b57
Binary files /dev/null and b/images/emoji/1f44e-1f3ff.png differ
diff --git a/images/emoji/1f44e.png b/images/emoji/1f44e.png
new file mode 100644
index 000000000..b63da2f20
Binary files /dev/null and b/images/emoji/1f44e.png differ
diff --git a/images/emoji/1f44f-1f3fb.png b/images/emoji/1f44f-1f3fb.png
new file mode 100644
index 000000000..770aa9ca0
Binary files /dev/null and b/images/emoji/1f44f-1f3fb.png differ
diff --git a/images/emoji/1f44f-1f3fc.png b/images/emoji/1f44f-1f3fc.png
new file mode 100644
index 000000000..37c6b559a
Binary files /dev/null and b/images/emoji/1f44f-1f3fc.png differ
diff --git a/images/emoji/1f44f-1f3fd.png b/images/emoji/1f44f-1f3fd.png
new file mode 100644
index 000000000..e95bf2fc7
Binary files /dev/null and b/images/emoji/1f44f-1f3fd.png differ
diff --git a/images/emoji/1f44f-1f3fe.png b/images/emoji/1f44f-1f3fe.png
new file mode 100644
index 000000000..b6e9a9160
Binary files /dev/null and b/images/emoji/1f44f-1f3fe.png differ
diff --git a/images/emoji/1f44f-1f3ff.png b/images/emoji/1f44f-1f3ff.png
new file mode 100644
index 000000000..59cccdb73
Binary files /dev/null and b/images/emoji/1f44f-1f3ff.png differ
diff --git a/images/emoji/1f44f.png b/images/emoji/1f44f.png
new file mode 100644
index 000000000..b0ffe9289
Binary files /dev/null and b/images/emoji/1f44f.png differ
diff --git a/images/emoji/1f450-1f3fb.png b/images/emoji/1f450-1f3fb.png
new file mode 100644
index 000000000..352d2614f
Binary files /dev/null and b/images/emoji/1f450-1f3fb.png differ
diff --git a/images/emoji/1f450-1f3fc.png b/images/emoji/1f450-1f3fc.png
new file mode 100644
index 000000000..70824a50c
Binary files /dev/null and b/images/emoji/1f450-1f3fc.png differ
diff --git a/images/emoji/1f450-1f3fd.png b/images/emoji/1f450-1f3fd.png
new file mode 100644
index 000000000..d7d136bd3
Binary files /dev/null and b/images/emoji/1f450-1f3fd.png differ
diff --git a/images/emoji/1f450-1f3fe.png b/images/emoji/1f450-1f3fe.png
new file mode 100644
index 000000000..df4eaa711
Binary files /dev/null and b/images/emoji/1f450-1f3fe.png differ
diff --git a/images/emoji/1f450-1f3ff.png b/images/emoji/1f450-1f3ff.png
new file mode 100644
index 000000000..7dc04eaeb
Binary files /dev/null and b/images/emoji/1f450-1f3ff.png differ
diff --git a/images/emoji/1f450.png b/images/emoji/1f450.png
new file mode 100644
index 000000000..1cf75c910
Binary files /dev/null and b/images/emoji/1f450.png differ
diff --git a/images/emoji/1f451.png b/images/emoji/1f451.png
new file mode 100644
index 000000000..93b82d92f
Binary files /dev/null and b/images/emoji/1f451.png differ
diff --git a/images/emoji/1f452.png b/images/emoji/1f452.png
new file mode 100644
index 000000000..b837b6a2e
Binary files /dev/null and b/images/emoji/1f452.png differ
diff --git a/images/emoji/1f453.png b/images/emoji/1f453.png
new file mode 100644
index 000000000..865d8274a
Binary files /dev/null and b/images/emoji/1f453.png differ
diff --git a/images/emoji/1f454.png b/images/emoji/1f454.png
new file mode 100644
index 000000000..1804e7f3f
Binary files /dev/null and b/images/emoji/1f454.png differ
diff --git a/images/emoji/1f455.png b/images/emoji/1f455.png
new file mode 100644
index 000000000..af08dec8b
Binary files /dev/null and b/images/emoji/1f455.png differ
diff --git a/images/emoji/1f456.png b/images/emoji/1f456.png
new file mode 100644
index 000000000..2a6869d67
Binary files /dev/null and b/images/emoji/1f456.png differ
diff --git a/images/emoji/1f457.png b/images/emoji/1f457.png
new file mode 100644
index 000000000..a697ca5c5
Binary files /dev/null and b/images/emoji/1f457.png differ
diff --git a/images/emoji/1f458.png b/images/emoji/1f458.png
new file mode 100644
index 000000000..297a42c7e
Binary files /dev/null and b/images/emoji/1f458.png differ
diff --git a/images/emoji/1f459.png b/images/emoji/1f459.png
new file mode 100644
index 000000000..77a8a0aae
Binary files /dev/null and b/images/emoji/1f459.png differ
diff --git a/images/emoji/1f45a.png b/images/emoji/1f45a.png
new file mode 100644
index 000000000..01410dc81
Binary files /dev/null and b/images/emoji/1f45a.png differ
diff --git a/images/emoji/1f45b.png b/images/emoji/1f45b.png
new file mode 100644
index 000000000..981346193
Binary files /dev/null and b/images/emoji/1f45b.png differ
diff --git a/images/emoji/1f45c.png b/images/emoji/1f45c.png
new file mode 100644
index 000000000..cbf75c5d2
Binary files /dev/null and b/images/emoji/1f45c.png differ
diff --git a/images/emoji/1f45d.png b/images/emoji/1f45d.png
new file mode 100644
index 000000000..8795c6c66
Binary files /dev/null and b/images/emoji/1f45d.png differ
diff --git a/images/emoji/1f45e.png b/images/emoji/1f45e.png
new file mode 100644
index 000000000..16ccafb93
Binary files /dev/null and b/images/emoji/1f45e.png differ
diff --git a/images/emoji/1f45f.png b/images/emoji/1f45f.png
new file mode 100644
index 000000000..423fa07dd
Binary files /dev/null and b/images/emoji/1f45f.png differ
diff --git a/images/emoji/1f460.png b/images/emoji/1f460.png
new file mode 100644
index 000000000..b331cbccc
Binary files /dev/null and b/images/emoji/1f460.png differ
diff --git a/images/emoji/1f461.png b/images/emoji/1f461.png
new file mode 100644
index 000000000..9d9f5122b
Binary files /dev/null and b/images/emoji/1f461.png differ
diff --git a/images/emoji/1f462.png b/images/emoji/1f462.png
new file mode 100644
index 000000000..11f1065ed
Binary files /dev/null and b/images/emoji/1f462.png differ
diff --git a/images/emoji/1f463.png b/images/emoji/1f463.png
new file mode 100644
index 000000000..b2673c5a1
Binary files /dev/null and b/images/emoji/1f463.png differ
diff --git a/images/emoji/1f464.png b/images/emoji/1f464.png
new file mode 100644
index 000000000..123b2cbe1
Binary files /dev/null and b/images/emoji/1f464.png differ
diff --git a/images/emoji/1f465.png b/images/emoji/1f465.png
new file mode 100644
index 000000000..d7656860a
Binary files /dev/null and b/images/emoji/1f465.png differ
diff --git a/images/emoji/1f466-1f3fb.png b/images/emoji/1f466-1f3fb.png
new file mode 100644
index 000000000..2fc436ea5
Binary files /dev/null and b/images/emoji/1f466-1f3fb.png differ
diff --git a/images/emoji/1f466-1f3fc.png b/images/emoji/1f466-1f3fc.png
new file mode 100644
index 000000000..09a5f18d3
Binary files /dev/null and b/images/emoji/1f466-1f3fc.png differ
diff --git a/images/emoji/1f466-1f3fd.png b/images/emoji/1f466-1f3fd.png
new file mode 100644
index 000000000..3cfe675dd
Binary files /dev/null and b/images/emoji/1f466-1f3fd.png differ
diff --git a/images/emoji/1f466-1f3fe.png b/images/emoji/1f466-1f3fe.png
new file mode 100644
index 000000000..780be0ace
Binary files /dev/null and b/images/emoji/1f466-1f3fe.png differ
diff --git a/images/emoji/1f466-1f3ff.png b/images/emoji/1f466-1f3ff.png
new file mode 100644
index 000000000..f32fe22e3
Binary files /dev/null and b/images/emoji/1f466-1f3ff.png differ
diff --git a/images/emoji/1f466.png b/images/emoji/1f466.png
new file mode 100644
index 000000000..8ecfb0a4e
Binary files /dev/null and b/images/emoji/1f466.png differ
diff --git a/images/emoji/1f467-1f3fb.png b/images/emoji/1f467-1f3fb.png
new file mode 100644
index 000000000..2be1f0bee
Binary files /dev/null and b/images/emoji/1f467-1f3fb.png differ
diff --git a/images/emoji/1f467-1f3fc.png b/images/emoji/1f467-1f3fc.png
new file mode 100644
index 000000000..a59ed4a3f
Binary files /dev/null and b/images/emoji/1f467-1f3fc.png differ
diff --git a/images/emoji/1f467-1f3fd.png b/images/emoji/1f467-1f3fd.png
new file mode 100644
index 000000000..517e7f2a7
Binary files /dev/null and b/images/emoji/1f467-1f3fd.png differ
diff --git a/images/emoji/1f467-1f3fe.png b/images/emoji/1f467-1f3fe.png
new file mode 100644
index 000000000..542d96c84
Binary files /dev/null and b/images/emoji/1f467-1f3fe.png differ
diff --git a/images/emoji/1f467-1f3ff.png b/images/emoji/1f467-1f3ff.png
new file mode 100644
index 000000000..66b7c28c2
Binary files /dev/null and b/images/emoji/1f467-1f3ff.png differ
diff --git a/images/emoji/1f467.png b/images/emoji/1f467.png
new file mode 100644
index 000000000..649eea6a5
Binary files /dev/null and b/images/emoji/1f467.png differ
diff --git a/images/emoji/1f468-1f3fb.png b/images/emoji/1f468-1f3fb.png
new file mode 100644
index 000000000..bb86e963a
Binary files /dev/null and b/images/emoji/1f468-1f3fb.png differ
diff --git a/images/emoji/1f468-1f3fc.png b/images/emoji/1f468-1f3fc.png
new file mode 100644
index 000000000..fdeeaff46
Binary files /dev/null and b/images/emoji/1f468-1f3fc.png differ
diff --git a/images/emoji/1f468-1f3fd.png b/images/emoji/1f468-1f3fd.png
new file mode 100644
index 000000000..7ae0b5df9
Binary files /dev/null and b/images/emoji/1f468-1f3fd.png differ
diff --git a/images/emoji/1f468-1f3fe.png b/images/emoji/1f468-1f3fe.png
new file mode 100644
index 000000000..db14cde99
Binary files /dev/null and b/images/emoji/1f468-1f3fe.png differ
diff --git a/images/emoji/1f468-1f3ff.png b/images/emoji/1f468-1f3ff.png
new file mode 100644
index 000000000..7c67a7052
Binary files /dev/null and b/images/emoji/1f468-1f3ff.png differ
diff --git a/images/emoji/1f468-1f468-1f466-1f466.png b/images/emoji/1f468-1f468-1f466-1f466.png
new file mode 100644
index 000000000..0944001a3
Binary files /dev/null and b/images/emoji/1f468-1f468-1f466-1f466.png differ
diff --git a/images/emoji/1f468-1f468-1f466.png b/images/emoji/1f468-1f468-1f466.png
new file mode 100644
index 000000000..7a2e4e2c4
Binary files /dev/null and b/images/emoji/1f468-1f468-1f466.png differ
diff --git a/images/emoji/1f468-1f468-1f467-1f466.png b/images/emoji/1f468-1f468-1f467-1f466.png
new file mode 100644
index 000000000..41e351666
Binary files /dev/null and b/images/emoji/1f468-1f468-1f467-1f466.png differ
diff --git a/images/emoji/1f468-1f468-1f467-1f467.png b/images/emoji/1f468-1f468-1f467-1f467.png
new file mode 100644
index 000000000..8e8ccfe6c
Binary files /dev/null and b/images/emoji/1f468-1f468-1f467-1f467.png differ
diff --git a/images/emoji/1f468-1f468-1f467.png b/images/emoji/1f468-1f468-1f467.png
new file mode 100644
index 000000000..9bca550d0
Binary files /dev/null and b/images/emoji/1f468-1f468-1f467.png differ
diff --git a/images/emoji/1f468-1f469-1f466-1f466.png b/images/emoji/1f468-1f469-1f466-1f466.png
new file mode 100644
index 000000000..579eb59f8
Binary files /dev/null and b/images/emoji/1f468-1f469-1f466-1f466.png differ
diff --git a/images/emoji/1f468-1f469-1f467-1f466.png b/images/emoji/1f468-1f469-1f467-1f466.png
new file mode 100644
index 000000000..c5c7b0942
Binary files /dev/null and b/images/emoji/1f468-1f469-1f467-1f466.png differ
diff --git a/images/emoji/1f468-1f469-1f467-1f467.png b/images/emoji/1f468-1f469-1f467-1f467.png
new file mode 100644
index 000000000..b47f3b1c7
Binary files /dev/null and b/images/emoji/1f468-1f469-1f467-1f467.png differ
diff --git a/images/emoji/1f468-1f469-1f467.png b/images/emoji/1f468-1f469-1f467.png
new file mode 100644
index 000000000..ffa6f4293
Binary files /dev/null and b/images/emoji/1f468-1f469-1f467.png differ
diff --git a/images/emoji/1f468-2764-1f468.png b/images/emoji/1f468-2764-1f468.png
new file mode 100644
index 000000000..8759fa5db
Binary files /dev/null and b/images/emoji/1f468-2764-1f468.png differ
diff --git a/images/emoji/1f468-2764-1f48b-1f468.png b/images/emoji/1f468-2764-1f48b-1f468.png
new file mode 100644
index 000000000..a9a0edae1
Binary files /dev/null and b/images/emoji/1f468-2764-1f48b-1f468.png differ
diff --git a/images/emoji/1f468.png b/images/emoji/1f468.png
new file mode 100644
index 000000000..857a02e51
Binary files /dev/null and b/images/emoji/1f468.png differ
diff --git a/images/emoji/1f469-1f3fb.png b/images/emoji/1f469-1f3fb.png
new file mode 100644
index 000000000..ff089b888
Binary files /dev/null and b/images/emoji/1f469-1f3fb.png differ
diff --git a/images/emoji/1f469-1f3fc.png b/images/emoji/1f469-1f3fc.png
new file mode 100644
index 000000000..0719c3780
Binary files /dev/null and b/images/emoji/1f469-1f3fc.png differ
diff --git a/images/emoji/1f469-1f3fd.png b/images/emoji/1f469-1f3fd.png
new file mode 100644
index 000000000..b4d7f21f4
Binary files /dev/null and b/images/emoji/1f469-1f3fd.png differ
diff --git a/images/emoji/1f469-1f3fe.png b/images/emoji/1f469-1f3fe.png
new file mode 100644
index 000000000..6f21d631f
Binary files /dev/null and b/images/emoji/1f469-1f3fe.png differ
diff --git a/images/emoji/1f469-1f3ff.png b/images/emoji/1f469-1f3ff.png
new file mode 100644
index 000000000..cd47bfdd6
Binary files /dev/null and b/images/emoji/1f469-1f3ff.png differ
diff --git a/images/emoji/1f469-1f469-1f466-1f466.png b/images/emoji/1f469-1f469-1f466-1f466.png
new file mode 100644
index 000000000..e3fc2686e
Binary files /dev/null and b/images/emoji/1f469-1f469-1f466-1f466.png differ
diff --git a/images/emoji/1f469-1f469-1f466.png b/images/emoji/1f469-1f469-1f466.png
new file mode 100644
index 000000000..836feae7c
Binary files /dev/null and b/images/emoji/1f469-1f469-1f466.png differ
diff --git a/images/emoji/1f469-1f469-1f467-1f466.png b/images/emoji/1f469-1f469-1f467-1f466.png
new file mode 100644
index 000000000..284d29ab5
Binary files /dev/null and b/images/emoji/1f469-1f469-1f467-1f466.png differ
diff --git a/images/emoji/1f469-1f469-1f467-1f467.png b/images/emoji/1f469-1f469-1f467-1f467.png
new file mode 100644
index 000000000..d8d3f49b8
Binary files /dev/null and b/images/emoji/1f469-1f469-1f467-1f467.png differ
diff --git a/images/emoji/1f469-1f469-1f467.png b/images/emoji/1f469-1f469-1f467.png
new file mode 100644
index 000000000..d8619fa1f
Binary files /dev/null and b/images/emoji/1f469-1f469-1f467.png differ
diff --git a/images/emoji/1f469-2764-1f469.png b/images/emoji/1f469-2764-1f469.png
new file mode 100644
index 000000000..08fdabcdc
Binary files /dev/null and b/images/emoji/1f469-2764-1f469.png differ
diff --git a/images/emoji/1f469-2764-1f48b-1f469.png b/images/emoji/1f469-2764-1f48b-1f469.png
new file mode 100644
index 000000000..4905a5b3e
Binary files /dev/null and b/images/emoji/1f469-2764-1f48b-1f469.png differ
diff --git a/images/emoji/1f469.png b/images/emoji/1f469.png
new file mode 100644
index 000000000..ece440e7a
Binary files /dev/null and b/images/emoji/1f469.png differ
diff --git a/images/emoji/1f46a.png b/images/emoji/1f46a.png
new file mode 100644
index 000000000..0350719a2
Binary files /dev/null and b/images/emoji/1f46a.png differ
diff --git a/images/emoji/1f46b.png b/images/emoji/1f46b.png
new file mode 100644
index 000000000..73f22f0ad
Binary files /dev/null and b/images/emoji/1f46b.png differ
diff --git a/images/emoji/1f46c.png b/images/emoji/1f46c.png
new file mode 100644
index 000000000..a511fda82
Binary files /dev/null and b/images/emoji/1f46c.png differ
diff --git a/images/emoji/1f46d.png b/images/emoji/1f46d.png
new file mode 100644
index 000000000..8623da423
Binary files /dev/null and b/images/emoji/1f46d.png differ
diff --git a/images/emoji/1f46e-1f3fb.png b/images/emoji/1f46e-1f3fb.png
new file mode 100644
index 000000000..6ccba3879
Binary files /dev/null and b/images/emoji/1f46e-1f3fb.png differ
diff --git a/images/emoji/1f46e-1f3fc.png b/images/emoji/1f46e-1f3fc.png
new file mode 100644
index 000000000..7814ea9f5
Binary files /dev/null and b/images/emoji/1f46e-1f3fc.png differ
diff --git a/images/emoji/1f46e-1f3fd.png b/images/emoji/1f46e-1f3fd.png
new file mode 100644
index 000000000..c29f0709b
Binary files /dev/null and b/images/emoji/1f46e-1f3fd.png differ
diff --git a/images/emoji/1f46e-1f3fe.png b/images/emoji/1f46e-1f3fe.png
new file mode 100644
index 000000000..8a009e55e
Binary files /dev/null and b/images/emoji/1f46e-1f3fe.png differ
diff --git a/images/emoji/1f46e-1f3ff.png b/images/emoji/1f46e-1f3ff.png
new file mode 100644
index 000000000..5bdc53c99
Binary files /dev/null and b/images/emoji/1f46e-1f3ff.png differ
diff --git a/images/emoji/1f46e.png b/images/emoji/1f46e.png
new file mode 100644
index 000000000..bd37a787e
Binary files /dev/null and b/images/emoji/1f46e.png differ
diff --git a/images/emoji/1f46f.png b/images/emoji/1f46f.png
new file mode 100644
index 000000000..7a33d199b
Binary files /dev/null and b/images/emoji/1f46f.png differ
diff --git a/images/emoji/1f470-1f3fb.png b/images/emoji/1f470-1f3fb.png
new file mode 100644
index 000000000..c4fb141ae
Binary files /dev/null and b/images/emoji/1f470-1f3fb.png differ
diff --git a/images/emoji/1f470-1f3fc.png b/images/emoji/1f470-1f3fc.png
new file mode 100644
index 000000000..c248769fc
Binary files /dev/null and b/images/emoji/1f470-1f3fc.png differ
diff --git a/images/emoji/1f470-1f3fd.png b/images/emoji/1f470-1f3fd.png
new file mode 100644
index 000000000..962c0a6ee
Binary files /dev/null and b/images/emoji/1f470-1f3fd.png differ
diff --git a/images/emoji/1f470-1f3fe.png b/images/emoji/1f470-1f3fe.png
new file mode 100644
index 000000000..740ca208c
Binary files /dev/null and b/images/emoji/1f470-1f3fe.png differ
diff --git a/images/emoji/1f470-1f3ff.png b/images/emoji/1f470-1f3ff.png
new file mode 100644
index 000000000..5cc559858
Binary files /dev/null and b/images/emoji/1f470-1f3ff.png differ
diff --git a/images/emoji/1f470.png b/images/emoji/1f470.png
new file mode 100644
index 000000000..eaf4bd978
Binary files /dev/null and b/images/emoji/1f470.png differ
diff --git a/images/emoji/1f471-1f3fb.png b/images/emoji/1f471-1f3fb.png
new file mode 100644
index 000000000..7d18ef244
Binary files /dev/null and b/images/emoji/1f471-1f3fb.png differ
diff --git a/images/emoji/1f471-1f3fc.png b/images/emoji/1f471-1f3fc.png
new file mode 100644
index 000000000..dae130731
Binary files /dev/null and b/images/emoji/1f471-1f3fc.png differ
diff --git a/images/emoji/1f471-1f3fd.png b/images/emoji/1f471-1f3fd.png
new file mode 100644
index 000000000..684677e8e
Binary files /dev/null and b/images/emoji/1f471-1f3fd.png differ
diff --git a/images/emoji/1f471-1f3fe.png b/images/emoji/1f471-1f3fe.png
new file mode 100644
index 000000000..012be0b51
Binary files /dev/null and b/images/emoji/1f471-1f3fe.png differ
diff --git a/images/emoji/1f471-1f3ff.png b/images/emoji/1f471-1f3ff.png
new file mode 100644
index 000000000..d4ecc4cf4
Binary files /dev/null and b/images/emoji/1f471-1f3ff.png differ
diff --git a/images/emoji/1f471.png b/images/emoji/1f471.png
new file mode 100644
index 000000000..ad6f01a7d
Binary files /dev/null and b/images/emoji/1f471.png differ
diff --git a/images/emoji/1f472-1f3fb.png b/images/emoji/1f472-1f3fb.png
new file mode 100644
index 000000000..5b7b3def1
Binary files /dev/null and b/images/emoji/1f472-1f3fb.png differ
diff --git a/images/emoji/1f472-1f3fc.png b/images/emoji/1f472-1f3fc.png
new file mode 100644
index 000000000..c8b9cf87f
Binary files /dev/null and b/images/emoji/1f472-1f3fc.png differ
diff --git a/images/emoji/1f472-1f3fd.png b/images/emoji/1f472-1f3fd.png
new file mode 100644
index 000000000..effdd0c4c
Binary files /dev/null and b/images/emoji/1f472-1f3fd.png differ
diff --git a/images/emoji/1f472-1f3fe.png b/images/emoji/1f472-1f3fe.png
new file mode 100644
index 000000000..f885ff46f
Binary files /dev/null and b/images/emoji/1f472-1f3fe.png differ
diff --git a/images/emoji/1f472-1f3ff.png b/images/emoji/1f472-1f3ff.png
new file mode 100644
index 000000000..a6d55ca13
Binary files /dev/null and b/images/emoji/1f472-1f3ff.png differ
diff --git a/images/emoji/1f472.png b/images/emoji/1f472.png
new file mode 100644
index 000000000..7841e1360
Binary files /dev/null and b/images/emoji/1f472.png differ
diff --git a/images/emoji/1f473-1f3fb.png b/images/emoji/1f473-1f3fb.png
new file mode 100644
index 000000000..1e12ee4b2
Binary files /dev/null and b/images/emoji/1f473-1f3fb.png differ
diff --git a/images/emoji/1f473-1f3fc.png b/images/emoji/1f473-1f3fc.png
new file mode 100644
index 000000000..7fe9f01c6
Binary files /dev/null and b/images/emoji/1f473-1f3fc.png differ
diff --git a/images/emoji/1f473-1f3fd.png b/images/emoji/1f473-1f3fd.png
new file mode 100644
index 000000000..f607afd34
Binary files /dev/null and b/images/emoji/1f473-1f3fd.png differ
diff --git a/images/emoji/1f473-1f3fe.png b/images/emoji/1f473-1f3fe.png
new file mode 100644
index 000000000..c05695888
Binary files /dev/null and b/images/emoji/1f473-1f3fe.png differ
diff --git a/images/emoji/1f473-1f3ff.png b/images/emoji/1f473-1f3ff.png
new file mode 100644
index 000000000..df935551c
Binary files /dev/null and b/images/emoji/1f473-1f3ff.png differ
diff --git a/images/emoji/1f473.png b/images/emoji/1f473.png
new file mode 100644
index 000000000..993fd952c
Binary files /dev/null and b/images/emoji/1f473.png differ
diff --git a/images/emoji/1f474-1f3fb.png b/images/emoji/1f474-1f3fb.png
new file mode 100644
index 000000000..cd7d20789
Binary files /dev/null and b/images/emoji/1f474-1f3fb.png differ
diff --git a/images/emoji/1f474-1f3fc.png b/images/emoji/1f474-1f3fc.png
new file mode 100644
index 000000000..3574be8d4
Binary files /dev/null and b/images/emoji/1f474-1f3fc.png differ
diff --git a/images/emoji/1f474-1f3fd.png b/images/emoji/1f474-1f3fd.png
new file mode 100644
index 000000000..bbd95afe0
Binary files /dev/null and b/images/emoji/1f474-1f3fd.png differ
diff --git a/images/emoji/1f474-1f3fe.png b/images/emoji/1f474-1f3fe.png
new file mode 100644
index 000000000..b350a764b
Binary files /dev/null and b/images/emoji/1f474-1f3fe.png differ
diff --git a/images/emoji/1f474-1f3ff.png b/images/emoji/1f474-1f3ff.png
new file mode 100644
index 000000000..05fe24a17
Binary files /dev/null and b/images/emoji/1f474-1f3ff.png differ
diff --git a/images/emoji/1f474.png b/images/emoji/1f474.png
new file mode 100644
index 000000000..5f214571b
Binary files /dev/null and b/images/emoji/1f474.png differ
diff --git a/images/emoji/1f475-1f3fb.png b/images/emoji/1f475-1f3fb.png
new file mode 100644
index 000000000..b49e82140
Binary files /dev/null and b/images/emoji/1f475-1f3fb.png differ
diff --git a/images/emoji/1f475-1f3fc.png b/images/emoji/1f475-1f3fc.png
new file mode 100644
index 000000000..e86bf5ab3
Binary files /dev/null and b/images/emoji/1f475-1f3fc.png differ
diff --git a/images/emoji/1f475-1f3fd.png b/images/emoji/1f475-1f3fd.png
new file mode 100644
index 000000000..83fc14b08
Binary files /dev/null and b/images/emoji/1f475-1f3fd.png differ
diff --git a/images/emoji/1f475-1f3fe.png b/images/emoji/1f475-1f3fe.png
new file mode 100644
index 000000000..ebbf7930f
Binary files /dev/null and b/images/emoji/1f475-1f3fe.png differ
diff --git a/images/emoji/1f475-1f3ff.png b/images/emoji/1f475-1f3ff.png
new file mode 100644
index 000000000..4009012bb
Binary files /dev/null and b/images/emoji/1f475-1f3ff.png differ
diff --git a/images/emoji/1f475.png b/images/emoji/1f475.png
new file mode 100644
index 000000000..52dc49871
Binary files /dev/null and b/images/emoji/1f475.png differ
diff --git a/images/emoji/1f476-1f3fb.png b/images/emoji/1f476-1f3fb.png
new file mode 100644
index 000000000..8c1cada59
Binary files /dev/null and b/images/emoji/1f476-1f3fb.png differ
diff --git a/images/emoji/1f476-1f3fc.png b/images/emoji/1f476-1f3fc.png
new file mode 100644
index 000000000..4ba95bd75
Binary files /dev/null and b/images/emoji/1f476-1f3fc.png differ
diff --git a/images/emoji/1f476-1f3fd.png b/images/emoji/1f476-1f3fd.png
new file mode 100644
index 000000000..f4734c0dc
Binary files /dev/null and b/images/emoji/1f476-1f3fd.png differ
diff --git a/images/emoji/1f476-1f3fe.png b/images/emoji/1f476-1f3fe.png
new file mode 100644
index 000000000..02d864833
Binary files /dev/null and b/images/emoji/1f476-1f3fe.png differ
diff --git a/images/emoji/1f476-1f3ff.png b/images/emoji/1f476-1f3ff.png
new file mode 100644
index 000000000..0653e1603
Binary files /dev/null and b/images/emoji/1f476-1f3ff.png differ
diff --git a/images/emoji/1f476.png b/images/emoji/1f476.png
new file mode 100644
index 000000000..7b28ba891
Binary files /dev/null and b/images/emoji/1f476.png differ
diff --git a/images/emoji/1f477-1f3fb.png b/images/emoji/1f477-1f3fb.png
new file mode 100644
index 000000000..2f24a2bab
Binary files /dev/null and b/images/emoji/1f477-1f3fb.png differ
diff --git a/images/emoji/1f477-1f3fc.png b/images/emoji/1f477-1f3fc.png
new file mode 100644
index 000000000..93c8fec5a
Binary files /dev/null and b/images/emoji/1f477-1f3fc.png differ
diff --git a/images/emoji/1f477-1f3fd.png b/images/emoji/1f477-1f3fd.png
new file mode 100644
index 000000000..abc1f2af2
Binary files /dev/null and b/images/emoji/1f477-1f3fd.png differ
diff --git a/images/emoji/1f477-1f3fe.png b/images/emoji/1f477-1f3fe.png
new file mode 100644
index 000000000..eed83289a
Binary files /dev/null and b/images/emoji/1f477-1f3fe.png differ
diff --git a/images/emoji/1f477-1f3ff.png b/images/emoji/1f477-1f3ff.png
new file mode 100644
index 000000000..acbb220b8
Binary files /dev/null and b/images/emoji/1f477-1f3ff.png differ
diff --git a/images/emoji/1f477.png b/images/emoji/1f477.png
new file mode 100644
index 000000000..a9970a890
Binary files /dev/null and b/images/emoji/1f477.png differ
diff --git a/images/emoji/1f478-1f3fb.png b/images/emoji/1f478-1f3fb.png
new file mode 100644
index 000000000..7e4d850d1
Binary files /dev/null and b/images/emoji/1f478-1f3fb.png differ
diff --git a/images/emoji/1f478-1f3fc.png b/images/emoji/1f478-1f3fc.png
new file mode 100644
index 000000000..8179de403
Binary files /dev/null and b/images/emoji/1f478-1f3fc.png differ
diff --git a/images/emoji/1f478-1f3fd.png b/images/emoji/1f478-1f3fd.png
new file mode 100644
index 000000000..de04809d1
Binary files /dev/null and b/images/emoji/1f478-1f3fd.png differ
diff --git a/images/emoji/1f478-1f3fe.png b/images/emoji/1f478-1f3fe.png
new file mode 100644
index 000000000..c71e69caa
Binary files /dev/null and b/images/emoji/1f478-1f3fe.png differ
diff --git a/images/emoji/1f478-1f3ff.png b/images/emoji/1f478-1f3ff.png
new file mode 100644
index 000000000..063e26459
Binary files /dev/null and b/images/emoji/1f478-1f3ff.png differ
diff --git a/images/emoji/1f478.png b/images/emoji/1f478.png
new file mode 100644
index 000000000..a9958dfff
Binary files /dev/null and b/images/emoji/1f478.png differ
diff --git a/images/emoji/1f479.png b/images/emoji/1f479.png
new file mode 100644
index 000000000..fe8670fda
Binary files /dev/null and b/images/emoji/1f479.png differ
diff --git a/images/emoji/1f47a.png b/images/emoji/1f47a.png
new file mode 100644
index 000000000..e2ffb0c19
Binary files /dev/null and b/images/emoji/1f47a.png differ
diff --git a/images/emoji/1f47b.png b/images/emoji/1f47b.png
new file mode 100644
index 000000000..d22b1ccba
Binary files /dev/null and b/images/emoji/1f47b.png differ
diff --git a/images/emoji/1f47c-1f3fb.png b/images/emoji/1f47c-1f3fb.png
new file mode 100644
index 000000000..391694dc0
Binary files /dev/null and b/images/emoji/1f47c-1f3fb.png differ
diff --git a/images/emoji/1f47c-1f3fc.png b/images/emoji/1f47c-1f3fc.png
new file mode 100644
index 000000000..700cbe6ed
Binary files /dev/null and b/images/emoji/1f47c-1f3fc.png differ
diff --git a/images/emoji/1f47c-1f3fd.png b/images/emoji/1f47c-1f3fd.png
new file mode 100644
index 000000000..be597437d
Binary files /dev/null and b/images/emoji/1f47c-1f3fd.png differ
diff --git a/images/emoji/1f47c-1f3fe.png b/images/emoji/1f47c-1f3fe.png
new file mode 100644
index 000000000..b06d3c853
Binary files /dev/null and b/images/emoji/1f47c-1f3fe.png differ
diff --git a/images/emoji/1f47c-1f3ff.png b/images/emoji/1f47c-1f3ff.png
new file mode 100644
index 000000000..17bd677e3
Binary files /dev/null and b/images/emoji/1f47c-1f3ff.png differ
diff --git a/images/emoji/1f47c.png b/images/emoji/1f47c.png
new file mode 100644
index 000000000..66ea97a3b
Binary files /dev/null and b/images/emoji/1f47c.png differ
diff --git a/images/emoji/1f47d.png b/images/emoji/1f47d.png
new file mode 100644
index 000000000..3b90e9743
Binary files /dev/null and b/images/emoji/1f47d.png differ
diff --git a/images/emoji/1f47e.png b/images/emoji/1f47e.png
new file mode 100644
index 000000000..2e73f5f32
Binary files /dev/null and b/images/emoji/1f47e.png differ
diff --git a/images/emoji/1f47f.png b/images/emoji/1f47f.png
new file mode 100644
index 000000000..83b68e404
Binary files /dev/null and b/images/emoji/1f47f.png differ
diff --git a/images/emoji/1f480.png b/images/emoji/1f480.png
new file mode 100644
index 000000000..26abb1729
Binary files /dev/null and b/images/emoji/1f480.png differ
diff --git a/images/emoji/1f481-1f3fb.png b/images/emoji/1f481-1f3fb.png
new file mode 100644
index 000000000..3d9e22479
Binary files /dev/null and b/images/emoji/1f481-1f3fb.png differ
diff --git a/images/emoji/1f481-1f3fc.png b/images/emoji/1f481-1f3fc.png
new file mode 100644
index 000000000..7853bc60a
Binary files /dev/null and b/images/emoji/1f481-1f3fc.png differ
diff --git a/images/emoji/1f481-1f3fd.png b/images/emoji/1f481-1f3fd.png
new file mode 100644
index 000000000..307514eab
Binary files /dev/null and b/images/emoji/1f481-1f3fd.png differ
diff --git a/images/emoji/1f481-1f3fe.png b/images/emoji/1f481-1f3fe.png
new file mode 100644
index 000000000..95cc7ff36
Binary files /dev/null and b/images/emoji/1f481-1f3fe.png differ
diff --git a/images/emoji/1f481-1f3ff.png b/images/emoji/1f481-1f3ff.png
new file mode 100644
index 000000000..26f8f22b2
Binary files /dev/null and b/images/emoji/1f481-1f3ff.png differ
diff --git a/images/emoji/1f481.png b/images/emoji/1f481.png
new file mode 100644
index 000000000..328cfb316
Binary files /dev/null and b/images/emoji/1f481.png differ
diff --git a/images/emoji/1f482-1f3fb.png b/images/emoji/1f482-1f3fb.png
new file mode 100644
index 000000000..cea9ba274
Binary files /dev/null and b/images/emoji/1f482-1f3fb.png differ
diff --git a/images/emoji/1f482-1f3fc.png b/images/emoji/1f482-1f3fc.png
new file mode 100644
index 000000000..c8c3c6444
Binary files /dev/null and b/images/emoji/1f482-1f3fc.png differ
diff --git a/images/emoji/1f482-1f3fd.png b/images/emoji/1f482-1f3fd.png
new file mode 100644
index 000000000..29d9fc477
Binary files /dev/null and b/images/emoji/1f482-1f3fd.png differ
diff --git a/images/emoji/1f482-1f3fe.png b/images/emoji/1f482-1f3fe.png
new file mode 100644
index 000000000..85fcf9a3b
Binary files /dev/null and b/images/emoji/1f482-1f3fe.png differ
diff --git a/images/emoji/1f482-1f3ff.png b/images/emoji/1f482-1f3ff.png
new file mode 100644
index 000000000..b140a2d23
Binary files /dev/null and b/images/emoji/1f482-1f3ff.png differ
diff --git a/images/emoji/1f482.png b/images/emoji/1f482.png
new file mode 100644
index 000000000..8d7ab3c47
Binary files /dev/null and b/images/emoji/1f482.png differ
diff --git a/images/emoji/1f483-1f3fb.png b/images/emoji/1f483-1f3fb.png
new file mode 100644
index 000000000..27975615e
Binary files /dev/null and b/images/emoji/1f483-1f3fb.png differ
diff --git a/images/emoji/1f483-1f3fc.png b/images/emoji/1f483-1f3fc.png
new file mode 100644
index 000000000..cb04b1f90
Binary files /dev/null and b/images/emoji/1f483-1f3fc.png differ
diff --git a/images/emoji/1f483-1f3fd.png b/images/emoji/1f483-1f3fd.png
new file mode 100644
index 000000000..98c5bca7b
Binary files /dev/null and b/images/emoji/1f483-1f3fd.png differ
diff --git a/images/emoji/1f483-1f3fe.png b/images/emoji/1f483-1f3fe.png
new file mode 100644
index 000000000..fdb1e00cb
Binary files /dev/null and b/images/emoji/1f483-1f3fe.png differ
diff --git a/images/emoji/1f483-1f3ff.png b/images/emoji/1f483-1f3ff.png
new file mode 100644
index 000000000..0e34e0e23
Binary files /dev/null and b/images/emoji/1f483-1f3ff.png differ
diff --git a/images/emoji/1f483.png b/images/emoji/1f483.png
new file mode 100644
index 000000000..d1cdad8dd
Binary files /dev/null and b/images/emoji/1f483.png differ
diff --git a/images/emoji/1f484.png b/images/emoji/1f484.png
new file mode 100644
index 000000000..61a0c084c
Binary files /dev/null and b/images/emoji/1f484.png differ
diff --git a/images/emoji/1f485-1f3fb.png b/images/emoji/1f485-1f3fb.png
new file mode 100644
index 000000000..f1fbfcf52
Binary files /dev/null and b/images/emoji/1f485-1f3fb.png differ
diff --git a/images/emoji/1f485-1f3fc.png b/images/emoji/1f485-1f3fc.png
new file mode 100644
index 000000000..02b836b2f
Binary files /dev/null and b/images/emoji/1f485-1f3fc.png differ
diff --git a/images/emoji/1f485-1f3fd.png b/images/emoji/1f485-1f3fd.png
new file mode 100644
index 000000000..7432e3cf2
Binary files /dev/null and b/images/emoji/1f485-1f3fd.png differ
diff --git a/images/emoji/1f485-1f3fe.png b/images/emoji/1f485-1f3fe.png
new file mode 100644
index 000000000..e4272692c
Binary files /dev/null and b/images/emoji/1f485-1f3fe.png differ
diff --git a/images/emoji/1f485-1f3ff.png b/images/emoji/1f485-1f3ff.png
new file mode 100644
index 000000000..d29e1c553
Binary files /dev/null and b/images/emoji/1f485-1f3ff.png differ
diff --git a/images/emoji/1f485.png b/images/emoji/1f485.png
new file mode 100644
index 000000000..aa52af705
Binary files /dev/null and b/images/emoji/1f485.png differ
diff --git a/images/emoji/1f486-1f3fb.png b/images/emoji/1f486-1f3fb.png
new file mode 100644
index 000000000..f9dea75f3
Binary files /dev/null and b/images/emoji/1f486-1f3fb.png differ
diff --git a/images/emoji/1f486-1f3fc.png b/images/emoji/1f486-1f3fc.png
new file mode 100644
index 000000000..0bb244a27
Binary files /dev/null and b/images/emoji/1f486-1f3fc.png differ
diff --git a/images/emoji/1f486-1f3fd.png b/images/emoji/1f486-1f3fd.png
new file mode 100644
index 000000000..06941c86b
Binary files /dev/null and b/images/emoji/1f486-1f3fd.png differ
diff --git a/images/emoji/1f486-1f3fe.png b/images/emoji/1f486-1f3fe.png
new file mode 100644
index 000000000..671d52310
Binary files /dev/null and b/images/emoji/1f486-1f3fe.png differ
diff --git a/images/emoji/1f486-1f3ff.png b/images/emoji/1f486-1f3ff.png
new file mode 100644
index 000000000..6a388c0d0
Binary files /dev/null and b/images/emoji/1f486-1f3ff.png differ
diff --git a/images/emoji/1f486.png b/images/emoji/1f486.png
new file mode 100644
index 000000000..9ed04ff13
Binary files /dev/null and b/images/emoji/1f486.png differ
diff --git a/images/emoji/1f487-1f3fb.png b/images/emoji/1f487-1f3fb.png
new file mode 100644
index 000000000..c743b74ab
Binary files /dev/null and b/images/emoji/1f487-1f3fb.png differ
diff --git a/images/emoji/1f487-1f3fc.png b/images/emoji/1f487-1f3fc.png
new file mode 100644
index 000000000..dbbddcb34
Binary files /dev/null and b/images/emoji/1f487-1f3fc.png differ
diff --git a/images/emoji/1f487-1f3fd.png b/images/emoji/1f487-1f3fd.png
new file mode 100644
index 000000000..d5ad19563
Binary files /dev/null and b/images/emoji/1f487-1f3fd.png differ
diff --git a/images/emoji/1f487-1f3fe.png b/images/emoji/1f487-1f3fe.png
new file mode 100644
index 000000000..244fd3af0
Binary files /dev/null and b/images/emoji/1f487-1f3fe.png differ
diff --git a/images/emoji/1f487-1f3ff.png b/images/emoji/1f487-1f3ff.png
new file mode 100644
index 000000000..20a94a886
Binary files /dev/null and b/images/emoji/1f487-1f3ff.png differ
diff --git a/images/emoji/1f487.png b/images/emoji/1f487.png
new file mode 100644
index 000000000..91266b129
Binary files /dev/null and b/images/emoji/1f487.png differ
diff --git a/images/emoji/1f488.png b/images/emoji/1f488.png
new file mode 100644
index 000000000..896f4d716
Binary files /dev/null and b/images/emoji/1f488.png differ
diff --git a/images/emoji/1f489.png b/images/emoji/1f489.png
new file mode 100644
index 000000000..71c1a9528
Binary files /dev/null and b/images/emoji/1f489.png differ
diff --git a/images/emoji/1f48a.png b/images/emoji/1f48a.png
new file mode 100644
index 000000000..1d4530e77
Binary files /dev/null and b/images/emoji/1f48a.png differ
diff --git a/images/emoji/1f48b.png b/images/emoji/1f48b.png
new file mode 100644
index 000000000..85e6dcfc4
Binary files /dev/null and b/images/emoji/1f48b.png differ
diff --git a/images/emoji/1f48c.png b/images/emoji/1f48c.png
new file mode 100644
index 000000000..3c3c767e7
Binary files /dev/null and b/images/emoji/1f48c.png differ
diff --git a/images/emoji/1f48d.png b/images/emoji/1f48d.png
new file mode 100644
index 000000000..87d227adb
Binary files /dev/null and b/images/emoji/1f48d.png differ
diff --git a/images/emoji/1f48e.png b/images/emoji/1f48e.png
new file mode 100644
index 000000000..db122d26a
Binary files /dev/null and b/images/emoji/1f48e.png differ
diff --git a/images/emoji/1f48f.png b/images/emoji/1f48f.png
new file mode 100644
index 000000000..9aa519da9
Binary files /dev/null and b/images/emoji/1f48f.png differ
diff --git a/images/emoji/1f490.png b/images/emoji/1f490.png
new file mode 100644
index 000000000..11455af6d
Binary files /dev/null and b/images/emoji/1f490.png differ
diff --git a/images/emoji/1f491.png b/images/emoji/1f491.png
new file mode 100644
index 000000000..62111601b
Binary files /dev/null and b/images/emoji/1f491.png differ
diff --git a/images/emoji/1f492.png b/images/emoji/1f492.png
new file mode 100644
index 000000000..d0d8aa0bf
Binary files /dev/null and b/images/emoji/1f492.png differ
diff --git a/images/emoji/1f493.png b/images/emoji/1f493.png
new file mode 100644
index 000000000..0bcf2d1d5
Binary files /dev/null and b/images/emoji/1f493.png differ
diff --git a/images/emoji/1f494.png b/images/emoji/1f494.png
new file mode 100644
index 000000000..718e26ee1
Binary files /dev/null and b/images/emoji/1f494.png differ
diff --git a/images/emoji/1f495.png b/images/emoji/1f495.png
new file mode 100644
index 000000000..4d8c33860
Binary files /dev/null and b/images/emoji/1f495.png differ
diff --git a/images/emoji/1f496.png b/images/emoji/1f496.png
new file mode 100644
index 000000000..670926945
Binary files /dev/null and b/images/emoji/1f496.png differ
diff --git a/images/emoji/1f497.png b/images/emoji/1f497.png
new file mode 100644
index 000000000..d6e694e97
Binary files /dev/null and b/images/emoji/1f497.png differ
diff --git a/images/emoji/1f498.png b/images/emoji/1f498.png
new file mode 100644
index 000000000..2df0078dd
Binary files /dev/null and b/images/emoji/1f498.png differ
diff --git a/images/emoji/1f499.png b/images/emoji/1f499.png
new file mode 100644
index 000000000..bdf1287e5
Binary files /dev/null and b/images/emoji/1f499.png differ
diff --git a/images/emoji/1f49a.png b/images/emoji/1f49a.png
new file mode 100644
index 000000000..c52d60a58
Binary files /dev/null and b/images/emoji/1f49a.png differ
diff --git a/images/emoji/1f49b.png b/images/emoji/1f49b.png
new file mode 100644
index 000000000..7901a9d01
Binary files /dev/null and b/images/emoji/1f49b.png differ
diff --git a/images/emoji/1f49c.png b/images/emoji/1f49c.png
new file mode 100644
index 000000000..95c53a9ad
Binary files /dev/null and b/images/emoji/1f49c.png differ
diff --git a/images/emoji/1f49d.png b/images/emoji/1f49d.png
new file mode 100644
index 000000000..902ceafe4
Binary files /dev/null and b/images/emoji/1f49d.png differ
diff --git a/images/emoji/1f49e.png b/images/emoji/1f49e.png
new file mode 100644
index 000000000..7b9d1948f
Binary files /dev/null and b/images/emoji/1f49e.png differ
diff --git a/images/emoji/1f49f.png b/images/emoji/1f49f.png
new file mode 100644
index 000000000..5443f60bc
Binary files /dev/null and b/images/emoji/1f49f.png differ
diff --git a/images/emoji/1f4a0.png b/images/emoji/1f4a0.png
new file mode 100644
index 000000000..2a22a26d1
Binary files /dev/null and b/images/emoji/1f4a0.png differ
diff --git a/images/emoji/1f4a1.png b/images/emoji/1f4a1.png
new file mode 100644
index 000000000..38e32e02d
Binary files /dev/null and b/images/emoji/1f4a1.png differ
diff --git a/images/emoji/1f4a2.png b/images/emoji/1f4a2.png
new file mode 100644
index 000000000..d63c2e000
Binary files /dev/null and b/images/emoji/1f4a2.png differ
diff --git a/images/emoji/1f4a3.png b/images/emoji/1f4a3.png
new file mode 100644
index 000000000..c7f8f81c9
Binary files /dev/null and b/images/emoji/1f4a3.png differ
diff --git a/images/emoji/1f4a4.png b/images/emoji/1f4a4.png
new file mode 100644
index 000000000..9bc72b446
Binary files /dev/null and b/images/emoji/1f4a4.png differ
diff --git a/images/emoji/1f4a5.png b/images/emoji/1f4a5.png
new file mode 100644
index 000000000..9b0f027b1
Binary files /dev/null and b/images/emoji/1f4a5.png differ
diff --git a/images/emoji/1f4a6.png b/images/emoji/1f4a6.png
new file mode 100644
index 000000000..4106117eb
Binary files /dev/null and b/images/emoji/1f4a6.png differ
diff --git a/images/emoji/1f4a7.png b/images/emoji/1f4a7.png
new file mode 100644
index 000000000..71241ec30
Binary files /dev/null and b/images/emoji/1f4a7.png differ
diff --git a/images/emoji/1f4a8.png b/images/emoji/1f4a8.png
new file mode 100644
index 000000000..064b8525c
Binary files /dev/null and b/images/emoji/1f4a8.png differ
diff --git a/images/emoji/1f4a9.png b/images/emoji/1f4a9.png
new file mode 100644
index 000000000..10b15e72d
Binary files /dev/null and b/images/emoji/1f4a9.png differ
diff --git a/images/emoji/1f4aa-1f3fb.png b/images/emoji/1f4aa-1f3fb.png
new file mode 100644
index 000000000..1522942ce
Binary files /dev/null and b/images/emoji/1f4aa-1f3fb.png differ
diff --git a/images/emoji/1f4aa-1f3fc.png b/images/emoji/1f4aa-1f3fc.png
new file mode 100644
index 000000000..569c6e832
Binary files /dev/null and b/images/emoji/1f4aa-1f3fc.png differ
diff --git a/images/emoji/1f4aa-1f3fd.png b/images/emoji/1f4aa-1f3fd.png
new file mode 100644
index 000000000..0a76b00fa
Binary files /dev/null and b/images/emoji/1f4aa-1f3fd.png differ
diff --git a/images/emoji/1f4aa-1f3fe.png b/images/emoji/1f4aa-1f3fe.png
new file mode 100644
index 000000000..f0cf31328
Binary files /dev/null and b/images/emoji/1f4aa-1f3fe.png differ
diff --git a/images/emoji/1f4aa-1f3ff.png b/images/emoji/1f4aa-1f3ff.png
new file mode 100644
index 000000000..4fda92460
Binary files /dev/null and b/images/emoji/1f4aa-1f3ff.png differ
diff --git a/images/emoji/1f4aa.png b/images/emoji/1f4aa.png
new file mode 100644
index 000000000..7e67c1880
Binary files /dev/null and b/images/emoji/1f4aa.png differ
diff --git a/images/emoji/1f4ab.png b/images/emoji/1f4ab.png
new file mode 100644
index 000000000..85f52efad
Binary files /dev/null and b/images/emoji/1f4ab.png differ
diff --git a/images/emoji/1f4ac.png b/images/emoji/1f4ac.png
new file mode 100644
index 000000000..a34ef7417
Binary files /dev/null and b/images/emoji/1f4ac.png differ
diff --git a/images/emoji/1f4ad.png b/images/emoji/1f4ad.png
new file mode 100644
index 000000000..72fe8fa70
Binary files /dev/null and b/images/emoji/1f4ad.png differ
diff --git a/images/emoji/1f4ae.png b/images/emoji/1f4ae.png
new file mode 100644
index 000000000..d6af8b600
Binary files /dev/null and b/images/emoji/1f4ae.png differ
diff --git a/images/emoji/1f4af.png b/images/emoji/1f4af.png
new file mode 100644
index 000000000..6903ff030
Binary files /dev/null and b/images/emoji/1f4af.png differ
diff --git a/images/emoji/1f4b0.png b/images/emoji/1f4b0.png
new file mode 100644
index 000000000..b9296be09
Binary files /dev/null and b/images/emoji/1f4b0.png differ
diff --git a/images/emoji/1f4b1.png b/images/emoji/1f4b1.png
new file mode 100644
index 000000000..4d46c6050
Binary files /dev/null and b/images/emoji/1f4b1.png differ
diff --git a/images/emoji/1f4b2.png b/images/emoji/1f4b2.png
new file mode 100644
index 000000000..ef2c2e205
Binary files /dev/null and b/images/emoji/1f4b2.png differ
diff --git a/images/emoji/1f4b3.png b/images/emoji/1f4b3.png
new file mode 100644
index 000000000..372777d5c
Binary files /dev/null and b/images/emoji/1f4b3.png differ
diff --git a/images/emoji/1f4b4.png b/images/emoji/1f4b4.png
new file mode 100644
index 000000000..63ee4799d
Binary files /dev/null and b/images/emoji/1f4b4.png differ
diff --git a/images/emoji/1f4b5.png b/images/emoji/1f4b5.png
new file mode 100644
index 000000000..a9904c282
Binary files /dev/null and b/images/emoji/1f4b5.png differ
diff --git a/images/emoji/1f4b6.png b/images/emoji/1f4b6.png
new file mode 100644
index 000000000..a49020820
Binary files /dev/null and b/images/emoji/1f4b6.png differ
diff --git a/images/emoji/1f4b7.png b/images/emoji/1f4b7.png
new file mode 100644
index 000000000..a0d4c4099
Binary files /dev/null and b/images/emoji/1f4b7.png differ
diff --git a/images/emoji/1f4b8.png b/images/emoji/1f4b8.png
new file mode 100644
index 000000000..f022b04b3
Binary files /dev/null and b/images/emoji/1f4b8.png differ
diff --git a/images/emoji/1f4b9.png b/images/emoji/1f4b9.png
new file mode 100644
index 000000000..9773f03be
Binary files /dev/null and b/images/emoji/1f4b9.png differ
diff --git a/images/emoji/1f4ba.png b/images/emoji/1f4ba.png
new file mode 100644
index 000000000..a6d72d95a
Binary files /dev/null and b/images/emoji/1f4ba.png differ
diff --git a/images/emoji/1f4bb.png b/images/emoji/1f4bb.png
new file mode 100644
index 000000000..c1fee27e3
Binary files /dev/null and b/images/emoji/1f4bb.png differ
diff --git a/images/emoji/1f4bc.png b/images/emoji/1f4bc.png
new file mode 100644
index 000000000..b9912ba21
Binary files /dev/null and b/images/emoji/1f4bc.png differ
diff --git a/images/emoji/1f4bd.png b/images/emoji/1f4bd.png
new file mode 100644
index 000000000..9fa94cfbe
Binary files /dev/null and b/images/emoji/1f4bd.png differ
diff --git a/images/emoji/1f4be.png b/images/emoji/1f4be.png
new file mode 100644
index 000000000..072a76d3c
Binary files /dev/null and b/images/emoji/1f4be.png differ
diff --git a/images/emoji/1f4bf.png b/images/emoji/1f4bf.png
new file mode 100644
index 000000000..e6b01449c
Binary files /dev/null and b/images/emoji/1f4bf.png differ
diff --git a/images/emoji/1f4c0.png b/images/emoji/1f4c0.png
new file mode 100644
index 000000000..045a6f7a0
Binary files /dev/null and b/images/emoji/1f4c0.png differ
diff --git a/images/emoji/1f4c1.png b/images/emoji/1f4c1.png
new file mode 100644
index 000000000..addedaf08
Binary files /dev/null and b/images/emoji/1f4c1.png differ
diff --git a/images/emoji/1f4c2.png b/images/emoji/1f4c2.png
new file mode 100644
index 000000000..3993b0922
Binary files /dev/null and b/images/emoji/1f4c2.png differ
diff --git a/images/emoji/1f4c3.png b/images/emoji/1f4c3.png
new file mode 100644
index 000000000..06355319c
Binary files /dev/null and b/images/emoji/1f4c3.png differ
diff --git a/images/emoji/1f4c4.png b/images/emoji/1f4c4.png
new file mode 100644
index 000000000..ba4ed757e
Binary files /dev/null and b/images/emoji/1f4c4.png differ
diff --git a/images/emoji/1f4c5.png b/images/emoji/1f4c5.png
new file mode 100644
index 000000000..f05b3da97
Binary files /dev/null and b/images/emoji/1f4c5.png differ
diff --git a/images/emoji/1f4c6.png b/images/emoji/1f4c6.png
new file mode 100644
index 000000000..47353b744
Binary files /dev/null and b/images/emoji/1f4c6.png differ
diff --git a/images/emoji/1f4c7.png b/images/emoji/1f4c7.png
new file mode 100644
index 000000000..151e11cb3
Binary files /dev/null and b/images/emoji/1f4c7.png differ
diff --git a/images/emoji/1f4c8.png b/images/emoji/1f4c8.png
new file mode 100644
index 000000000..f13cfcf99
Binary files /dev/null and b/images/emoji/1f4c8.png differ
diff --git a/images/emoji/1f4c9.png b/images/emoji/1f4c9.png
new file mode 100644
index 000000000..5222ec72d
Binary files /dev/null and b/images/emoji/1f4c9.png differ
diff --git a/images/emoji/1f4ca.png b/images/emoji/1f4ca.png
new file mode 100644
index 000000000..53c894550
Binary files /dev/null and b/images/emoji/1f4ca.png differ
diff --git a/images/emoji/1f4cb.png b/images/emoji/1f4cb.png
new file mode 100644
index 000000000..ffd5b315d
Binary files /dev/null and b/images/emoji/1f4cb.png differ
diff --git a/images/emoji/1f4cc.png b/images/emoji/1f4cc.png
new file mode 100644
index 000000000..57e07d7f4
Binary files /dev/null and b/images/emoji/1f4cc.png differ
diff --git a/images/emoji/1f4cd.png b/images/emoji/1f4cd.png
new file mode 100644
index 000000000..28b9d7286
Binary files /dev/null and b/images/emoji/1f4cd.png differ
diff --git a/images/emoji/1f4ce.png b/images/emoji/1f4ce.png
new file mode 100644
index 000000000..8cd8d4f87
Binary files /dev/null and b/images/emoji/1f4ce.png differ
diff --git a/images/emoji/1f4cf.png b/images/emoji/1f4cf.png
new file mode 100644
index 000000000..1017b7433
Binary files /dev/null and b/images/emoji/1f4cf.png differ
diff --git a/images/emoji/1f4d0.png b/images/emoji/1f4d0.png
new file mode 100644
index 000000000..77dee9ee8
Binary files /dev/null and b/images/emoji/1f4d0.png differ
diff --git a/images/emoji/1f4d1.png b/images/emoji/1f4d1.png
new file mode 100644
index 000000000..23a3083ad
Binary files /dev/null and b/images/emoji/1f4d1.png differ
diff --git a/images/emoji/1f4d2.png b/images/emoji/1f4d2.png
new file mode 100644
index 000000000..ef0ea3b1f
Binary files /dev/null and b/images/emoji/1f4d2.png differ
diff --git a/images/emoji/1f4d3.png b/images/emoji/1f4d3.png
new file mode 100644
index 000000000..f6c28b491
Binary files /dev/null and b/images/emoji/1f4d3.png differ
diff --git a/images/emoji/1f4d4.png b/images/emoji/1f4d4.png
new file mode 100644
index 000000000..03f566b6d
Binary files /dev/null and b/images/emoji/1f4d4.png differ
diff --git a/images/emoji/1f4d5.png b/images/emoji/1f4d5.png
new file mode 100644
index 000000000..6395cf215
Binary files /dev/null and b/images/emoji/1f4d5.png differ
diff --git a/images/emoji/1f4d6.png b/images/emoji/1f4d6.png
new file mode 100644
index 000000000..0f4447ed3
Binary files /dev/null and b/images/emoji/1f4d6.png differ
diff --git a/images/emoji/1f4d7.png b/images/emoji/1f4d7.png
new file mode 100644
index 000000000..e5e411cf3
Binary files /dev/null and b/images/emoji/1f4d7.png differ
diff --git a/images/emoji/1f4d8.png b/images/emoji/1f4d8.png
new file mode 100644
index 000000000..d73dfd725
Binary files /dev/null and b/images/emoji/1f4d8.png differ
diff --git a/images/emoji/1f4d9.png b/images/emoji/1f4d9.png
new file mode 100644
index 000000000..ab40e6ae6
Binary files /dev/null and b/images/emoji/1f4d9.png differ
diff --git a/images/emoji/1f4da.png b/images/emoji/1f4da.png
new file mode 100644
index 000000000..59a8bafeb
Binary files /dev/null and b/images/emoji/1f4da.png differ
diff --git a/images/emoji/1f4db.png b/images/emoji/1f4db.png
new file mode 100644
index 000000000..ec5ee213e
Binary files /dev/null and b/images/emoji/1f4db.png differ
diff --git a/images/emoji/1f4dc.png b/images/emoji/1f4dc.png
new file mode 100644
index 000000000..50ee5dcd4
Binary files /dev/null and b/images/emoji/1f4dc.png differ
diff --git a/images/emoji/1f4dd.png b/images/emoji/1f4dd.png
new file mode 100644
index 000000000..9e44f60f4
Binary files /dev/null and b/images/emoji/1f4dd.png differ
diff --git a/images/emoji/1f4de.png b/images/emoji/1f4de.png
new file mode 100644
index 000000000..69388316c
Binary files /dev/null and b/images/emoji/1f4de.png differ
diff --git a/images/emoji/1f4df.png b/images/emoji/1f4df.png
new file mode 100644
index 000000000..b24b99306
Binary files /dev/null and b/images/emoji/1f4df.png differ
diff --git a/images/emoji/1f4e0.png b/images/emoji/1f4e0.png
new file mode 100644
index 000000000..6f929e294
Binary files /dev/null and b/images/emoji/1f4e0.png differ
diff --git a/images/emoji/1f4e1.png b/images/emoji/1f4e1.png
new file mode 100644
index 000000000..db0372795
Binary files /dev/null and b/images/emoji/1f4e1.png differ
diff --git a/images/emoji/1f4e2.png b/images/emoji/1f4e2.png
new file mode 100644
index 000000000..5fd76a95b
Binary files /dev/null and b/images/emoji/1f4e2.png differ
diff --git a/images/emoji/1f4e3.png b/images/emoji/1f4e3.png
new file mode 100644
index 000000000..4e6735188
Binary files /dev/null and b/images/emoji/1f4e3.png differ
diff --git a/images/emoji/1f4e4.png b/images/emoji/1f4e4.png
new file mode 100644
index 000000000..46493ed5b
Binary files /dev/null and b/images/emoji/1f4e4.png differ
diff --git a/images/emoji/1f4e5.png b/images/emoji/1f4e5.png
new file mode 100644
index 000000000..41a6be2b0
Binary files /dev/null and b/images/emoji/1f4e5.png differ
diff --git a/images/emoji/1f4e6.png b/images/emoji/1f4e6.png
new file mode 100644
index 000000000..85431756a
Binary files /dev/null and b/images/emoji/1f4e6.png differ
diff --git a/images/emoji/1f4e7.png b/images/emoji/1f4e7.png
new file mode 100644
index 000000000..d22e654a2
Binary files /dev/null and b/images/emoji/1f4e7.png differ
diff --git a/images/emoji/1f4e8.png b/images/emoji/1f4e8.png
new file mode 100644
index 000000000..fd22e8818
Binary files /dev/null and b/images/emoji/1f4e8.png differ
diff --git a/images/emoji/1f4e9.png b/images/emoji/1f4e9.png
new file mode 100644
index 000000000..7448a6b76
Binary files /dev/null and b/images/emoji/1f4e9.png differ
diff --git a/images/emoji/1f4ea.png b/images/emoji/1f4ea.png
new file mode 100644
index 000000000..ddc705db0
Binary files /dev/null and b/images/emoji/1f4ea.png differ
diff --git a/images/emoji/1f4eb.png b/images/emoji/1f4eb.png
new file mode 100644
index 000000000..ef5174e40
Binary files /dev/null and b/images/emoji/1f4eb.png differ
diff --git a/images/emoji/1f4ec.png b/images/emoji/1f4ec.png
new file mode 100644
index 000000000..5460616a5
Binary files /dev/null and b/images/emoji/1f4ec.png differ
diff --git a/images/emoji/1f4ed.png b/images/emoji/1f4ed.png
new file mode 100644
index 000000000..f9aeee6b1
Binary files /dev/null and b/images/emoji/1f4ed.png differ
diff --git a/images/emoji/1f4ee.png b/images/emoji/1f4ee.png
new file mode 100644
index 000000000..07c9c4ab3
Binary files /dev/null and b/images/emoji/1f4ee.png differ
diff --git a/images/emoji/1f4ef.png b/images/emoji/1f4ef.png
new file mode 100644
index 000000000..c173b8dbd
Binary files /dev/null and b/images/emoji/1f4ef.png differ
diff --git a/images/emoji/1f4f0.png b/images/emoji/1f4f0.png
new file mode 100644
index 000000000..2aa8f060b
Binary files /dev/null and b/images/emoji/1f4f0.png differ
diff --git a/images/emoji/1f4f1.png b/images/emoji/1f4f1.png
new file mode 100644
index 000000000..fd377acf8
Binary files /dev/null and b/images/emoji/1f4f1.png differ
diff --git a/images/emoji/1f4f2.png b/images/emoji/1f4f2.png
new file mode 100644
index 000000000..e2f308f8e
Binary files /dev/null and b/images/emoji/1f4f2.png differ
diff --git a/images/emoji/1f4f3.png b/images/emoji/1f4f3.png
new file mode 100644
index 000000000..cc46510e4
Binary files /dev/null and b/images/emoji/1f4f3.png differ
diff --git a/images/emoji/1f4f4.png b/images/emoji/1f4f4.png
new file mode 100644
index 000000000..8b661ec1c
Binary files /dev/null and b/images/emoji/1f4f4.png differ
diff --git a/images/emoji/1f4f5.png b/images/emoji/1f4f5.png
new file mode 100644
index 000000000..7b1ae6ea5
Binary files /dev/null and b/images/emoji/1f4f5.png differ
diff --git a/images/emoji/1f4f6.png b/images/emoji/1f4f6.png
new file mode 100644
index 000000000..ee2b5a4b5
Binary files /dev/null and b/images/emoji/1f4f6.png differ
diff --git a/images/emoji/1f4f7.png b/images/emoji/1f4f7.png
new file mode 100644
index 000000000..0a3429f72
Binary files /dev/null and b/images/emoji/1f4f7.png differ
diff --git a/images/emoji/1f4f8.png b/images/emoji/1f4f8.png
new file mode 100644
index 000000000..27471da20
Binary files /dev/null and b/images/emoji/1f4f8.png differ
diff --git a/images/emoji/1f4f9.png b/images/emoji/1f4f9.png
new file mode 100644
index 000000000..8008d1414
Binary files /dev/null and b/images/emoji/1f4f9.png differ
diff --git a/images/emoji/1f4fa.png b/images/emoji/1f4fa.png
new file mode 100644
index 000000000..999f1fb5c
Binary files /dev/null and b/images/emoji/1f4fa.png differ
diff --git a/images/emoji/1f4fb.png b/images/emoji/1f4fb.png
new file mode 100644
index 000000000..dec381fa2
Binary files /dev/null and b/images/emoji/1f4fb.png differ
diff --git a/images/emoji/1f4fc.png b/images/emoji/1f4fc.png
new file mode 100644
index 000000000..b9eb78ecd
Binary files /dev/null and b/images/emoji/1f4fc.png differ
diff --git a/images/emoji/1f4fd.png b/images/emoji/1f4fd.png
new file mode 100644
index 000000000..ce9ab0daa
Binary files /dev/null and b/images/emoji/1f4fd.png differ
diff --git a/images/emoji/1f4ff.png b/images/emoji/1f4ff.png
new file mode 100644
index 000000000..a4b6dfcc6
Binary files /dev/null and b/images/emoji/1f4ff.png differ
diff --git a/images/emoji/1f500.png b/images/emoji/1f500.png
new file mode 100644
index 000000000..5904badde
Binary files /dev/null and b/images/emoji/1f500.png differ
diff --git a/images/emoji/1f501.png b/images/emoji/1f501.png
new file mode 100644
index 000000000..540ce4e0f
Binary files /dev/null and b/images/emoji/1f501.png differ
diff --git a/images/emoji/1f502.png b/images/emoji/1f502.png
new file mode 100644
index 000000000..9567e8333
Binary files /dev/null and b/images/emoji/1f502.png differ
diff --git a/images/emoji/1f503.png b/images/emoji/1f503.png
new file mode 100644
index 000000000..26e49c383
Binary files /dev/null and b/images/emoji/1f503.png differ
diff --git a/images/emoji/1f504.png b/images/emoji/1f504.png
new file mode 100644
index 000000000..8d06d8e09
Binary files /dev/null and b/images/emoji/1f504.png differ
diff --git a/images/emoji/1f505.png b/images/emoji/1f505.png
new file mode 100644
index 000000000..543011d39
Binary files /dev/null and b/images/emoji/1f505.png differ
diff --git a/images/emoji/1f506.png b/images/emoji/1f506.png
new file mode 100644
index 000000000..c41f2d5fd
Binary files /dev/null and b/images/emoji/1f506.png differ
diff --git a/images/emoji/1f507.png b/images/emoji/1f507.png
new file mode 100644
index 000000000..7c1788e50
Binary files /dev/null and b/images/emoji/1f507.png differ
diff --git a/images/emoji/1f508.png b/images/emoji/1f508.png
new file mode 100644
index 000000000..7bcffb8fc
Binary files /dev/null and b/images/emoji/1f508.png differ
diff --git a/images/emoji/1f509.png b/images/emoji/1f509.png
new file mode 100644
index 000000000..e75ddca53
Binary files /dev/null and b/images/emoji/1f509.png differ
diff --git a/images/emoji/1f50a.png b/images/emoji/1f50a.png
new file mode 100644
index 000000000..8370033a5
Binary files /dev/null and b/images/emoji/1f50a.png differ
diff --git a/images/emoji/1f50b.png b/images/emoji/1f50b.png
new file mode 100644
index 000000000..f593e2bdb
Binary files /dev/null and b/images/emoji/1f50b.png differ
diff --git a/images/emoji/1f50c.png b/images/emoji/1f50c.png
new file mode 100644
index 000000000..31d1eb215
Binary files /dev/null and b/images/emoji/1f50c.png differ
diff --git a/images/emoji/1f50d.png b/images/emoji/1f50d.png
new file mode 100644
index 000000000..55487156a
Binary files /dev/null and b/images/emoji/1f50d.png differ
diff --git a/images/emoji/1f50e.png b/images/emoji/1f50e.png
new file mode 100644
index 000000000..0f4b1bca8
Binary files /dev/null and b/images/emoji/1f50e.png differ
diff --git a/images/emoji/1f50f.png b/images/emoji/1f50f.png
new file mode 100644
index 000000000..19a07d162
Binary files /dev/null and b/images/emoji/1f50f.png differ
diff --git a/images/emoji/1f510.png b/images/emoji/1f510.png
new file mode 100644
index 000000000..1c1cd5d07
Binary files /dev/null and b/images/emoji/1f510.png differ
diff --git a/images/emoji/1f511.png b/images/emoji/1f511.png
new file mode 100644
index 000000000..319cd1b88
Binary files /dev/null and b/images/emoji/1f511.png differ
diff --git a/images/emoji/1f512.png b/images/emoji/1f512.png
new file mode 100644
index 000000000..5a739c466
Binary files /dev/null and b/images/emoji/1f512.png differ
diff --git a/images/emoji/1f513.png b/images/emoji/1f513.png
new file mode 100644
index 000000000..4a74a6939
Binary files /dev/null and b/images/emoji/1f513.png differ
diff --git a/images/emoji/1f514.png b/images/emoji/1f514.png
new file mode 100644
index 000000000..776f4fdd0
Binary files /dev/null and b/images/emoji/1f514.png differ
diff --git a/images/emoji/1f515.png b/images/emoji/1f515.png
new file mode 100644
index 000000000..15cb38dd1
Binary files /dev/null and b/images/emoji/1f515.png differ
diff --git a/images/emoji/1f516.png b/images/emoji/1f516.png
new file mode 100644
index 000000000..bbb444611
Binary files /dev/null and b/images/emoji/1f516.png differ
diff --git a/images/emoji/1f517.png b/images/emoji/1f517.png
new file mode 100644
index 000000000..ae20f0f8e
Binary files /dev/null and b/images/emoji/1f517.png differ
diff --git a/images/emoji/1f518.png b/images/emoji/1f518.png
new file mode 100644
index 000000000..3a23449d9
Binary files /dev/null and b/images/emoji/1f518.png differ
diff --git a/images/emoji/1f519.png b/images/emoji/1f519.png
new file mode 100644
index 000000000..d32c5d4f1
Binary files /dev/null and b/images/emoji/1f519.png differ
diff --git a/images/emoji/1f51a.png b/images/emoji/1f51a.png
new file mode 100644
index 000000000..ef3ccd5f3
Binary files /dev/null and b/images/emoji/1f51a.png differ
diff --git a/images/emoji/1f51b.png b/images/emoji/1f51b.png
new file mode 100644
index 000000000..a0c371ae2
Binary files /dev/null and b/images/emoji/1f51b.png differ
diff --git a/images/emoji/1f51c.png b/images/emoji/1f51c.png
new file mode 100644
index 000000000..8cdfd8669
Binary files /dev/null and b/images/emoji/1f51c.png differ
diff --git a/images/emoji/1f51d.png b/images/emoji/1f51d.png
new file mode 100644
index 000000000..49dea8c08
Binary files /dev/null and b/images/emoji/1f51d.png differ
diff --git a/images/emoji/1f51e.png b/images/emoji/1f51e.png
new file mode 100644
index 000000000..6dfe6da51
Binary files /dev/null and b/images/emoji/1f51e.png differ
diff --git a/images/emoji/1f51f.png b/images/emoji/1f51f.png
new file mode 100644
index 000000000..782d40049
Binary files /dev/null and b/images/emoji/1f51f.png differ
diff --git a/images/emoji/1f520.png b/images/emoji/1f520.png
new file mode 100644
index 000000000..fe9482d2d
Binary files /dev/null and b/images/emoji/1f520.png differ
diff --git a/images/emoji/1f521.png b/images/emoji/1f521.png
new file mode 100644
index 000000000..0996a8705
Binary files /dev/null and b/images/emoji/1f521.png differ
diff --git a/images/emoji/1f522.png b/images/emoji/1f522.png
new file mode 100644
index 000000000..248dc7e55
Binary files /dev/null and b/images/emoji/1f522.png differ
diff --git a/images/emoji/1f523.png b/images/emoji/1f523.png
new file mode 100644
index 000000000..ac2fc1f35
Binary files /dev/null and b/images/emoji/1f523.png differ
diff --git a/images/emoji/1f524.png b/images/emoji/1f524.png
new file mode 100644
index 000000000..7688de692
Binary files /dev/null and b/images/emoji/1f524.png differ
diff --git a/images/emoji/1f525.png b/images/emoji/1f525.png
new file mode 100644
index 000000000..bd3775a46
Binary files /dev/null and b/images/emoji/1f525.png differ
diff --git a/images/emoji/1f526.png b/images/emoji/1f526.png
new file mode 100644
index 000000000..eee36c250
Binary files /dev/null and b/images/emoji/1f526.png differ
diff --git a/images/emoji/1f527.png b/images/emoji/1f527.png
new file mode 100644
index 000000000..c16b74396
Binary files /dev/null and b/images/emoji/1f527.png differ
diff --git a/images/emoji/1f528.png b/images/emoji/1f528.png
new file mode 100644
index 000000000..00736cce4
Binary files /dev/null and b/images/emoji/1f528.png differ
diff --git a/images/emoji/1f529.png b/images/emoji/1f529.png
new file mode 100644
index 000000000..4b9ae1553
Binary files /dev/null and b/images/emoji/1f529.png differ
diff --git a/images/emoji/1f52a.png b/images/emoji/1f52a.png
new file mode 100644
index 000000000..1acb9f307
Binary files /dev/null and b/images/emoji/1f52a.png differ
diff --git a/images/emoji/1f52b.png b/images/emoji/1f52b.png
new file mode 100644
index 000000000..89c5c244c
Binary files /dev/null and b/images/emoji/1f52b.png differ
diff --git a/images/emoji/1f52c.png b/images/emoji/1f52c.png
new file mode 100644
index 000000000..90f5acf6a
Binary files /dev/null and b/images/emoji/1f52c.png differ
diff --git a/images/emoji/1f52d.png b/images/emoji/1f52d.png
new file mode 100644
index 000000000..d63154614
Binary files /dev/null and b/images/emoji/1f52d.png differ
diff --git a/images/emoji/1f52e.png b/images/emoji/1f52e.png
new file mode 100644
index 000000000..54334c18b
Binary files /dev/null and b/images/emoji/1f52e.png differ
diff --git a/images/emoji/1f52f.png b/images/emoji/1f52f.png
new file mode 100644
index 000000000..2eb170745
Binary files /dev/null and b/images/emoji/1f52f.png differ
diff --git a/images/emoji/1f530.png b/images/emoji/1f530.png
new file mode 100644
index 000000000..bc434fb7c
Binary files /dev/null and b/images/emoji/1f530.png differ
diff --git a/images/emoji/1f531.png b/images/emoji/1f531.png
new file mode 100644
index 000000000..777a1dad1
Binary files /dev/null and b/images/emoji/1f531.png differ
diff --git a/images/emoji/1f532.png b/images/emoji/1f532.png
new file mode 100644
index 000000000..a78fc2f6b
Binary files /dev/null and b/images/emoji/1f532.png differ
diff --git a/images/emoji/1f533.png b/images/emoji/1f533.png
new file mode 100644
index 000000000..934b1cedf
Binary files /dev/null and b/images/emoji/1f533.png differ
diff --git a/images/emoji/1f534.png b/images/emoji/1f534.png
new file mode 100644
index 000000000..4bef930d9
Binary files /dev/null and b/images/emoji/1f534.png differ
diff --git a/images/emoji/1f535.png b/images/emoji/1f535.png
new file mode 100644
index 000000000..84078ef31
Binary files /dev/null and b/images/emoji/1f535.png differ
diff --git a/images/emoji/1f536.png b/images/emoji/1f536.png
new file mode 100644
index 000000000..73ff0ac36
Binary files /dev/null and b/images/emoji/1f536.png differ
diff --git a/images/emoji/1f537.png b/images/emoji/1f537.png
new file mode 100644
index 000000000..416a58bd5
Binary files /dev/null and b/images/emoji/1f537.png differ
diff --git a/images/emoji/1f538.png b/images/emoji/1f538.png
new file mode 100644
index 000000000..e1c6ed9b2
Binary files /dev/null and b/images/emoji/1f538.png differ
diff --git a/images/emoji/1f539.png b/images/emoji/1f539.png
new file mode 100644
index 000000000..b86b5bc4d
Binary files /dev/null and b/images/emoji/1f539.png differ
diff --git a/images/emoji/1f53a.png b/images/emoji/1f53a.png
new file mode 100644
index 000000000..785887c19
Binary files /dev/null and b/images/emoji/1f53a.png differ
diff --git a/images/emoji/1f53b.png b/images/emoji/1f53b.png
new file mode 100644
index 000000000..a83beff19
Binary files /dev/null and b/images/emoji/1f53b.png differ
diff --git a/images/emoji/1f53c.png b/images/emoji/1f53c.png
new file mode 100644
index 000000000..20a13dcd5
Binary files /dev/null and b/images/emoji/1f53c.png differ
diff --git a/images/emoji/1f53d.png b/images/emoji/1f53d.png
new file mode 100644
index 000000000..5870b9a22
Binary files /dev/null and b/images/emoji/1f53d.png differ
diff --git a/images/emoji/1f549.png b/images/emoji/1f549.png
new file mode 100644
index 000000000..a35c63c45
Binary files /dev/null and b/images/emoji/1f549.png differ
diff --git a/images/emoji/1f54a.png b/images/emoji/1f54a.png
new file mode 100644
index 000000000..9580c4917
Binary files /dev/null and b/images/emoji/1f54a.png differ
diff --git a/images/emoji/1f54b.png b/images/emoji/1f54b.png
new file mode 100644
index 000000000..1778c1138
Binary files /dev/null and b/images/emoji/1f54b.png differ
diff --git a/images/emoji/1f54c.png b/images/emoji/1f54c.png
new file mode 100644
index 000000000..ef770b26d
Binary files /dev/null and b/images/emoji/1f54c.png differ
diff --git a/images/emoji/1f54d.png b/images/emoji/1f54d.png
new file mode 100644
index 000000000..ee347904c
Binary files /dev/null and b/images/emoji/1f54d.png differ
diff --git a/images/emoji/1f54e.png b/images/emoji/1f54e.png
new file mode 100644
index 000000000..b42973628
Binary files /dev/null and b/images/emoji/1f54e.png differ
diff --git a/images/emoji/1f550.png b/images/emoji/1f550.png
new file mode 100644
index 000000000..d6e34941f
Binary files /dev/null and b/images/emoji/1f550.png differ
diff --git a/images/emoji/1f551.png b/images/emoji/1f551.png
new file mode 100644
index 000000000..a54253d7d
Binary files /dev/null and b/images/emoji/1f551.png differ
diff --git a/images/emoji/1f552.png b/images/emoji/1f552.png
new file mode 100644
index 000000000..27ec4b1f5
Binary files /dev/null and b/images/emoji/1f552.png differ
diff --git a/images/emoji/1f553.png b/images/emoji/1f553.png
new file mode 100644
index 000000000..60a1ef4cc
Binary files /dev/null and b/images/emoji/1f553.png differ
diff --git a/images/emoji/1f554.png b/images/emoji/1f554.png
new file mode 100644
index 000000000..c9382d1e0
Binary files /dev/null and b/images/emoji/1f554.png differ
diff --git a/images/emoji/1f555.png b/images/emoji/1f555.png
new file mode 100644
index 000000000..8fd5d3f5b
Binary files /dev/null and b/images/emoji/1f555.png differ
diff --git a/images/emoji/1f556.png b/images/emoji/1f556.png
new file mode 100644
index 000000000..8c7084036
Binary files /dev/null and b/images/emoji/1f556.png differ
diff --git a/images/emoji/1f557.png b/images/emoji/1f557.png
new file mode 100644
index 000000000..fcddf722e
Binary files /dev/null and b/images/emoji/1f557.png differ
diff --git a/images/emoji/1f558.png b/images/emoji/1f558.png
new file mode 100644
index 000000000..dfbe01179
Binary files /dev/null and b/images/emoji/1f558.png differ
diff --git a/images/emoji/1f559.png b/images/emoji/1f559.png
new file mode 100644
index 000000000..e62b245cd
Binary files /dev/null and b/images/emoji/1f559.png differ
diff --git a/images/emoji/1f55a.png b/images/emoji/1f55a.png
new file mode 100644
index 000000000..098334527
Binary files /dev/null and b/images/emoji/1f55a.png differ
diff --git a/images/emoji/1f55b.png b/images/emoji/1f55b.png
new file mode 100644
index 000000000..e61caa4b3
Binary files /dev/null and b/images/emoji/1f55b.png differ
diff --git a/images/emoji/1f55c.png b/images/emoji/1f55c.png
new file mode 100644
index 000000000..86b7689b8
Binary files /dev/null and b/images/emoji/1f55c.png differ
diff --git a/images/emoji/1f55d.png b/images/emoji/1f55d.png
new file mode 100644
index 000000000..7a787e018
Binary files /dev/null and b/images/emoji/1f55d.png differ
diff --git a/images/emoji/1f55e.png b/images/emoji/1f55e.png
new file mode 100644
index 000000000..c6860395c
Binary files /dev/null and b/images/emoji/1f55e.png differ
diff --git a/images/emoji/1f55f.png b/images/emoji/1f55f.png
new file mode 100644
index 000000000..3c05b3621
Binary files /dev/null and b/images/emoji/1f55f.png differ
diff --git a/images/emoji/1f560.png b/images/emoji/1f560.png
new file mode 100644
index 000000000..c21fa926d
Binary files /dev/null and b/images/emoji/1f560.png differ
diff --git a/images/emoji/1f561.png b/images/emoji/1f561.png
new file mode 100644
index 000000000..2aec87fef
Binary files /dev/null and b/images/emoji/1f561.png differ
diff --git a/images/emoji/1f562.png b/images/emoji/1f562.png
new file mode 100644
index 000000000..f7a1135e0
Binary files /dev/null and b/images/emoji/1f562.png differ
diff --git a/images/emoji/1f563.png b/images/emoji/1f563.png
new file mode 100644
index 000000000..799b4aebc
Binary files /dev/null and b/images/emoji/1f563.png differ
diff --git a/images/emoji/1f564.png b/images/emoji/1f564.png
new file mode 100644
index 000000000..4a2092ee6
Binary files /dev/null and b/images/emoji/1f564.png differ
diff --git a/images/emoji/1f565.png b/images/emoji/1f565.png
new file mode 100644
index 000000000..0802b3c65
Binary files /dev/null and b/images/emoji/1f565.png differ
diff --git a/images/emoji/1f566.png b/images/emoji/1f566.png
new file mode 100644
index 000000000..d970d03b8
Binary files /dev/null and b/images/emoji/1f566.png differ
diff --git a/images/emoji/1f567.png b/images/emoji/1f567.png
new file mode 100644
index 000000000..f2b1d2617
Binary files /dev/null and b/images/emoji/1f567.png differ
diff --git a/images/emoji/1f56f.png b/images/emoji/1f56f.png
new file mode 100644
index 000000000..0b56444e3
Binary files /dev/null and b/images/emoji/1f56f.png differ
diff --git a/images/emoji/1f570.png b/images/emoji/1f570.png
new file mode 100644
index 000000000..ffdb451e3
Binary files /dev/null and b/images/emoji/1f570.png differ
diff --git a/images/emoji/1f573.png b/images/emoji/1f573.png
new file mode 100644
index 000000000..517d2ae0d
Binary files /dev/null and b/images/emoji/1f573.png differ
diff --git a/images/emoji/1f574.png b/images/emoji/1f574.png
new file mode 100644
index 000000000..3dc315a3d
Binary files /dev/null and b/images/emoji/1f574.png differ
diff --git a/images/emoji/1f575-1f3fb.png b/images/emoji/1f575-1f3fb.png
new file mode 100644
index 000000000..2d1c022ca
Binary files /dev/null and b/images/emoji/1f575-1f3fb.png differ
diff --git a/images/emoji/1f575-1f3fc.png b/images/emoji/1f575-1f3fc.png
new file mode 100644
index 000000000..13e01ad93
Binary files /dev/null and b/images/emoji/1f575-1f3fc.png differ
diff --git a/images/emoji/1f575-1f3fd.png b/images/emoji/1f575-1f3fd.png
new file mode 100644
index 000000000..a814dca2e
Binary files /dev/null and b/images/emoji/1f575-1f3fd.png differ
diff --git a/images/emoji/1f575-1f3fe.png b/images/emoji/1f575-1f3fe.png
new file mode 100644
index 000000000..d8300af49
Binary files /dev/null and b/images/emoji/1f575-1f3fe.png differ
diff --git a/images/emoji/1f575-1f3ff.png b/images/emoji/1f575-1f3ff.png
new file mode 100644
index 000000000..ca1462595
Binary files /dev/null and b/images/emoji/1f575-1f3ff.png differ
diff --git a/images/emoji/1f575.png b/images/emoji/1f575.png
new file mode 100644
index 000000000..a729e9584
Binary files /dev/null and b/images/emoji/1f575.png differ
diff --git a/images/emoji/1f576.png b/images/emoji/1f576.png
new file mode 100644
index 000000000..b1b6db0ac
Binary files /dev/null and b/images/emoji/1f576.png differ
diff --git a/images/emoji/1f577.png b/images/emoji/1f577.png
new file mode 100644
index 000000000..3849fa90b
Binary files /dev/null and b/images/emoji/1f577.png differ
diff --git a/images/emoji/1f578.png b/images/emoji/1f578.png
new file mode 100644
index 000000000..ba448ee7f
Binary files /dev/null and b/images/emoji/1f578.png differ
diff --git a/images/emoji/1f579.png b/images/emoji/1f579.png
new file mode 100644
index 000000000..1ee190543
Binary files /dev/null and b/images/emoji/1f579.png differ
diff --git a/images/emoji/1f57a-1f3fb.png b/images/emoji/1f57a-1f3fb.png
new file mode 100644
index 000000000..e0b9f82d9
Binary files /dev/null and b/images/emoji/1f57a-1f3fb.png differ
diff --git a/images/emoji/1f57a-1f3fc.png b/images/emoji/1f57a-1f3fc.png
new file mode 100644
index 000000000..a5beed56e
Binary files /dev/null and b/images/emoji/1f57a-1f3fc.png differ
diff --git a/images/emoji/1f57a-1f3fd.png b/images/emoji/1f57a-1f3fd.png
new file mode 100644
index 000000000..2fa20180a
Binary files /dev/null and b/images/emoji/1f57a-1f3fd.png differ
diff --git a/images/emoji/1f57a-1f3fe.png b/images/emoji/1f57a-1f3fe.png
new file mode 100644
index 000000000..bd3528c83
Binary files /dev/null and b/images/emoji/1f57a-1f3fe.png differ
diff --git a/images/emoji/1f57a-1f3ff.png b/images/emoji/1f57a-1f3ff.png
new file mode 100644
index 000000000..41fd4f880
Binary files /dev/null and b/images/emoji/1f57a-1f3ff.png differ
diff --git a/images/emoji/1f57a.png b/images/emoji/1f57a.png
new file mode 100644
index 000000000..ccff3bede
Binary files /dev/null and b/images/emoji/1f57a.png differ
diff --git a/images/emoji/1f587.png b/images/emoji/1f587.png
new file mode 100644
index 000000000..76021e8c7
Binary files /dev/null and b/images/emoji/1f587.png differ
diff --git a/images/emoji/1f58a.png b/images/emoji/1f58a.png
new file mode 100644
index 000000000..6ef7a3424
Binary files /dev/null and b/images/emoji/1f58a.png differ
diff --git a/images/emoji/1f58b.png b/images/emoji/1f58b.png
new file mode 100644
index 000000000..3ca4bd2c2
Binary files /dev/null and b/images/emoji/1f58b.png differ
diff --git a/images/emoji/1f58c.png b/images/emoji/1f58c.png
new file mode 100644
index 000000000..28bffbaa3
Binary files /dev/null and b/images/emoji/1f58c.png differ
diff --git a/images/emoji/1f58d.png b/images/emoji/1f58d.png
new file mode 100644
index 000000000..8d7b427aa
Binary files /dev/null and b/images/emoji/1f58d.png differ
diff --git a/images/emoji/1f590-1f3fb.png b/images/emoji/1f590-1f3fb.png
new file mode 100644
index 000000000..a7888e6bd
Binary files /dev/null and b/images/emoji/1f590-1f3fb.png differ
diff --git a/images/emoji/1f590-1f3fc.png b/images/emoji/1f590-1f3fc.png
new file mode 100644
index 000000000..cc10fbc27
Binary files /dev/null and b/images/emoji/1f590-1f3fc.png differ
diff --git a/images/emoji/1f590-1f3fd.png b/images/emoji/1f590-1f3fd.png
new file mode 100644
index 000000000..707236ae8
Binary files /dev/null and b/images/emoji/1f590-1f3fd.png differ
diff --git a/images/emoji/1f590-1f3fe.png b/images/emoji/1f590-1f3fe.png
new file mode 100644
index 000000000..1430df9c6
Binary files /dev/null and b/images/emoji/1f590-1f3fe.png differ
diff --git a/images/emoji/1f590-1f3ff.png b/images/emoji/1f590-1f3ff.png
new file mode 100644
index 000000000..80bec971b
Binary files /dev/null and b/images/emoji/1f590-1f3ff.png differ
diff --git a/images/emoji/1f590.png b/images/emoji/1f590.png
new file mode 100644
index 000000000..fb5ae8ebb
Binary files /dev/null and b/images/emoji/1f590.png differ
diff --git a/images/emoji/1f595-1f3fb.png b/images/emoji/1f595-1f3fb.png
new file mode 100644
index 000000000..61ef12a15
Binary files /dev/null and b/images/emoji/1f595-1f3fb.png differ
diff --git a/images/emoji/1f595-1f3fc.png b/images/emoji/1f595-1f3fc.png
new file mode 100644
index 000000000..c31a69be9
Binary files /dev/null and b/images/emoji/1f595-1f3fc.png differ
diff --git a/images/emoji/1f595-1f3fd.png b/images/emoji/1f595-1f3fd.png
new file mode 100644
index 000000000..73ac216ce
Binary files /dev/null and b/images/emoji/1f595-1f3fd.png differ
diff --git a/images/emoji/1f595-1f3fe.png b/images/emoji/1f595-1f3fe.png
new file mode 100644
index 000000000..80b8ab770
Binary files /dev/null and b/images/emoji/1f595-1f3fe.png differ
diff --git a/images/emoji/1f595-1f3ff.png b/images/emoji/1f595-1f3ff.png
new file mode 100644
index 000000000..a8826b196
Binary files /dev/null and b/images/emoji/1f595-1f3ff.png differ
diff --git a/images/emoji/1f595.png b/images/emoji/1f595.png
new file mode 100644
index 000000000..697f7a25e
Binary files /dev/null and b/images/emoji/1f595.png differ
diff --git a/images/emoji/1f596-1f3fb.png b/images/emoji/1f596-1f3fb.png
new file mode 100644
index 000000000..8aff5d8fa
Binary files /dev/null and b/images/emoji/1f596-1f3fb.png differ
diff --git a/images/emoji/1f596-1f3fc.png b/images/emoji/1f596-1f3fc.png
new file mode 100644
index 000000000..82b7ad519
Binary files /dev/null and b/images/emoji/1f596-1f3fc.png differ
diff --git a/images/emoji/1f596-1f3fd.png b/images/emoji/1f596-1f3fd.png
new file mode 100644
index 000000000..d1400e1dd
Binary files /dev/null and b/images/emoji/1f596-1f3fd.png differ
diff --git a/images/emoji/1f596-1f3fe.png b/images/emoji/1f596-1f3fe.png
new file mode 100644
index 000000000..47e2b2801
Binary files /dev/null and b/images/emoji/1f596-1f3fe.png differ
diff --git a/images/emoji/1f596-1f3ff.png b/images/emoji/1f596-1f3ff.png
new file mode 100644
index 000000000..60b5c6077
Binary files /dev/null and b/images/emoji/1f596-1f3ff.png differ
diff --git a/images/emoji/1f596.png b/images/emoji/1f596.png
new file mode 100644
index 000000000..54728bcaf
Binary files /dev/null and b/images/emoji/1f596.png differ
diff --git a/images/emoji/1f5a4.png b/images/emoji/1f5a4.png
new file mode 100644
index 000000000..b4068c3e6
Binary files /dev/null and b/images/emoji/1f5a4.png differ
diff --git a/images/emoji/1f5a5.png b/images/emoji/1f5a5.png
new file mode 100644
index 000000000..909bd42b5
Binary files /dev/null and b/images/emoji/1f5a5.png differ
diff --git a/images/emoji/1f5a8.png b/images/emoji/1f5a8.png
new file mode 100644
index 000000000..027c830f0
Binary files /dev/null and b/images/emoji/1f5a8.png differ
diff --git a/images/emoji/1f5b1.png b/images/emoji/1f5b1.png
new file mode 100644
index 000000000..e84e96ff6
Binary files /dev/null and b/images/emoji/1f5b1.png differ
diff --git a/images/emoji/1f5b2.png b/images/emoji/1f5b2.png
new file mode 100644
index 000000000..3bea84ad7
Binary files /dev/null and b/images/emoji/1f5b2.png differ
diff --git a/images/emoji/1f5bc.png b/images/emoji/1f5bc.png
new file mode 100644
index 000000000..9fe84607b
Binary files /dev/null and b/images/emoji/1f5bc.png differ
diff --git a/images/emoji/1f5c2.png b/images/emoji/1f5c2.png
new file mode 100644
index 000000000..46a7e403f
Binary files /dev/null and b/images/emoji/1f5c2.png differ
diff --git a/images/emoji/1f5c3.png b/images/emoji/1f5c3.png
new file mode 100644
index 000000000..f2e764ce5
Binary files /dev/null and b/images/emoji/1f5c3.png differ
diff --git a/images/emoji/1f5c4.png b/images/emoji/1f5c4.png
new file mode 100644
index 000000000..fddc65dde
Binary files /dev/null and b/images/emoji/1f5c4.png differ
diff --git a/images/emoji/1f5d1.png b/images/emoji/1f5d1.png
new file mode 100644
index 000000000..2b3c484b4
Binary files /dev/null and b/images/emoji/1f5d1.png differ
diff --git a/images/emoji/1f5d2.png b/images/emoji/1f5d2.png
new file mode 100644
index 000000000..85faa10d8
Binary files /dev/null and b/images/emoji/1f5d2.png differ
diff --git a/images/emoji/1f5d3.png b/images/emoji/1f5d3.png
new file mode 100644
index 000000000..dec8d49bf
Binary files /dev/null and b/images/emoji/1f5d3.png differ
diff --git a/images/emoji/1f5dc.png b/images/emoji/1f5dc.png
new file mode 100644
index 000000000..67c13258d
Binary files /dev/null and b/images/emoji/1f5dc.png differ
diff --git a/images/emoji/1f5dd.png b/images/emoji/1f5dd.png
new file mode 100644
index 000000000..e11d706c6
Binary files /dev/null and b/images/emoji/1f5dd.png differ
diff --git a/images/emoji/1f5de.png b/images/emoji/1f5de.png
new file mode 100644
index 000000000..f64748df2
Binary files /dev/null and b/images/emoji/1f5de.png differ
diff --git a/images/emoji/1f5e1.png b/images/emoji/1f5e1.png
new file mode 100644
index 000000000..66e97b0aa
Binary files /dev/null and b/images/emoji/1f5e1.png differ
diff --git a/images/emoji/1f5e3.png b/images/emoji/1f5e3.png
new file mode 100644
index 000000000..2df93aaae
Binary files /dev/null and b/images/emoji/1f5e3.png differ
diff --git a/images/emoji/1f5e8.png b/images/emoji/1f5e8.png
new file mode 100644
index 000000000..00c05959b
Binary files /dev/null and b/images/emoji/1f5e8.png differ
diff --git a/images/emoji/1f5ef.png b/images/emoji/1f5ef.png
new file mode 100644
index 000000000..f5c97c4d2
Binary files /dev/null and b/images/emoji/1f5ef.png differ
diff --git a/images/emoji/1f5f3.png b/images/emoji/1f5f3.png
new file mode 100644
index 000000000..9b6767aea
Binary files /dev/null and b/images/emoji/1f5f3.png differ
diff --git a/images/emoji/1f5fa.png b/images/emoji/1f5fa.png
new file mode 100644
index 000000000..15efe32c7
Binary files /dev/null and b/images/emoji/1f5fa.png differ
diff --git a/images/emoji/1f5fb.png b/images/emoji/1f5fb.png
new file mode 100644
index 000000000..88a547524
Binary files /dev/null and b/images/emoji/1f5fb.png differ
diff --git a/images/emoji/1f5fc.png b/images/emoji/1f5fc.png
new file mode 100644
index 000000000..37df7fc65
Binary files /dev/null and b/images/emoji/1f5fc.png differ
diff --git a/images/emoji/1f5fd.png b/images/emoji/1f5fd.png
new file mode 100644
index 000000000..05df8289b
Binary files /dev/null and b/images/emoji/1f5fd.png differ
diff --git a/images/emoji/1f5fe.png b/images/emoji/1f5fe.png
new file mode 100644
index 000000000..d86d0a59e
Binary files /dev/null and b/images/emoji/1f5fe.png differ
diff --git a/images/emoji/1f5ff.png b/images/emoji/1f5ff.png
new file mode 100644
index 000000000..e6a7779c4
Binary files /dev/null and b/images/emoji/1f5ff.png differ
diff --git a/images/emoji/1f600.png b/images/emoji/1f600.png
new file mode 100644
index 000000000..3e8e0dab7
Binary files /dev/null and b/images/emoji/1f600.png differ
diff --git a/images/emoji/1f601.png b/images/emoji/1f601.png
new file mode 100644
index 000000000..418d94c81
Binary files /dev/null and b/images/emoji/1f601.png differ
diff --git a/images/emoji/1f602.png b/images/emoji/1f602.png
new file mode 100644
index 000000000..0ba3b1859
Binary files /dev/null and b/images/emoji/1f602.png differ
diff --git a/images/emoji/1f603.png b/images/emoji/1f603.png
new file mode 100644
index 000000000..30957a659
Binary files /dev/null and b/images/emoji/1f603.png differ
diff --git a/images/emoji/1f604.png b/images/emoji/1f604.png
new file mode 100644
index 000000000..aa47ffe97
Binary files /dev/null and b/images/emoji/1f604.png differ
diff --git a/images/emoji/1f605.png b/images/emoji/1f605.png
new file mode 100644
index 000000000..cb18d9c89
Binary files /dev/null and b/images/emoji/1f605.png differ
diff --git a/images/emoji/1f606.png b/images/emoji/1f606.png
new file mode 100644
index 000000000..d94e9505b
Binary files /dev/null and b/images/emoji/1f606.png differ
diff --git a/images/emoji/1f607.png b/images/emoji/1f607.png
new file mode 100644
index 000000000..57f515112
Binary files /dev/null and b/images/emoji/1f607.png differ
diff --git a/images/emoji/1f608.png b/images/emoji/1f608.png
new file mode 100644
index 000000000..cc2c5f1ec
Binary files /dev/null and b/images/emoji/1f608.png differ
diff --git a/images/emoji/1f609.png b/images/emoji/1f609.png
new file mode 100644
index 000000000..7ea7810a3
Binary files /dev/null and b/images/emoji/1f609.png differ
diff --git a/images/emoji/1f60a.png b/images/emoji/1f60a.png
new file mode 100644
index 000000000..aac1a424a
Binary files /dev/null and b/images/emoji/1f60a.png differ
diff --git a/images/emoji/1f60b.png b/images/emoji/1f60b.png
new file mode 100644
index 000000000..2df15753c
Binary files /dev/null and b/images/emoji/1f60b.png differ
diff --git a/images/emoji/1f60c.png b/images/emoji/1f60c.png
new file mode 100644
index 000000000..715ad0bf5
Binary files /dev/null and b/images/emoji/1f60c.png differ
diff --git a/images/emoji/1f60d.png b/images/emoji/1f60d.png
new file mode 100644
index 000000000..73fbee29d
Binary files /dev/null and b/images/emoji/1f60d.png differ
diff --git a/images/emoji/1f60e.png b/images/emoji/1f60e.png
new file mode 100644
index 000000000..200117351
Binary files /dev/null and b/images/emoji/1f60e.png differ
diff --git a/images/emoji/1f60f.png b/images/emoji/1f60f.png
new file mode 100644
index 000000000..878521099
Binary files /dev/null and b/images/emoji/1f60f.png differ
diff --git a/images/emoji/1f610.png b/images/emoji/1f610.png
new file mode 100644
index 000000000..065d193af
Binary files /dev/null and b/images/emoji/1f610.png differ
diff --git a/images/emoji/1f611.png b/images/emoji/1f611.png
new file mode 100644
index 000000000..2954017f6
Binary files /dev/null and b/images/emoji/1f611.png differ
diff --git a/images/emoji/1f612.png b/images/emoji/1f612.png
new file mode 100644
index 000000000..25e3677f2
Binary files /dev/null and b/images/emoji/1f612.png differ
diff --git a/images/emoji/1f613.png b/images/emoji/1f613.png
new file mode 100644
index 000000000..f0dae7b78
Binary files /dev/null and b/images/emoji/1f613.png differ
diff --git a/images/emoji/1f614.png b/images/emoji/1f614.png
new file mode 100644
index 000000000..490fb5669
Binary files /dev/null and b/images/emoji/1f614.png differ
diff --git a/images/emoji/1f615.png b/images/emoji/1f615.png
new file mode 100644
index 000000000..502b6bf0e
Binary files /dev/null and b/images/emoji/1f615.png differ
diff --git a/images/emoji/1f616.png b/images/emoji/1f616.png
new file mode 100644
index 000000000..aa4b29e93
Binary files /dev/null and b/images/emoji/1f616.png differ
diff --git a/images/emoji/1f617.png b/images/emoji/1f617.png
new file mode 100644
index 000000000..39d325fd8
Binary files /dev/null and b/images/emoji/1f617.png differ
diff --git a/images/emoji/1f618.png b/images/emoji/1f618.png
new file mode 100644
index 000000000..0ff808fd6
Binary files /dev/null and b/images/emoji/1f618.png differ
diff --git a/images/emoji/1f619.png b/images/emoji/1f619.png
new file mode 100644
index 000000000..e181f1709
Binary files /dev/null and b/images/emoji/1f619.png differ
diff --git a/images/emoji/1f61a.png b/images/emoji/1f61a.png
new file mode 100644
index 000000000..b684d7d4d
Binary files /dev/null and b/images/emoji/1f61a.png differ
diff --git a/images/emoji/1f61b.png b/images/emoji/1f61b.png
new file mode 100644
index 000000000..25757341f
Binary files /dev/null and b/images/emoji/1f61b.png differ
diff --git a/images/emoji/1f61c.png b/images/emoji/1f61c.png
new file mode 100644
index 000000000..4817eaa3d
Binary files /dev/null and b/images/emoji/1f61c.png differ
diff --git a/images/emoji/1f61d.png b/images/emoji/1f61d.png
new file mode 100644
index 000000000..5c0401e9b
Binary files /dev/null and b/images/emoji/1f61d.png differ
diff --git a/images/emoji/1f61e.png b/images/emoji/1f61e.png
new file mode 100644
index 000000000..efe4e67e2
Binary files /dev/null and b/images/emoji/1f61e.png differ
diff --git a/images/emoji/1f61f.png b/images/emoji/1f61f.png
new file mode 100644
index 000000000..7074afcf5
Binary files /dev/null and b/images/emoji/1f61f.png differ
diff --git a/images/emoji/1f620.png b/images/emoji/1f620.png
new file mode 100644
index 000000000..cfc4a6ecd
Binary files /dev/null and b/images/emoji/1f620.png differ
diff --git a/images/emoji/1f621.png b/images/emoji/1f621.png
new file mode 100644
index 000000000..9d739bd40
Binary files /dev/null and b/images/emoji/1f621.png differ
diff --git a/images/emoji/1f622.png b/images/emoji/1f622.png
new file mode 100644
index 000000000..b7877f8a1
Binary files /dev/null and b/images/emoji/1f622.png differ
diff --git a/images/emoji/1f623.png b/images/emoji/1f623.png
new file mode 100644
index 000000000..646a05fe9
Binary files /dev/null and b/images/emoji/1f623.png differ
diff --git a/images/emoji/1f624.png b/images/emoji/1f624.png
new file mode 100644
index 000000000..4f3312854
Binary files /dev/null and b/images/emoji/1f624.png differ
diff --git a/images/emoji/1f625.png b/images/emoji/1f625.png
new file mode 100644
index 000000000..aef864d2b
Binary files /dev/null and b/images/emoji/1f625.png differ
diff --git a/images/emoji/1f626.png b/images/emoji/1f626.png
new file mode 100644
index 000000000..43ab6b0a1
Binary files /dev/null and b/images/emoji/1f626.png differ
diff --git a/images/emoji/1f627.png b/images/emoji/1f627.png
new file mode 100644
index 000000000..f99026a3b
Binary files /dev/null and b/images/emoji/1f627.png differ
diff --git a/images/emoji/1f628.png b/images/emoji/1f628.png
new file mode 100644
index 000000000..eb8b347ce
Binary files /dev/null and b/images/emoji/1f628.png differ
diff --git a/images/emoji/1f629.png b/images/emoji/1f629.png
new file mode 100644
index 000000000..98bfbd24a
Binary files /dev/null and b/images/emoji/1f629.png differ
diff --git a/images/emoji/1f62a.png b/images/emoji/1f62a.png
new file mode 100644
index 000000000..836b41077
Binary files /dev/null and b/images/emoji/1f62a.png differ
diff --git a/images/emoji/1f62b.png b/images/emoji/1f62b.png
new file mode 100644
index 000000000..19aba1bc1
Binary files /dev/null and b/images/emoji/1f62b.png differ
diff --git a/images/emoji/1f62c.png b/images/emoji/1f62c.png
new file mode 100644
index 000000000..871b2f071
Binary files /dev/null and b/images/emoji/1f62c.png differ
diff --git a/images/emoji/1f62d.png b/images/emoji/1f62d.png
new file mode 100644
index 000000000..e4f818360
Binary files /dev/null and b/images/emoji/1f62d.png differ
diff --git a/images/emoji/1f62e.png b/images/emoji/1f62e.png
new file mode 100644
index 000000000..a62cd27e1
Binary files /dev/null and b/images/emoji/1f62e.png differ
diff --git a/images/emoji/1f62f.png b/images/emoji/1f62f.png
new file mode 100644
index 000000000..cad0e2313
Binary files /dev/null and b/images/emoji/1f62f.png differ
diff --git a/images/emoji/1f630.png b/images/emoji/1f630.png
new file mode 100644
index 000000000..85b2231bb
Binary files /dev/null and b/images/emoji/1f630.png differ
diff --git a/images/emoji/1f631.png b/images/emoji/1f631.png
new file mode 100644
index 000000000..6ab43a0d3
Binary files /dev/null and b/images/emoji/1f631.png differ
diff --git a/images/emoji/1f632.png b/images/emoji/1f632.png
new file mode 100644
index 000000000..bd0ac55ec
Binary files /dev/null and b/images/emoji/1f632.png differ
diff --git a/images/emoji/1f633.png b/images/emoji/1f633.png
new file mode 100644
index 000000000..829220bc4
Binary files /dev/null and b/images/emoji/1f633.png differ
diff --git a/images/emoji/1f634.png b/images/emoji/1f634.png
new file mode 100644
index 000000000..9ecf600d6
Binary files /dev/null and b/images/emoji/1f634.png differ
diff --git a/images/emoji/1f635.png b/images/emoji/1f635.png
new file mode 100644
index 000000000..3120316ab
Binary files /dev/null and b/images/emoji/1f635.png differ
diff --git a/images/emoji/1f636.png b/images/emoji/1f636.png
new file mode 100644
index 000000000..b642f6c11
Binary files /dev/null and b/images/emoji/1f636.png differ
diff --git a/images/emoji/1f637.png b/images/emoji/1f637.png
new file mode 100644
index 000000000..23852e578
Binary files /dev/null and b/images/emoji/1f637.png differ
diff --git a/images/emoji/1f638.png b/images/emoji/1f638.png
new file mode 100644
index 000000000..e27290a67
Binary files /dev/null and b/images/emoji/1f638.png differ
diff --git a/images/emoji/1f639.png b/images/emoji/1f639.png
new file mode 100644
index 000000000..aac353179
Binary files /dev/null and b/images/emoji/1f639.png differ
diff --git a/images/emoji/1f63a.png b/images/emoji/1f63a.png
new file mode 100644
index 000000000..d5b1cef0b
Binary files /dev/null and b/images/emoji/1f63a.png differ
diff --git a/images/emoji/1f63b.png b/images/emoji/1f63b.png
new file mode 100644
index 000000000..5a59eed04
Binary files /dev/null and b/images/emoji/1f63b.png differ
diff --git a/images/emoji/1f63c.png b/images/emoji/1f63c.png
new file mode 100644
index 000000000..0bfeae4eb
Binary files /dev/null and b/images/emoji/1f63c.png differ
diff --git a/images/emoji/1f63d.png b/images/emoji/1f63d.png
new file mode 100644
index 000000000..7f1ef2056
Binary files /dev/null and b/images/emoji/1f63d.png differ
diff --git a/images/emoji/1f63e.png b/images/emoji/1f63e.png
new file mode 100644
index 000000000..41ddfeab4
Binary files /dev/null and b/images/emoji/1f63e.png differ
diff --git a/images/emoji/1f63f.png b/images/emoji/1f63f.png
new file mode 100644
index 000000000..ccc8d4f25
Binary files /dev/null and b/images/emoji/1f63f.png differ
diff --git a/images/emoji/1f640.png b/images/emoji/1f640.png
new file mode 100644
index 000000000..15803ad8e
Binary files /dev/null and b/images/emoji/1f640.png differ
diff --git a/images/emoji/1f641.png b/images/emoji/1f641.png
new file mode 100644
index 000000000..b2f1d983d
Binary files /dev/null and b/images/emoji/1f641.png differ
diff --git a/images/emoji/1f642.png b/images/emoji/1f642.png
new file mode 100644
index 000000000..ddd7d65dd
Binary files /dev/null and b/images/emoji/1f642.png differ
diff --git a/images/emoji/1f643.png b/images/emoji/1f643.png
new file mode 100644
index 000000000..128f31c98
Binary files /dev/null and b/images/emoji/1f643.png differ
diff --git a/images/emoji/1f644.png b/images/emoji/1f644.png
new file mode 100644
index 000000000..2f77b9fc3
Binary files /dev/null and b/images/emoji/1f644.png differ
diff --git a/images/emoji/1f645-1f3fb.png b/images/emoji/1f645-1f3fb.png
new file mode 100644
index 000000000..7f28bf121
Binary files /dev/null and b/images/emoji/1f645-1f3fb.png differ
diff --git a/images/emoji/1f645-1f3fc.png b/images/emoji/1f645-1f3fc.png
new file mode 100644
index 000000000..80d8021f8
Binary files /dev/null and b/images/emoji/1f645-1f3fc.png differ
diff --git a/images/emoji/1f645-1f3fd.png b/images/emoji/1f645-1f3fd.png
new file mode 100644
index 000000000..635e6a008
Binary files /dev/null and b/images/emoji/1f645-1f3fd.png differ
diff --git a/images/emoji/1f645-1f3fe.png b/images/emoji/1f645-1f3fe.png
new file mode 100644
index 000000000..42006e7da
Binary files /dev/null and b/images/emoji/1f645-1f3fe.png differ
diff --git a/images/emoji/1f645-1f3ff.png b/images/emoji/1f645-1f3ff.png
new file mode 100644
index 000000000..309096cba
Binary files /dev/null and b/images/emoji/1f645-1f3ff.png differ
diff --git a/images/emoji/1f645.png b/images/emoji/1f645.png
new file mode 100644
index 000000000..381753cd8
Binary files /dev/null and b/images/emoji/1f645.png differ
diff --git a/images/emoji/1f646-1f3fb.png b/images/emoji/1f646-1f3fb.png
new file mode 100644
index 000000000..ac28746a5
Binary files /dev/null and b/images/emoji/1f646-1f3fb.png differ
diff --git a/images/emoji/1f646-1f3fc.png b/images/emoji/1f646-1f3fc.png
new file mode 100644
index 000000000..5d845b042
Binary files /dev/null and b/images/emoji/1f646-1f3fc.png differ
diff --git a/images/emoji/1f646-1f3fd.png b/images/emoji/1f646-1f3fd.png
new file mode 100644
index 000000000..74c7b794f
Binary files /dev/null and b/images/emoji/1f646-1f3fd.png differ
diff --git a/images/emoji/1f646-1f3fe.png b/images/emoji/1f646-1f3fe.png
new file mode 100644
index 000000000..2fbcd7f67
Binary files /dev/null and b/images/emoji/1f646-1f3fe.png differ
diff --git a/images/emoji/1f646-1f3ff.png b/images/emoji/1f646-1f3ff.png
new file mode 100644
index 000000000..da2d13546
Binary files /dev/null and b/images/emoji/1f646-1f3ff.png differ
diff --git a/images/emoji/1f646.png b/images/emoji/1f646.png
new file mode 100644
index 000000000..3de4594bd
Binary files /dev/null and b/images/emoji/1f646.png differ
diff --git a/images/emoji/1f647-1f3fb.png b/images/emoji/1f647-1f3fb.png
new file mode 100644
index 000000000..003d66052
Binary files /dev/null and b/images/emoji/1f647-1f3fb.png differ
diff --git a/images/emoji/1f647-1f3fc.png b/images/emoji/1f647-1f3fc.png
new file mode 100644
index 000000000..d774be9c9
Binary files /dev/null and b/images/emoji/1f647-1f3fc.png differ
diff --git a/images/emoji/1f647-1f3fd.png b/images/emoji/1f647-1f3fd.png
new file mode 100644
index 000000000..43e06fd86
Binary files /dev/null and b/images/emoji/1f647-1f3fd.png differ
diff --git a/images/emoji/1f647-1f3fe.png b/images/emoji/1f647-1f3fe.png
new file mode 100644
index 000000000..2d0f1a7c7
Binary files /dev/null and b/images/emoji/1f647-1f3fe.png differ
diff --git a/images/emoji/1f647-1f3ff.png b/images/emoji/1f647-1f3ff.png
new file mode 100644
index 000000000..91f1a8ace
Binary files /dev/null and b/images/emoji/1f647-1f3ff.png differ
diff --git a/images/emoji/1f647.png b/images/emoji/1f647.png
new file mode 100644
index 000000000..3a0e83ee8
Binary files /dev/null and b/images/emoji/1f647.png differ
diff --git a/images/emoji/1f648.png b/images/emoji/1f648.png
new file mode 100644
index 000000000..5187e4745
Binary files /dev/null and b/images/emoji/1f648.png differ
diff --git a/images/emoji/1f649.png b/images/emoji/1f649.png
new file mode 100644
index 000000000..74b6be0c6
Binary files /dev/null and b/images/emoji/1f649.png differ
diff --git a/images/emoji/1f64a.png b/images/emoji/1f64a.png
new file mode 100644
index 000000000..c75f42ae7
Binary files /dev/null and b/images/emoji/1f64a.png differ
diff --git a/images/emoji/1f64b-1f3fb.png b/images/emoji/1f64b-1f3fb.png
new file mode 100644
index 000000000..1c90e3e26
Binary files /dev/null and b/images/emoji/1f64b-1f3fb.png differ
diff --git a/images/emoji/1f64b-1f3fc.png b/images/emoji/1f64b-1f3fc.png
new file mode 100644
index 000000000..82c3ef2bf
Binary files /dev/null and b/images/emoji/1f64b-1f3fc.png differ
diff --git a/images/emoji/1f64b-1f3fd.png b/images/emoji/1f64b-1f3fd.png
new file mode 100644
index 000000000..92a389f72
Binary files /dev/null and b/images/emoji/1f64b-1f3fd.png differ
diff --git a/images/emoji/1f64b-1f3fe.png b/images/emoji/1f64b-1f3fe.png
new file mode 100644
index 000000000..8b95f0533
Binary files /dev/null and b/images/emoji/1f64b-1f3fe.png differ
diff --git a/images/emoji/1f64b-1f3ff.png b/images/emoji/1f64b-1f3ff.png
new file mode 100644
index 000000000..b86200fd8
Binary files /dev/null and b/images/emoji/1f64b-1f3ff.png differ
diff --git a/images/emoji/1f64b.png b/images/emoji/1f64b.png
new file mode 100644
index 000000000..7c803b315
Binary files /dev/null and b/images/emoji/1f64b.png differ
diff --git a/images/emoji/1f64c-1f3fb.png b/images/emoji/1f64c-1f3fb.png
new file mode 100644
index 000000000..1168b8236
Binary files /dev/null and b/images/emoji/1f64c-1f3fb.png differ
diff --git a/images/emoji/1f64c-1f3fc.png b/images/emoji/1f64c-1f3fc.png
new file mode 100644
index 000000000..322de6229
Binary files /dev/null and b/images/emoji/1f64c-1f3fc.png differ
diff --git a/images/emoji/1f64c-1f3fd.png b/images/emoji/1f64c-1f3fd.png
new file mode 100644
index 000000000..2aa24e05a
Binary files /dev/null and b/images/emoji/1f64c-1f3fd.png differ
diff --git a/images/emoji/1f64c-1f3fe.png b/images/emoji/1f64c-1f3fe.png
new file mode 100644
index 000000000..f31bf0db9
Binary files /dev/null and b/images/emoji/1f64c-1f3fe.png differ
diff --git a/images/emoji/1f64c-1f3ff.png b/images/emoji/1f64c-1f3ff.png
new file mode 100644
index 000000000..5e95067f9
Binary files /dev/null and b/images/emoji/1f64c-1f3ff.png differ
diff --git a/images/emoji/1f64c.png b/images/emoji/1f64c.png
new file mode 100644
index 000000000..c0155f728
Binary files /dev/null and b/images/emoji/1f64c.png differ
diff --git a/images/emoji/1f64d-1f3fb.png b/images/emoji/1f64d-1f3fb.png
new file mode 100644
index 000000000..21d3bb439
Binary files /dev/null and b/images/emoji/1f64d-1f3fb.png differ
diff --git a/images/emoji/1f64d-1f3fc.png b/images/emoji/1f64d-1f3fc.png
new file mode 100644
index 000000000..973f5fc83
Binary files /dev/null and b/images/emoji/1f64d-1f3fc.png differ
diff --git a/images/emoji/1f64d-1f3fd.png b/images/emoji/1f64d-1f3fd.png
new file mode 100644
index 000000000..41fbcc788
Binary files /dev/null and b/images/emoji/1f64d-1f3fd.png differ
diff --git a/images/emoji/1f64d-1f3fe.png b/images/emoji/1f64d-1f3fe.png
new file mode 100644
index 000000000..5a37c7410
Binary files /dev/null and b/images/emoji/1f64d-1f3fe.png differ
diff --git a/images/emoji/1f64d-1f3ff.png b/images/emoji/1f64d-1f3ff.png
new file mode 100644
index 000000000..e08141f3e
Binary files /dev/null and b/images/emoji/1f64d-1f3ff.png differ
diff --git a/images/emoji/1f64d.png b/images/emoji/1f64d.png
new file mode 100644
index 000000000..579324959
Binary files /dev/null and b/images/emoji/1f64d.png differ
diff --git a/images/emoji/1f64e-1f3fb.png b/images/emoji/1f64e-1f3fb.png
new file mode 100644
index 000000000..57e826b75
Binary files /dev/null and b/images/emoji/1f64e-1f3fb.png differ
diff --git a/images/emoji/1f64e-1f3fc.png b/images/emoji/1f64e-1f3fc.png
new file mode 100644
index 000000000..3f317c0c2
Binary files /dev/null and b/images/emoji/1f64e-1f3fc.png differ
diff --git a/images/emoji/1f64e-1f3fd.png b/images/emoji/1f64e-1f3fd.png
new file mode 100644
index 000000000..d2fbb6c20
Binary files /dev/null and b/images/emoji/1f64e-1f3fd.png differ
diff --git a/images/emoji/1f64e-1f3fe.png b/images/emoji/1f64e-1f3fe.png
new file mode 100644
index 000000000..643ceb4a5
Binary files /dev/null and b/images/emoji/1f64e-1f3fe.png differ
diff --git a/images/emoji/1f64e-1f3ff.png b/images/emoji/1f64e-1f3ff.png
new file mode 100644
index 000000000..b2eb6859c
Binary files /dev/null and b/images/emoji/1f64e-1f3ff.png differ
diff --git a/images/emoji/1f64e.png b/images/emoji/1f64e.png
new file mode 100644
index 000000000..10eb05710
Binary files /dev/null and b/images/emoji/1f64e.png differ
diff --git a/images/emoji/1f64f-1f3fb.png b/images/emoji/1f64f-1f3fb.png
new file mode 100644
index 000000000..060ef2571
Binary files /dev/null and b/images/emoji/1f64f-1f3fb.png differ
diff --git a/images/emoji/1f64f-1f3fc.png b/images/emoji/1f64f-1f3fc.png
new file mode 100644
index 000000000..56dc607c0
Binary files /dev/null and b/images/emoji/1f64f-1f3fc.png differ
diff --git a/images/emoji/1f64f-1f3fd.png b/images/emoji/1f64f-1f3fd.png
new file mode 100644
index 000000000..0f33b8620
Binary files /dev/null and b/images/emoji/1f64f-1f3fd.png differ
diff --git a/images/emoji/1f64f-1f3fe.png b/images/emoji/1f64f-1f3fe.png
new file mode 100644
index 000000000..2ea8dc116
Binary files /dev/null and b/images/emoji/1f64f-1f3fe.png differ
diff --git a/images/emoji/1f64f-1f3ff.png b/images/emoji/1f64f-1f3ff.png
new file mode 100644
index 000000000..2128a6c47
Binary files /dev/null and b/images/emoji/1f64f-1f3ff.png differ
diff --git a/images/emoji/1f64f.png b/images/emoji/1f64f.png
new file mode 100644
index 000000000..8347f2435
Binary files /dev/null and b/images/emoji/1f64f.png differ
diff --git a/images/emoji/1f680.png b/images/emoji/1f680.png
new file mode 100644
index 000000000..0d8da089a
Binary files /dev/null and b/images/emoji/1f680.png differ
diff --git a/images/emoji/1f681.png b/images/emoji/1f681.png
new file mode 100644
index 000000000..7ec5f39a5
Binary files /dev/null and b/images/emoji/1f681.png differ
diff --git a/images/emoji/1f682.png b/images/emoji/1f682.png
new file mode 100644
index 000000000..9ac0d999c
Binary files /dev/null and b/images/emoji/1f682.png differ
diff --git a/images/emoji/1f683.png b/images/emoji/1f683.png
new file mode 100644
index 000000000..a9acbf130
Binary files /dev/null and b/images/emoji/1f683.png differ
diff --git a/images/emoji/1f684.png b/images/emoji/1f684.png
new file mode 100644
index 000000000..ed61c67bf
Binary files /dev/null and b/images/emoji/1f684.png differ
diff --git a/images/emoji/1f685.png b/images/emoji/1f685.png
new file mode 100644
index 000000000..4f698e056
Binary files /dev/null and b/images/emoji/1f685.png differ
diff --git a/images/emoji/1f686.png b/images/emoji/1f686.png
new file mode 100644
index 000000000..8701e41e7
Binary files /dev/null and b/images/emoji/1f686.png differ
diff --git a/images/emoji/1f687.png b/images/emoji/1f687.png
new file mode 100644
index 000000000..1de8f0551
Binary files /dev/null and b/images/emoji/1f687.png differ
diff --git a/images/emoji/1f688.png b/images/emoji/1f688.png
new file mode 100644
index 000000000..a64829f50
Binary files /dev/null and b/images/emoji/1f688.png differ
diff --git a/images/emoji/1f689.png b/images/emoji/1f689.png
new file mode 100644
index 000000000..5c26fee52
Binary files /dev/null and b/images/emoji/1f689.png differ
diff --git a/images/emoji/1f68a.png b/images/emoji/1f68a.png
new file mode 100644
index 000000000..b6f0e6903
Binary files /dev/null and b/images/emoji/1f68a.png differ
diff --git a/images/emoji/1f68b.png b/images/emoji/1f68b.png
new file mode 100644
index 000000000..3c80321f7
Binary files /dev/null and b/images/emoji/1f68b.png differ
diff --git a/images/emoji/1f68c.png b/images/emoji/1f68c.png
new file mode 100644
index 000000000..641ddc56c
Binary files /dev/null and b/images/emoji/1f68c.png differ
diff --git a/images/emoji/1f68d.png b/images/emoji/1f68d.png
new file mode 100644
index 000000000..ad91e256c
Binary files /dev/null and b/images/emoji/1f68d.png differ
diff --git a/images/emoji/1f68e.png b/images/emoji/1f68e.png
new file mode 100644
index 000000000..139a9931b
Binary files /dev/null and b/images/emoji/1f68e.png differ
diff --git a/images/emoji/1f68f.png b/images/emoji/1f68f.png
new file mode 100644
index 000000000..b2b62208b
Binary files /dev/null and b/images/emoji/1f68f.png differ
diff --git a/images/emoji/1f690.png b/images/emoji/1f690.png
new file mode 100644
index 000000000..c60dd8f47
Binary files /dev/null and b/images/emoji/1f690.png differ
diff --git a/images/emoji/1f691.png b/images/emoji/1f691.png
new file mode 100644
index 000000000..6fb8076d7
Binary files /dev/null and b/images/emoji/1f691.png differ
diff --git a/images/emoji/1f692.png b/images/emoji/1f692.png
new file mode 100644
index 000000000..249ffaabd
Binary files /dev/null and b/images/emoji/1f692.png differ
diff --git a/images/emoji/1f693.png b/images/emoji/1f693.png
new file mode 100644
index 000000000..3da4253de
Binary files /dev/null and b/images/emoji/1f693.png differ
diff --git a/images/emoji/1f694.png b/images/emoji/1f694.png
new file mode 100644
index 000000000..a50388fc9
Binary files /dev/null and b/images/emoji/1f694.png differ
diff --git a/images/emoji/1f695.png b/images/emoji/1f695.png
new file mode 100644
index 000000000..55f4cc847
Binary files /dev/null and b/images/emoji/1f695.png differ
diff --git a/images/emoji/1f696.png b/images/emoji/1f696.png
new file mode 100644
index 000000000..b4a9ddde4
Binary files /dev/null and b/images/emoji/1f696.png differ
diff --git a/images/emoji/1f697.png b/images/emoji/1f697.png
new file mode 100644
index 000000000..b3e6a774d
Binary files /dev/null and b/images/emoji/1f697.png differ
diff --git a/images/emoji/1f698.png b/images/emoji/1f698.png
new file mode 100644
index 000000000..3c7e1d52e
Binary files /dev/null and b/images/emoji/1f698.png differ
diff --git a/images/emoji/1f699.png b/images/emoji/1f699.png
new file mode 100644
index 000000000..e8ba817d3
Binary files /dev/null and b/images/emoji/1f699.png differ
diff --git a/images/emoji/1f69a.png b/images/emoji/1f69a.png
new file mode 100644
index 000000000..c7677a769
Binary files /dev/null and b/images/emoji/1f69a.png differ
diff --git a/images/emoji/1f69b.png b/images/emoji/1f69b.png
new file mode 100644
index 000000000..b3b7742e6
Binary files /dev/null and b/images/emoji/1f69b.png differ
diff --git a/images/emoji/1f69c.png b/images/emoji/1f69c.png
new file mode 100644
index 000000000..c1bf8cae4
Binary files /dev/null and b/images/emoji/1f69c.png differ
diff --git a/images/emoji/1f69d.png b/images/emoji/1f69d.png
new file mode 100644
index 000000000..11eb1f574
Binary files /dev/null and b/images/emoji/1f69d.png differ
diff --git a/images/emoji/1f69e.png b/images/emoji/1f69e.png
new file mode 100644
index 000000000..d136d60aa
Binary files /dev/null and b/images/emoji/1f69e.png differ
diff --git a/images/emoji/1f69f.png b/images/emoji/1f69f.png
new file mode 100644
index 000000000..a59d5f48c
Binary files /dev/null and b/images/emoji/1f69f.png differ
diff --git a/images/emoji/1f6a0.png b/images/emoji/1f6a0.png
new file mode 100644
index 000000000..1dea73ca5
Binary files /dev/null and b/images/emoji/1f6a0.png differ
diff --git a/images/emoji/1f6a1.png b/images/emoji/1f6a1.png
new file mode 100644
index 000000000..3eb4b61bf
Binary files /dev/null and b/images/emoji/1f6a1.png differ
diff --git a/images/emoji/1f6a2.png b/images/emoji/1f6a2.png
new file mode 100644
index 000000000..62d54f7d6
Binary files /dev/null and b/images/emoji/1f6a2.png differ
diff --git a/images/emoji/1f6a3-1f3fb.png b/images/emoji/1f6a3-1f3fb.png
new file mode 100644
index 000000000..947471874
Binary files /dev/null and b/images/emoji/1f6a3-1f3fb.png differ
diff --git a/images/emoji/1f6a3-1f3fc.png b/images/emoji/1f6a3-1f3fc.png
new file mode 100644
index 000000000..9b123ef88
Binary files /dev/null and b/images/emoji/1f6a3-1f3fc.png differ
diff --git a/images/emoji/1f6a3-1f3fd.png b/images/emoji/1f6a3-1f3fd.png
new file mode 100644
index 000000000..8ebd89a55
Binary files /dev/null and b/images/emoji/1f6a3-1f3fd.png differ
diff --git a/images/emoji/1f6a3-1f3fe.png b/images/emoji/1f6a3-1f3fe.png
new file mode 100644
index 000000000..2b0d04f87
Binary files /dev/null and b/images/emoji/1f6a3-1f3fe.png differ
diff --git a/images/emoji/1f6a3-1f3ff.png b/images/emoji/1f6a3-1f3ff.png
new file mode 100644
index 000000000..b346f2dfc
Binary files /dev/null and b/images/emoji/1f6a3-1f3ff.png differ
diff --git a/images/emoji/1f6a3.png b/images/emoji/1f6a3.png
new file mode 100644
index 000000000..dd4dfc095
Binary files /dev/null and b/images/emoji/1f6a3.png differ
diff --git a/images/emoji/1f6a4.png b/images/emoji/1f6a4.png
new file mode 100644
index 000000000..74059d12d
Binary files /dev/null and b/images/emoji/1f6a4.png differ
diff --git a/images/emoji/1f6a5.png b/images/emoji/1f6a5.png
new file mode 100644
index 000000000..6b312285b
Binary files /dev/null and b/images/emoji/1f6a5.png differ
diff --git a/images/emoji/1f6a6.png b/images/emoji/1f6a6.png
new file mode 100644
index 000000000..8085973ee
Binary files /dev/null and b/images/emoji/1f6a6.png differ
diff --git a/images/emoji/1f6a7.png b/images/emoji/1f6a7.png
new file mode 100644
index 000000000..ef8db5f47
Binary files /dev/null and b/images/emoji/1f6a7.png differ
diff --git a/images/emoji/1f6a8.png b/images/emoji/1f6a8.png
new file mode 100644
index 000000000..cad66b0af
Binary files /dev/null and b/images/emoji/1f6a8.png differ
diff --git a/images/emoji/1f6a9.png b/images/emoji/1f6a9.png
new file mode 100644
index 000000000..c12d8b068
Binary files /dev/null and b/images/emoji/1f6a9.png differ
diff --git a/images/emoji/1f6aa.png b/images/emoji/1f6aa.png
new file mode 100644
index 000000000..36ae3e274
Binary files /dev/null and b/images/emoji/1f6aa.png differ
diff --git a/images/emoji/1f6ab.png b/images/emoji/1f6ab.png
new file mode 100644
index 000000000..d2efd65e7
Binary files /dev/null and b/images/emoji/1f6ab.png differ
diff --git a/images/emoji/1f6ac.png b/images/emoji/1f6ac.png
new file mode 100644
index 000000000..910f648c8
Binary files /dev/null and b/images/emoji/1f6ac.png differ
diff --git a/images/emoji/1f6ad.png b/images/emoji/1f6ad.png
new file mode 100644
index 000000000..d33b9de53
Binary files /dev/null and b/images/emoji/1f6ad.png differ
diff --git a/images/emoji/1f6ae.png b/images/emoji/1f6ae.png
new file mode 100644
index 000000000..82a84f9a3
Binary files /dev/null and b/images/emoji/1f6ae.png differ
diff --git a/images/emoji/1f6af.png b/images/emoji/1f6af.png
new file mode 100644
index 000000000..341d2575f
Binary files /dev/null and b/images/emoji/1f6af.png differ
diff --git a/images/emoji/1f6b0.png b/images/emoji/1f6b0.png
new file mode 100644
index 000000000..2c6100494
Binary files /dev/null and b/images/emoji/1f6b0.png differ
diff --git a/images/emoji/1f6b1.png b/images/emoji/1f6b1.png
new file mode 100644
index 000000000..827d4193f
Binary files /dev/null and b/images/emoji/1f6b1.png differ
diff --git a/images/emoji/1f6b2.png b/images/emoji/1f6b2.png
new file mode 100644
index 000000000..6125842f8
Binary files /dev/null and b/images/emoji/1f6b2.png differ
diff --git a/images/emoji/1f6b3.png b/images/emoji/1f6b3.png
new file mode 100644
index 000000000..19c85421c
Binary files /dev/null and b/images/emoji/1f6b3.png differ
diff --git a/images/emoji/1f6b4-1f3fb.png b/images/emoji/1f6b4-1f3fb.png
new file mode 100644
index 000000000..decc2f728
Binary files /dev/null and b/images/emoji/1f6b4-1f3fb.png differ
diff --git a/images/emoji/1f6b4-1f3fc.png b/images/emoji/1f6b4-1f3fc.png
new file mode 100644
index 000000000..0067717b8
Binary files /dev/null and b/images/emoji/1f6b4-1f3fc.png differ
diff --git a/images/emoji/1f6b4-1f3fd.png b/images/emoji/1f6b4-1f3fd.png
new file mode 100644
index 000000000..a4f7b5e27
Binary files /dev/null and b/images/emoji/1f6b4-1f3fd.png differ
diff --git a/images/emoji/1f6b4-1f3fe.png b/images/emoji/1f6b4-1f3fe.png
new file mode 100644
index 000000000..a3c8a797d
Binary files /dev/null and b/images/emoji/1f6b4-1f3fe.png differ
diff --git a/images/emoji/1f6b4-1f3ff.png b/images/emoji/1f6b4-1f3ff.png
new file mode 100644
index 000000000..1606a8740
Binary files /dev/null and b/images/emoji/1f6b4-1f3ff.png differ
diff --git a/images/emoji/1f6b4.png b/images/emoji/1f6b4.png
new file mode 100644
index 000000000..9274da110
Binary files /dev/null and b/images/emoji/1f6b4.png differ
diff --git a/images/emoji/1f6b5-1f3fb.png b/images/emoji/1f6b5-1f3fb.png
new file mode 100644
index 000000000..e9f1daf5e
Binary files /dev/null and b/images/emoji/1f6b5-1f3fb.png differ
diff --git a/images/emoji/1f6b5-1f3fc.png b/images/emoji/1f6b5-1f3fc.png
new file mode 100644
index 000000000..555b9e29d
Binary files /dev/null and b/images/emoji/1f6b5-1f3fc.png differ
diff --git a/images/emoji/1f6b5-1f3fd.png b/images/emoji/1f6b5-1f3fd.png
new file mode 100644
index 000000000..7df5508ec
Binary files /dev/null and b/images/emoji/1f6b5-1f3fd.png differ
diff --git a/images/emoji/1f6b5-1f3fe.png b/images/emoji/1f6b5-1f3fe.png
new file mode 100644
index 000000000..f94b34506
Binary files /dev/null and b/images/emoji/1f6b5-1f3fe.png differ
diff --git a/images/emoji/1f6b5-1f3ff.png b/images/emoji/1f6b5-1f3ff.png
new file mode 100644
index 000000000..16a45861e
Binary files /dev/null and b/images/emoji/1f6b5-1f3ff.png differ
diff --git a/images/emoji/1f6b5.png b/images/emoji/1f6b5.png
new file mode 100644
index 000000000..41d3dc3ac
Binary files /dev/null and b/images/emoji/1f6b5.png differ
diff --git a/images/emoji/1f6b6-1f3fb.png b/images/emoji/1f6b6-1f3fb.png
new file mode 100644
index 000000000..4e391b45a
Binary files /dev/null and b/images/emoji/1f6b6-1f3fb.png differ
diff --git a/images/emoji/1f6b6-1f3fc.png b/images/emoji/1f6b6-1f3fc.png
new file mode 100644
index 000000000..31f94a1bc
Binary files /dev/null and b/images/emoji/1f6b6-1f3fc.png differ
diff --git a/images/emoji/1f6b6-1f3fd.png b/images/emoji/1f6b6-1f3fd.png
new file mode 100644
index 000000000..f7ed8e39c
Binary files /dev/null and b/images/emoji/1f6b6-1f3fd.png differ
diff --git a/images/emoji/1f6b6-1f3fe.png b/images/emoji/1f6b6-1f3fe.png
new file mode 100644
index 000000000..e58dc04c7
Binary files /dev/null and b/images/emoji/1f6b6-1f3fe.png differ
diff --git a/images/emoji/1f6b6-1f3ff.png b/images/emoji/1f6b6-1f3ff.png
new file mode 100644
index 000000000..ba4e1b58f
Binary files /dev/null and b/images/emoji/1f6b6-1f3ff.png differ
diff --git a/images/emoji/1f6b6.png b/images/emoji/1f6b6.png
new file mode 100644
index 000000000..06dc169a3
Binary files /dev/null and b/images/emoji/1f6b6.png differ
diff --git a/images/emoji/1f6b7.png b/images/emoji/1f6b7.png
new file mode 100644
index 000000000..286aa577a
Binary files /dev/null and b/images/emoji/1f6b7.png differ
diff --git a/images/emoji/1f6b8.png b/images/emoji/1f6b8.png
new file mode 100644
index 000000000..fa4c091c7
Binary files /dev/null and b/images/emoji/1f6b8.png differ
diff --git a/images/emoji/1f6b9.png b/images/emoji/1f6b9.png
new file mode 100644
index 000000000..f5a1e1ba0
Binary files /dev/null and b/images/emoji/1f6b9.png differ
diff --git a/images/emoji/1f6ba.png b/images/emoji/1f6ba.png
new file mode 100644
index 000000000..d4ecc22e7
Binary files /dev/null and b/images/emoji/1f6ba.png differ
diff --git a/images/emoji/1f6bb.png b/images/emoji/1f6bb.png
new file mode 100644
index 000000000..9588e0f0e
Binary files /dev/null and b/images/emoji/1f6bb.png differ
diff --git a/images/emoji/1f6bc.png b/images/emoji/1f6bc.png
new file mode 100644
index 000000000..64a10b717
Binary files /dev/null and b/images/emoji/1f6bc.png differ
diff --git a/images/emoji/1f6bd.png b/images/emoji/1f6bd.png
new file mode 100644
index 000000000..1392f7618
Binary files /dev/null and b/images/emoji/1f6bd.png differ
diff --git a/images/emoji/1f6be.png b/images/emoji/1f6be.png
new file mode 100644
index 000000000..aa433e84b
Binary files /dev/null and b/images/emoji/1f6be.png differ
diff --git a/images/emoji/1f6bf.png b/images/emoji/1f6bf.png
new file mode 100644
index 000000000..156776a2e
Binary files /dev/null and b/images/emoji/1f6bf.png differ
diff --git a/images/emoji/1f6c0-1f3fb.png b/images/emoji/1f6c0-1f3fb.png
new file mode 100644
index 000000000..2152eabf2
Binary files /dev/null and b/images/emoji/1f6c0-1f3fb.png differ
diff --git a/images/emoji/1f6c0-1f3fc.png b/images/emoji/1f6c0-1f3fc.png
new file mode 100644
index 000000000..2102e6133
Binary files /dev/null and b/images/emoji/1f6c0-1f3fc.png differ
diff --git a/images/emoji/1f6c0-1f3fd.png b/images/emoji/1f6c0-1f3fd.png
new file mode 100644
index 000000000..fae66181e
Binary files /dev/null and b/images/emoji/1f6c0-1f3fd.png differ
diff --git a/images/emoji/1f6c0-1f3fe.png b/images/emoji/1f6c0-1f3fe.png
new file mode 100644
index 000000000..1f8959d0d
Binary files /dev/null and b/images/emoji/1f6c0-1f3fe.png differ
diff --git a/images/emoji/1f6c0-1f3ff.png b/images/emoji/1f6c0-1f3ff.png
new file mode 100644
index 000000000..c8a08e84f
Binary files /dev/null and b/images/emoji/1f6c0-1f3ff.png differ
diff --git a/images/emoji/1f6c0.png b/images/emoji/1f6c0.png
new file mode 100644
index 000000000..43fba5c8a
Binary files /dev/null and b/images/emoji/1f6c0.png differ
diff --git a/images/emoji/1f6c1.png b/images/emoji/1f6c1.png
new file mode 100644
index 000000000..9a5f09361
Binary files /dev/null and b/images/emoji/1f6c1.png differ
diff --git a/images/emoji/1f6c2.png b/images/emoji/1f6c2.png
new file mode 100644
index 000000000..079e34ee4
Binary files /dev/null and b/images/emoji/1f6c2.png differ
diff --git a/images/emoji/1f6c3.png b/images/emoji/1f6c3.png
new file mode 100644
index 000000000..21b7ce2c6
Binary files /dev/null and b/images/emoji/1f6c3.png differ
diff --git a/images/emoji/1f6c4.png b/images/emoji/1f6c4.png
new file mode 100644
index 000000000..409b593e7
Binary files /dev/null and b/images/emoji/1f6c4.png differ
diff --git a/images/emoji/1f6c5.png b/images/emoji/1f6c5.png
new file mode 100644
index 000000000..887b23f3f
Binary files /dev/null and b/images/emoji/1f6c5.png differ
diff --git a/images/emoji/1f6cb.png b/images/emoji/1f6cb.png
new file mode 100644
index 000000000..27b19b13b
Binary files /dev/null and b/images/emoji/1f6cb.png differ
diff --git a/images/emoji/1f6cc.png b/images/emoji/1f6cc.png
new file mode 100644
index 000000000..c739e7fb6
Binary files /dev/null and b/images/emoji/1f6cc.png differ
diff --git a/images/emoji/1f6cd.png b/images/emoji/1f6cd.png
new file mode 100644
index 000000000..99f2a2b13
Binary files /dev/null and b/images/emoji/1f6cd.png differ
diff --git a/images/emoji/1f6ce.png b/images/emoji/1f6ce.png
new file mode 100644
index 000000000..6b3297cea
Binary files /dev/null and b/images/emoji/1f6ce.png differ
diff --git a/images/emoji/1f6cf.png b/images/emoji/1f6cf.png
new file mode 100644
index 000000000..cf75349a3
Binary files /dev/null and b/images/emoji/1f6cf.png differ
diff --git a/images/emoji/1f6d0.png b/images/emoji/1f6d0.png
new file mode 100644
index 000000000..207d59cce
Binary files /dev/null and b/images/emoji/1f6d0.png differ
diff --git a/images/emoji/1f6d1.png b/images/emoji/1f6d1.png
new file mode 100644
index 000000000..5ed610040
Binary files /dev/null and b/images/emoji/1f6d1.png differ
diff --git a/images/emoji/1f6d2.png b/images/emoji/1f6d2.png
new file mode 100644
index 000000000..1086fe6e4
Binary files /dev/null and b/images/emoji/1f6d2.png differ
diff --git a/images/emoji/1f6e0.png b/images/emoji/1f6e0.png
new file mode 100644
index 000000000..3c6049273
Binary files /dev/null and b/images/emoji/1f6e0.png differ
diff --git a/images/emoji/1f6e1.png b/images/emoji/1f6e1.png
new file mode 100644
index 000000000..610bf033c
Binary files /dev/null and b/images/emoji/1f6e1.png differ
diff --git a/images/emoji/1f6e2.png b/images/emoji/1f6e2.png
new file mode 100644
index 000000000..c4c4d42da
Binary files /dev/null and b/images/emoji/1f6e2.png differ
diff --git a/images/emoji/1f6e3.png b/images/emoji/1f6e3.png
new file mode 100644
index 000000000..8c3d3d03e
Binary files /dev/null and b/images/emoji/1f6e3.png differ
diff --git a/images/emoji/1f6e4.png b/images/emoji/1f6e4.png
new file mode 100644
index 000000000..3bde6fb65
Binary files /dev/null and b/images/emoji/1f6e4.png differ
diff --git a/images/emoji/1f6e5.png b/images/emoji/1f6e5.png
new file mode 100644
index 000000000..0506db1a4
Binary files /dev/null and b/images/emoji/1f6e5.png differ
diff --git a/images/emoji/1f6e9.png b/images/emoji/1f6e9.png
new file mode 100644
index 000000000..b731b15e3
Binary files /dev/null and b/images/emoji/1f6e9.png differ
diff --git a/images/emoji/1f6eb.png b/images/emoji/1f6eb.png
new file mode 100644
index 000000000..a5766f9f4
Binary files /dev/null and b/images/emoji/1f6eb.png differ
diff --git a/images/emoji/1f6ec.png b/images/emoji/1f6ec.png
new file mode 100644
index 000000000..d66841962
Binary files /dev/null and b/images/emoji/1f6ec.png differ
diff --git a/images/emoji/1f6f0.png b/images/emoji/1f6f0.png
new file mode 100644
index 000000000..4ba55d6e2
Binary files /dev/null and b/images/emoji/1f6f0.png differ
diff --git a/images/emoji/1f6f3.png b/images/emoji/1f6f3.png
new file mode 100644
index 000000000..19d4acbe4
Binary files /dev/null and b/images/emoji/1f6f3.png differ
diff --git a/images/emoji/1f6f4.png b/images/emoji/1f6f4.png
new file mode 100644
index 000000000..4ab7ef59c
Binary files /dev/null and b/images/emoji/1f6f4.png differ
diff --git a/images/emoji/1f6f5.png b/images/emoji/1f6f5.png
new file mode 100644
index 000000000..c5afa72d8
Binary files /dev/null and b/images/emoji/1f6f5.png differ
diff --git a/images/emoji/1f6f6.png b/images/emoji/1f6f6.png
new file mode 100644
index 000000000..e26cdb9da
Binary files /dev/null and b/images/emoji/1f6f6.png differ
diff --git a/images/emoji/1f910.png b/images/emoji/1f910.png
new file mode 100644
index 000000000..f8ced2502
Binary files /dev/null and b/images/emoji/1f910.png differ
diff --git a/images/emoji/1f911.png b/images/emoji/1f911.png
new file mode 100644
index 000000000..75fd1e90c
Binary files /dev/null and b/images/emoji/1f911.png differ
diff --git a/images/emoji/1f912.png b/images/emoji/1f912.png
new file mode 100644
index 000000000..8a1e841af
Binary files /dev/null and b/images/emoji/1f912.png differ
diff --git a/images/emoji/1f913.png b/images/emoji/1f913.png
new file mode 100644
index 000000000..7820bd581
Binary files /dev/null and b/images/emoji/1f913.png differ
diff --git a/images/emoji/1f914.png b/images/emoji/1f914.png
new file mode 100644
index 000000000..c18f6fd14
Binary files /dev/null and b/images/emoji/1f914.png differ
diff --git a/images/emoji/1f915.png b/images/emoji/1f915.png
new file mode 100644
index 000000000..53c7be1d2
Binary files /dev/null and b/images/emoji/1f915.png differ
diff --git a/images/emoji/1f916.png b/images/emoji/1f916.png
new file mode 100644
index 000000000..7cc62612c
Binary files /dev/null and b/images/emoji/1f916.png differ
diff --git a/images/emoji/1f917.png b/images/emoji/1f917.png
new file mode 100644
index 000000000..f398b783a
Binary files /dev/null and b/images/emoji/1f917.png differ
diff --git a/images/emoji/1f918-1f3fb.png b/images/emoji/1f918-1f3fb.png
new file mode 100644
index 000000000..c080d2add
Binary files /dev/null and b/images/emoji/1f918-1f3fb.png differ
diff --git a/images/emoji/1f918-1f3fc.png b/images/emoji/1f918-1f3fc.png
new file mode 100644
index 000000000..12313529b
Binary files /dev/null and b/images/emoji/1f918-1f3fc.png differ
diff --git a/images/emoji/1f918-1f3fd.png b/images/emoji/1f918-1f3fd.png
new file mode 100644
index 000000000..ca9be6ae6
Binary files /dev/null and b/images/emoji/1f918-1f3fd.png differ
diff --git a/images/emoji/1f918-1f3fe.png b/images/emoji/1f918-1f3fe.png
new file mode 100644
index 000000000..abe28cbf8
Binary files /dev/null and b/images/emoji/1f918-1f3fe.png differ
diff --git a/images/emoji/1f918-1f3ff.png b/images/emoji/1f918-1f3ff.png
new file mode 100644
index 000000000..0c6b5dd34
Binary files /dev/null and b/images/emoji/1f918-1f3ff.png differ
diff --git a/images/emoji/1f918.png b/images/emoji/1f918.png
new file mode 100644
index 000000000..4aa6e7e0a
Binary files /dev/null and b/images/emoji/1f918.png differ
diff --git a/images/emoji/1f919-1f3fb.png b/images/emoji/1f919-1f3fb.png
new file mode 100644
index 000000000..2c9320118
Binary files /dev/null and b/images/emoji/1f919-1f3fb.png differ
diff --git a/images/emoji/1f919-1f3fc.png b/images/emoji/1f919-1f3fc.png
new file mode 100644
index 000000000..c39f45a41
Binary files /dev/null and b/images/emoji/1f919-1f3fc.png differ
diff --git a/images/emoji/1f919-1f3fd.png b/images/emoji/1f919-1f3fd.png
new file mode 100644
index 000000000..83a57f63c
Binary files /dev/null and b/images/emoji/1f919-1f3fd.png differ
diff --git a/images/emoji/1f919-1f3fe.png b/images/emoji/1f919-1f3fe.png
new file mode 100644
index 000000000..65b3468fe
Binary files /dev/null and b/images/emoji/1f919-1f3fe.png differ
diff --git a/images/emoji/1f919-1f3ff.png b/images/emoji/1f919-1f3ff.png
new file mode 100644
index 000000000..94ef68ff3
Binary files /dev/null and b/images/emoji/1f919-1f3ff.png differ
diff --git a/images/emoji/1f919.png b/images/emoji/1f919.png
new file mode 100644
index 000000000..a10c59ba7
Binary files /dev/null and b/images/emoji/1f919.png differ
diff --git a/images/emoji/1f91a-1f3fb.png b/images/emoji/1f91a-1f3fb.png
new file mode 100644
index 000000000..813d28499
Binary files /dev/null and b/images/emoji/1f91a-1f3fb.png differ
diff --git a/images/emoji/1f91a-1f3fc.png b/images/emoji/1f91a-1f3fc.png
new file mode 100644
index 000000000..192ff795e
Binary files /dev/null and b/images/emoji/1f91a-1f3fc.png differ
diff --git a/images/emoji/1f91a-1f3fd.png b/images/emoji/1f91a-1f3fd.png
new file mode 100644
index 000000000..61a727abe
Binary files /dev/null and b/images/emoji/1f91a-1f3fd.png differ
diff --git a/images/emoji/1f91a-1f3fe.png b/images/emoji/1f91a-1f3fe.png
new file mode 100644
index 000000000..2e83da511
Binary files /dev/null and b/images/emoji/1f91a-1f3fe.png differ
diff --git a/images/emoji/1f91a-1f3ff.png b/images/emoji/1f91a-1f3ff.png
new file mode 100644
index 000000000..d7a5b95a0
Binary files /dev/null and b/images/emoji/1f91a-1f3ff.png differ
diff --git a/images/emoji/1f91a.png b/images/emoji/1f91a.png
new file mode 100644
index 000000000..479234294
Binary files /dev/null and b/images/emoji/1f91a.png differ
diff --git a/images/emoji/1f91b-1f3fb.png b/images/emoji/1f91b-1f3fb.png
new file mode 100644
index 000000000..1262a6b4b
Binary files /dev/null and b/images/emoji/1f91b-1f3fb.png differ
diff --git a/images/emoji/1f91b-1f3fc.png b/images/emoji/1f91b-1f3fc.png
new file mode 100644
index 000000000..40bf70b82
Binary files /dev/null and b/images/emoji/1f91b-1f3fc.png differ
diff --git a/images/emoji/1f91b-1f3fd.png b/images/emoji/1f91b-1f3fd.png
new file mode 100644
index 000000000..93f581451
Binary files /dev/null and b/images/emoji/1f91b-1f3fd.png differ
diff --git a/images/emoji/1f91b-1f3fe.png b/images/emoji/1f91b-1f3fe.png
new file mode 100644
index 000000000..d82b5ec91
Binary files /dev/null and b/images/emoji/1f91b-1f3fe.png differ
diff --git a/images/emoji/1f91b-1f3ff.png b/images/emoji/1f91b-1f3ff.png
new file mode 100644
index 000000000..09ae4cd49
Binary files /dev/null and b/images/emoji/1f91b-1f3ff.png differ
diff --git a/images/emoji/1f91b.png b/images/emoji/1f91b.png
new file mode 100644
index 000000000..a9d9fd8d5
Binary files /dev/null and b/images/emoji/1f91b.png differ
diff --git a/images/emoji/1f91c-1f3fb.png b/images/emoji/1f91c-1f3fb.png
new file mode 100644
index 000000000..33ded2f61
Binary files /dev/null and b/images/emoji/1f91c-1f3fb.png differ
diff --git a/images/emoji/1f91c-1f3fc.png b/images/emoji/1f91c-1f3fc.png
new file mode 100644
index 000000000..88054e335
Binary files /dev/null and b/images/emoji/1f91c-1f3fc.png differ
diff --git a/images/emoji/1f91c-1f3fd.png b/images/emoji/1f91c-1f3fd.png
new file mode 100644
index 000000000..84b9f5da7
Binary files /dev/null and b/images/emoji/1f91c-1f3fd.png differ
diff --git a/images/emoji/1f91c-1f3fe.png b/images/emoji/1f91c-1f3fe.png
new file mode 100644
index 000000000..e741cfea6
Binary files /dev/null and b/images/emoji/1f91c-1f3fe.png differ
diff --git a/images/emoji/1f91c-1f3ff.png b/images/emoji/1f91c-1f3ff.png
new file mode 100644
index 000000000..cf66d760c
Binary files /dev/null and b/images/emoji/1f91c-1f3ff.png differ
diff --git a/images/emoji/1f91c.png b/images/emoji/1f91c.png
new file mode 100644
index 000000000..754ed066d
Binary files /dev/null and b/images/emoji/1f91c.png differ
diff --git a/images/emoji/1f91d-1f3fb.png b/images/emoji/1f91d-1f3fb.png
new file mode 100644
index 000000000..255fc7ec6
Binary files /dev/null and b/images/emoji/1f91d-1f3fb.png differ
diff --git a/images/emoji/1f91d-1f3fc.png b/images/emoji/1f91d-1f3fc.png
new file mode 100644
index 000000000..1aec7450e
Binary files /dev/null and b/images/emoji/1f91d-1f3fc.png differ
diff --git a/images/emoji/1f91d-1f3fd.png b/images/emoji/1f91d-1f3fd.png
new file mode 100644
index 000000000..104d65691
Binary files /dev/null and b/images/emoji/1f91d-1f3fd.png differ
diff --git a/images/emoji/1f91d-1f3fe.png b/images/emoji/1f91d-1f3fe.png
new file mode 100644
index 000000000..999966d4b
Binary files /dev/null and b/images/emoji/1f91d-1f3fe.png differ
diff --git a/images/emoji/1f91d-1f3ff.png b/images/emoji/1f91d-1f3ff.png
new file mode 100644
index 000000000..9a38f1b66
Binary files /dev/null and b/images/emoji/1f91d-1f3ff.png differ
diff --git a/images/emoji/1f91d.png b/images/emoji/1f91d.png
new file mode 100644
index 000000000..75e8d58e9
Binary files /dev/null and b/images/emoji/1f91d.png differ
diff --git a/images/emoji/1f91e-1f3fb.png b/images/emoji/1f91e-1f3fb.png
new file mode 100644
index 000000000..dd2384a6c
Binary files /dev/null and b/images/emoji/1f91e-1f3fb.png differ
diff --git a/images/emoji/1f91e-1f3fc.png b/images/emoji/1f91e-1f3fc.png
new file mode 100644
index 000000000..6228401be
Binary files /dev/null and b/images/emoji/1f91e-1f3fc.png differ
diff --git a/images/emoji/1f91e-1f3fd.png b/images/emoji/1f91e-1f3fd.png
new file mode 100644
index 000000000..b1074da15
Binary files /dev/null and b/images/emoji/1f91e-1f3fd.png differ
diff --git a/images/emoji/1f91e-1f3fe.png b/images/emoji/1f91e-1f3fe.png
new file mode 100644
index 000000000..75e05e4d3
Binary files /dev/null and b/images/emoji/1f91e-1f3fe.png differ
diff --git a/images/emoji/1f91e-1f3ff.png b/images/emoji/1f91e-1f3ff.png
new file mode 100644
index 000000000..761aebdc3
Binary files /dev/null and b/images/emoji/1f91e-1f3ff.png differ
diff --git a/images/emoji/1f91e.png b/images/emoji/1f91e.png
new file mode 100644
index 000000000..4cd18514e
Binary files /dev/null and b/images/emoji/1f91e.png differ
diff --git a/images/emoji/1f920.png b/images/emoji/1f920.png
new file mode 100644
index 000000000..e67709b88
Binary files /dev/null and b/images/emoji/1f920.png differ
diff --git a/images/emoji/1f921.png b/images/emoji/1f921.png
new file mode 100644
index 000000000..f0e05bac4
Binary files /dev/null and b/images/emoji/1f921.png differ
diff --git a/images/emoji/1f922.png b/images/emoji/1f922.png
new file mode 100644
index 000000000..a566c109c
Binary files /dev/null and b/images/emoji/1f922.png differ
diff --git a/images/emoji/1f923.png b/images/emoji/1f923.png
new file mode 100644
index 000000000..b1736fedf
Binary files /dev/null and b/images/emoji/1f923.png differ
diff --git a/images/emoji/1f924.png b/images/emoji/1f924.png
new file mode 100644
index 000000000..a54605325
Binary files /dev/null and b/images/emoji/1f924.png differ
diff --git a/images/emoji/1f925.png b/images/emoji/1f925.png
new file mode 100644
index 000000000..02827e262
Binary files /dev/null and b/images/emoji/1f925.png differ
diff --git a/images/emoji/1f926-1f3fb.png b/images/emoji/1f926-1f3fb.png
new file mode 100644
index 000000000..2f4b010bb
Binary files /dev/null and b/images/emoji/1f926-1f3fb.png differ
diff --git a/images/emoji/1f926-1f3fc.png b/images/emoji/1f926-1f3fc.png
new file mode 100644
index 000000000..9cba0b0e1
Binary files /dev/null and b/images/emoji/1f926-1f3fc.png differ
diff --git a/images/emoji/1f926-1f3fd.png b/images/emoji/1f926-1f3fd.png
new file mode 100644
index 000000000..b5b5c1e53
Binary files /dev/null and b/images/emoji/1f926-1f3fd.png differ
diff --git a/images/emoji/1f926-1f3fe.png b/images/emoji/1f926-1f3fe.png
new file mode 100644
index 000000000..2840b1134
Binary files /dev/null and b/images/emoji/1f926-1f3fe.png differ
diff --git a/images/emoji/1f926-1f3ff.png b/images/emoji/1f926-1f3ff.png
new file mode 100644
index 000000000..6f070db98
Binary files /dev/null and b/images/emoji/1f926-1f3ff.png differ
diff --git a/images/emoji/1f926.png b/images/emoji/1f926.png
new file mode 100644
index 000000000..defc796cf
Binary files /dev/null and b/images/emoji/1f926.png differ
diff --git a/images/emoji/1f927.png b/images/emoji/1f927.png
new file mode 100644
index 000000000..d6c796746
Binary files /dev/null and b/images/emoji/1f927.png differ
diff --git a/images/emoji/1f930-1f3fb.png b/images/emoji/1f930-1f3fb.png
new file mode 100644
index 000000000..a78703b33
Binary files /dev/null and b/images/emoji/1f930-1f3fb.png differ
diff --git a/images/emoji/1f930-1f3fc.png b/images/emoji/1f930-1f3fc.png
new file mode 100644
index 000000000..0068c6c4a
Binary files /dev/null and b/images/emoji/1f930-1f3fc.png differ
diff --git a/images/emoji/1f930-1f3fd.png b/images/emoji/1f930-1f3fd.png
new file mode 100644
index 000000000..3206296b6
Binary files /dev/null and b/images/emoji/1f930-1f3fd.png differ
diff --git a/images/emoji/1f930-1f3fe.png b/images/emoji/1f930-1f3fe.png
new file mode 100644
index 000000000..120fda5cd
Binary files /dev/null and b/images/emoji/1f930-1f3fe.png differ
diff --git a/images/emoji/1f930-1f3ff.png b/images/emoji/1f930-1f3ff.png
new file mode 100644
index 000000000..569bfdf05
Binary files /dev/null and b/images/emoji/1f930-1f3ff.png differ
diff --git a/images/emoji/1f930.png b/images/emoji/1f930.png
new file mode 100644
index 000000000..084e83a41
Binary files /dev/null and b/images/emoji/1f930.png differ
diff --git a/images/emoji/1f933-1f3fb.png b/images/emoji/1f933-1f3fb.png
new file mode 100644
index 000000000..290e075b5
Binary files /dev/null and b/images/emoji/1f933-1f3fb.png differ
diff --git a/images/emoji/1f933-1f3fc.png b/images/emoji/1f933-1f3fc.png
new file mode 100644
index 000000000..fcd9595b6
Binary files /dev/null and b/images/emoji/1f933-1f3fc.png differ
diff --git a/images/emoji/1f933-1f3fd.png b/images/emoji/1f933-1f3fd.png
new file mode 100644
index 000000000..f3a22fdf4
Binary files /dev/null and b/images/emoji/1f933-1f3fd.png differ
diff --git a/images/emoji/1f933-1f3fe.png b/images/emoji/1f933-1f3fe.png
new file mode 100644
index 000000000..cdecf6d9f
Binary files /dev/null and b/images/emoji/1f933-1f3fe.png differ
diff --git a/images/emoji/1f933-1f3ff.png b/images/emoji/1f933-1f3ff.png
new file mode 100644
index 000000000..86acbb6c2
Binary files /dev/null and b/images/emoji/1f933-1f3ff.png differ
diff --git a/images/emoji/1f933.png b/images/emoji/1f933.png
new file mode 100644
index 000000000..6a1ba75c7
Binary files /dev/null and b/images/emoji/1f933.png differ
diff --git a/images/emoji/1f934-1f3fb.png b/images/emoji/1f934-1f3fb.png
new file mode 100644
index 000000000..9102f9c46
Binary files /dev/null and b/images/emoji/1f934-1f3fb.png differ
diff --git a/images/emoji/1f934-1f3fc.png b/images/emoji/1f934-1f3fc.png
new file mode 100644
index 000000000..23d8b3b12
Binary files /dev/null and b/images/emoji/1f934-1f3fc.png differ
diff --git a/images/emoji/1f934-1f3fd.png b/images/emoji/1f934-1f3fd.png
new file mode 100644
index 000000000..e7692efb7
Binary files /dev/null and b/images/emoji/1f934-1f3fd.png differ
diff --git a/images/emoji/1f934-1f3fe.png b/images/emoji/1f934-1f3fe.png
new file mode 100644
index 000000000..8e10f8be6
Binary files /dev/null and b/images/emoji/1f934-1f3fe.png differ
diff --git a/images/emoji/1f934-1f3ff.png b/images/emoji/1f934-1f3ff.png
new file mode 100644
index 000000000..138d4ea70
Binary files /dev/null and b/images/emoji/1f934-1f3ff.png differ
diff --git a/images/emoji/1f934.png b/images/emoji/1f934.png
new file mode 100644
index 000000000..38d69344c
Binary files /dev/null and b/images/emoji/1f934.png differ
diff --git a/images/emoji/1f935-1f3fb.png b/images/emoji/1f935-1f3fb.png
new file mode 100644
index 000000000..7b6b3acd9
Binary files /dev/null and b/images/emoji/1f935-1f3fb.png differ
diff --git a/images/emoji/1f935-1f3fc.png b/images/emoji/1f935-1f3fc.png
new file mode 100644
index 000000000..7975191b3
Binary files /dev/null and b/images/emoji/1f935-1f3fc.png differ
diff --git a/images/emoji/1f935-1f3fd.png b/images/emoji/1f935-1f3fd.png
new file mode 100644
index 000000000..a2816f600
Binary files /dev/null and b/images/emoji/1f935-1f3fd.png differ
diff --git a/images/emoji/1f935-1f3fe.png b/images/emoji/1f935-1f3fe.png
new file mode 100644
index 000000000..ea8291760
Binary files /dev/null and b/images/emoji/1f935-1f3fe.png differ
diff --git a/images/emoji/1f935-1f3ff.png b/images/emoji/1f935-1f3ff.png
new file mode 100644
index 000000000..c743e05fc
Binary files /dev/null and b/images/emoji/1f935-1f3ff.png differ
diff --git a/images/emoji/1f935.png b/images/emoji/1f935.png
new file mode 100644
index 000000000..5f7e9303f
Binary files /dev/null and b/images/emoji/1f935.png differ
diff --git a/images/emoji/1f936-1f3fb.png b/images/emoji/1f936-1f3fb.png
new file mode 100644
index 000000000..d8a695d70
Binary files /dev/null and b/images/emoji/1f936-1f3fb.png differ
diff --git a/images/emoji/1f936-1f3fc.png b/images/emoji/1f936-1f3fc.png
new file mode 100644
index 000000000..0e17e8c51
Binary files /dev/null and b/images/emoji/1f936-1f3fc.png differ
diff --git a/images/emoji/1f936-1f3fd.png b/images/emoji/1f936-1f3fd.png
new file mode 100644
index 000000000..195ebc400
Binary files /dev/null and b/images/emoji/1f936-1f3fd.png differ
diff --git a/images/emoji/1f936-1f3fe.png b/images/emoji/1f936-1f3fe.png
new file mode 100644
index 000000000..68a556da2
Binary files /dev/null and b/images/emoji/1f936-1f3fe.png differ
diff --git a/images/emoji/1f936-1f3ff.png b/images/emoji/1f936-1f3ff.png
new file mode 100644
index 000000000..ccab3c40f
Binary files /dev/null and b/images/emoji/1f936-1f3ff.png differ
diff --git a/images/emoji/1f936.png b/images/emoji/1f936.png
new file mode 100644
index 000000000..078f0657f
Binary files /dev/null and b/images/emoji/1f936.png differ
diff --git a/images/emoji/1f937-1f3fb.png b/images/emoji/1f937-1f3fb.png
new file mode 100644
index 000000000..1c895e644
Binary files /dev/null and b/images/emoji/1f937-1f3fb.png differ
diff --git a/images/emoji/1f937-1f3fc.png b/images/emoji/1f937-1f3fc.png
new file mode 100644
index 000000000..d76ac4b19
Binary files /dev/null and b/images/emoji/1f937-1f3fc.png differ
diff --git a/images/emoji/1f937-1f3fd.png b/images/emoji/1f937-1f3fd.png
new file mode 100644
index 000000000..dc3a5a9fb
Binary files /dev/null and b/images/emoji/1f937-1f3fd.png differ
diff --git a/images/emoji/1f937-1f3fe.png b/images/emoji/1f937-1f3fe.png
new file mode 100644
index 000000000..5fbef3f22
Binary files /dev/null and b/images/emoji/1f937-1f3fe.png differ
diff --git a/images/emoji/1f937-1f3ff.png b/images/emoji/1f937-1f3ff.png
new file mode 100644
index 000000000..303640fe7
Binary files /dev/null and b/images/emoji/1f937-1f3ff.png differ
diff --git a/images/emoji/1f937.png b/images/emoji/1f937.png
new file mode 100644
index 000000000..76e63bfac
Binary files /dev/null and b/images/emoji/1f937.png differ
diff --git a/images/emoji/1f938-1f3fb.png b/images/emoji/1f938-1f3fb.png
new file mode 100644
index 000000000..db6d65895
Binary files /dev/null and b/images/emoji/1f938-1f3fb.png differ
diff --git a/images/emoji/1f938-1f3fc.png b/images/emoji/1f938-1f3fc.png
new file mode 100644
index 000000000..e00ffbc27
Binary files /dev/null and b/images/emoji/1f938-1f3fc.png differ
diff --git a/images/emoji/1f938-1f3fd.png b/images/emoji/1f938-1f3fd.png
new file mode 100644
index 000000000..49321be39
Binary files /dev/null and b/images/emoji/1f938-1f3fd.png differ
diff --git a/images/emoji/1f938-1f3fe.png b/images/emoji/1f938-1f3fe.png
new file mode 100644
index 000000000..d4562b5e3
Binary files /dev/null and b/images/emoji/1f938-1f3fe.png differ
diff --git a/images/emoji/1f938-1f3ff.png b/images/emoji/1f938-1f3ff.png
new file mode 100644
index 000000000..6e09a8707
Binary files /dev/null and b/images/emoji/1f938-1f3ff.png differ
diff --git a/images/emoji/1f938.png b/images/emoji/1f938.png
new file mode 100644
index 000000000..cbcaa5782
Binary files /dev/null and b/images/emoji/1f938.png differ
diff --git a/images/emoji/1f939-1f3fb.png b/images/emoji/1f939-1f3fb.png
new file mode 100644
index 000000000..c18eda400
Binary files /dev/null and b/images/emoji/1f939-1f3fb.png differ
diff --git a/images/emoji/1f939-1f3fc.png b/images/emoji/1f939-1f3fc.png
new file mode 100644
index 000000000..de3b7a555
Binary files /dev/null and b/images/emoji/1f939-1f3fc.png differ
diff --git a/images/emoji/1f939-1f3fd.png b/images/emoji/1f939-1f3fd.png
new file mode 100644
index 000000000..74ab6d854
Binary files /dev/null and b/images/emoji/1f939-1f3fd.png differ
diff --git a/images/emoji/1f939-1f3fe.png b/images/emoji/1f939-1f3fe.png
new file mode 100644
index 000000000..1c5782320
Binary files /dev/null and b/images/emoji/1f939-1f3fe.png differ
diff --git a/images/emoji/1f939-1f3ff.png b/images/emoji/1f939-1f3ff.png
new file mode 100644
index 000000000..c343d6ee9
Binary files /dev/null and b/images/emoji/1f939-1f3ff.png differ
diff --git a/images/emoji/1f939.png b/images/emoji/1f939.png
new file mode 100644
index 000000000..a37f6224a
Binary files /dev/null and b/images/emoji/1f939.png differ
diff --git a/images/emoji/1f93a.png b/images/emoji/1f93a.png
new file mode 100644
index 000000000..9f6cb6ff8
Binary files /dev/null and b/images/emoji/1f93a.png differ
diff --git a/images/emoji/1f93b-1f3fb.png b/images/emoji/1f93b-1f3fb.png
new file mode 100644
index 000000000..f29209325
Binary files /dev/null and b/images/emoji/1f93b-1f3fb.png differ
diff --git a/images/emoji/1f93b-1f3fc.png b/images/emoji/1f93b-1f3fc.png
new file mode 100644
index 000000000..fea2cc7ee
Binary files /dev/null and b/images/emoji/1f93b-1f3fc.png differ
diff --git a/images/emoji/1f93b-1f3fd.png b/images/emoji/1f93b-1f3fd.png
new file mode 100644
index 000000000..030f32fdd
Binary files /dev/null and b/images/emoji/1f93b-1f3fd.png differ
diff --git a/images/emoji/1f93b-1f3fe.png b/images/emoji/1f93b-1f3fe.png
new file mode 100644
index 000000000..d4d011091
Binary files /dev/null and b/images/emoji/1f93b-1f3fe.png differ
diff --git a/images/emoji/1f93b-1f3ff.png b/images/emoji/1f93b-1f3ff.png
new file mode 100644
index 000000000..69a9789f5
Binary files /dev/null and b/images/emoji/1f93b-1f3ff.png differ
diff --git a/images/emoji/1f93b.png b/images/emoji/1f93b.png
new file mode 100644
index 000000000..71e67cfad
Binary files /dev/null and b/images/emoji/1f93b.png differ
diff --git a/images/emoji/1f93c-1f3fb.png b/images/emoji/1f93c-1f3fb.png
new file mode 100644
index 000000000..379070fd0
Binary files /dev/null and b/images/emoji/1f93c-1f3fb.png differ
diff --git a/images/emoji/1f93c-1f3fc.png b/images/emoji/1f93c-1f3fc.png
new file mode 100644
index 000000000..6863ea920
Binary files /dev/null and b/images/emoji/1f93c-1f3fc.png differ
diff --git a/images/emoji/1f93c-1f3fd.png b/images/emoji/1f93c-1f3fd.png
new file mode 100644
index 000000000..b7e629101
Binary files /dev/null and b/images/emoji/1f93c-1f3fd.png differ
diff --git a/images/emoji/1f93c-1f3fe.png b/images/emoji/1f93c-1f3fe.png
new file mode 100644
index 000000000..750f95892
Binary files /dev/null and b/images/emoji/1f93c-1f3fe.png differ
diff --git a/images/emoji/1f93c-1f3ff.png b/images/emoji/1f93c-1f3ff.png
new file mode 100644
index 000000000..36ab9bb3f
Binary files /dev/null and b/images/emoji/1f93c-1f3ff.png differ
diff --git a/images/emoji/1f93c.png b/images/emoji/1f93c.png
new file mode 100644
index 000000000..9838f24e5
Binary files /dev/null and b/images/emoji/1f93c.png differ
diff --git a/images/emoji/1f93d-1f3fb.png b/images/emoji/1f93d-1f3fb.png
new file mode 100644
index 000000000..bed1a908d
Binary files /dev/null and b/images/emoji/1f93d-1f3fb.png differ
diff --git a/images/emoji/1f93d-1f3fc.png b/images/emoji/1f93d-1f3fc.png
new file mode 100644
index 000000000..2e44151d3
Binary files /dev/null and b/images/emoji/1f93d-1f3fc.png differ
diff --git a/images/emoji/1f93d-1f3fd.png b/images/emoji/1f93d-1f3fd.png
new file mode 100644
index 000000000..b081a4a5a
Binary files /dev/null and b/images/emoji/1f93d-1f3fd.png differ
diff --git a/images/emoji/1f93d-1f3fe.png b/images/emoji/1f93d-1f3fe.png
new file mode 100644
index 000000000..82cfbc3b0
Binary files /dev/null and b/images/emoji/1f93d-1f3fe.png differ
diff --git a/images/emoji/1f93d-1f3ff.png b/images/emoji/1f93d-1f3ff.png
new file mode 100644
index 000000000..6b8e245dc
Binary files /dev/null and b/images/emoji/1f93d-1f3ff.png differ
diff --git a/images/emoji/1f93d.png b/images/emoji/1f93d.png
new file mode 100644
index 000000000..8d6114761
Binary files /dev/null and b/images/emoji/1f93d.png differ
diff --git a/images/emoji/1f93e-1f3fb.png b/images/emoji/1f93e-1f3fb.png
new file mode 100644
index 000000000..a68057a7d
Binary files /dev/null and b/images/emoji/1f93e-1f3fb.png differ
diff --git a/images/emoji/1f93e-1f3fc.png b/images/emoji/1f93e-1f3fc.png
new file mode 100644
index 000000000..74972f8a5
Binary files /dev/null and b/images/emoji/1f93e-1f3fc.png differ
diff --git a/images/emoji/1f93e-1f3fd.png b/images/emoji/1f93e-1f3fd.png
new file mode 100644
index 000000000..0e3a37c3d
Binary files /dev/null and b/images/emoji/1f93e-1f3fd.png differ
diff --git a/images/emoji/1f93e-1f3fe.png b/images/emoji/1f93e-1f3fe.png
new file mode 100644
index 000000000..e1233f382
Binary files /dev/null and b/images/emoji/1f93e-1f3fe.png differ
diff --git a/images/emoji/1f93e-1f3ff.png b/images/emoji/1f93e-1f3ff.png
new file mode 100644
index 000000000..6b1eb9b64
Binary files /dev/null and b/images/emoji/1f93e-1f3ff.png differ
diff --git a/images/emoji/1f93e.png b/images/emoji/1f93e.png
new file mode 100644
index 000000000..cb4457678
Binary files /dev/null and b/images/emoji/1f93e.png differ
diff --git a/images/emoji/1f93f.png b/images/emoji/1f93f.png
new file mode 100644
index 000000000..677c060b4
Binary files /dev/null and b/images/emoji/1f93f.png differ
diff --git a/images/emoji/1f940.png b/images/emoji/1f940.png
new file mode 100644
index 000000000..62412b143
Binary files /dev/null and b/images/emoji/1f940.png differ
diff --git a/images/emoji/1f942.png b/images/emoji/1f942.png
new file mode 100644
index 000000000..32f18d4c9
Binary files /dev/null and b/images/emoji/1f942.png differ
diff --git a/images/emoji/1f943.png b/images/emoji/1f943.png
new file mode 100644
index 000000000..7bf092298
Binary files /dev/null and b/images/emoji/1f943.png differ
diff --git a/images/emoji/1f944.png b/images/emoji/1f944.png
new file mode 100644
index 000000000..3c4da766a
Binary files /dev/null and b/images/emoji/1f944.png differ
diff --git a/images/emoji/1f945.png b/images/emoji/1f945.png
new file mode 100644
index 000000000..3bec11c5b
Binary files /dev/null and b/images/emoji/1f945.png differ
diff --git a/images/emoji/1f946.png b/images/emoji/1f946.png
new file mode 100644
index 000000000..2815a1bb3
Binary files /dev/null and b/images/emoji/1f946.png differ
diff --git a/images/emoji/1f947.png b/images/emoji/1f947.png
new file mode 100644
index 000000000..83011ad99
Binary files /dev/null and b/images/emoji/1f947.png differ
diff --git a/images/emoji/1f948.png b/images/emoji/1f948.png
new file mode 100644
index 000000000..41926fcf5
Binary files /dev/null and b/images/emoji/1f948.png differ
diff --git a/images/emoji/1f949.png b/images/emoji/1f949.png
new file mode 100644
index 000000000..c713851bc
Binary files /dev/null and b/images/emoji/1f949.png differ
diff --git a/images/emoji/1f950.png b/images/emoji/1f950.png
new file mode 100644
index 000000000..502df5b15
Binary files /dev/null and b/images/emoji/1f950.png differ
diff --git a/images/emoji/1f951.png b/images/emoji/1f951.png
new file mode 100644
index 000000000..96b847232
Binary files /dev/null and b/images/emoji/1f951.png differ
diff --git a/images/emoji/1f952.png b/images/emoji/1f952.png
new file mode 100644
index 000000000..c01fd0edd
Binary files /dev/null and b/images/emoji/1f952.png differ
diff --git a/images/emoji/1f953.png b/images/emoji/1f953.png
new file mode 100644
index 000000000..f38a485fb
Binary files /dev/null and b/images/emoji/1f953.png differ
diff --git a/images/emoji/1f954.png b/images/emoji/1f954.png
new file mode 100644
index 000000000..5fa341216
Binary files /dev/null and b/images/emoji/1f954.png differ
diff --git a/images/emoji/1f955.png b/images/emoji/1f955.png
new file mode 100644
index 000000000..c68829b58
Binary files /dev/null and b/images/emoji/1f955.png differ
diff --git a/images/emoji/1f956.png b/images/emoji/1f956.png
new file mode 100644
index 000000000..72477ff78
Binary files /dev/null and b/images/emoji/1f956.png differ
diff --git a/images/emoji/1f957.png b/images/emoji/1f957.png
new file mode 100644
index 000000000..c89f93411
Binary files /dev/null and b/images/emoji/1f957.png differ
diff --git a/images/emoji/1f958.png b/images/emoji/1f958.png
new file mode 100644
index 000000000..663a1006a
Binary files /dev/null and b/images/emoji/1f958.png differ
diff --git a/images/emoji/1f959.png b/images/emoji/1f959.png
new file mode 100644
index 000000000..a2e10df40
Binary files /dev/null and b/images/emoji/1f959.png differ
diff --git a/images/emoji/1f95a.png b/images/emoji/1f95a.png
new file mode 100644
index 000000000..c171974d9
Binary files /dev/null and b/images/emoji/1f95a.png differ
diff --git a/images/emoji/1f95b.png b/images/emoji/1f95b.png
new file mode 100644
index 000000000..e4fcf2e64
Binary files /dev/null and b/images/emoji/1f95b.png differ
diff --git a/images/emoji/1f95c.png b/images/emoji/1f95c.png
new file mode 100644
index 000000000..b64fadad0
Binary files /dev/null and b/images/emoji/1f95c.png differ
diff --git a/images/emoji/1f95d.png b/images/emoji/1f95d.png
new file mode 100644
index 000000000..f04835776
Binary files /dev/null and b/images/emoji/1f95d.png differ
diff --git a/images/emoji/1f95e.png b/images/emoji/1f95e.png
new file mode 100644
index 000000000..6223d1a28
Binary files /dev/null and b/images/emoji/1f95e.png differ
diff --git a/images/emoji/1f960.png b/images/emoji/1f960.png
new file mode 100644
index 000000000..e890c30d4
Binary files /dev/null and b/images/emoji/1f960.png differ
diff --git a/images/emoji/1f961.png b/images/emoji/1f961.png
new file mode 100644
index 000000000..4d09f0ee4
Binary files /dev/null and b/images/emoji/1f961.png differ
diff --git a/images/emoji/1f980.png b/images/emoji/1f980.png
new file mode 100644
index 000000000..ca9350f51
Binary files /dev/null and b/images/emoji/1f980.png differ
diff --git a/images/emoji/1f981.png b/images/emoji/1f981.png
new file mode 100644
index 000000000..5062ab47e
Binary files /dev/null and b/images/emoji/1f981.png differ
diff --git a/images/emoji/1f982.png b/images/emoji/1f982.png
new file mode 100644
index 000000000..449a6b281
Binary files /dev/null and b/images/emoji/1f982.png differ
diff --git a/images/emoji/1f983.png b/images/emoji/1f983.png
new file mode 100644
index 000000000..344af94c9
Binary files /dev/null and b/images/emoji/1f983.png differ
diff --git a/images/emoji/1f984.png b/images/emoji/1f984.png
new file mode 100644
index 000000000..05a97969f
Binary files /dev/null and b/images/emoji/1f984.png differ
diff --git a/images/emoji/1f985.png b/images/emoji/1f985.png
new file mode 100644
index 000000000..4f277debe
Binary files /dev/null and b/images/emoji/1f985.png differ
diff --git a/images/emoji/1f986.png b/images/emoji/1f986.png
new file mode 100644
index 000000000..74330b77c
Binary files /dev/null and b/images/emoji/1f986.png differ
diff --git a/images/emoji/1f987.png b/images/emoji/1f987.png
new file mode 100644
index 000000000..c8f23c515
Binary files /dev/null and b/images/emoji/1f987.png differ
diff --git a/images/emoji/1f988.png b/images/emoji/1f988.png
new file mode 100644
index 000000000..c75076d57
Binary files /dev/null and b/images/emoji/1f988.png differ
diff --git a/images/emoji/1f989.png b/images/emoji/1f989.png
new file mode 100644
index 000000000..a2c318b15
Binary files /dev/null and b/images/emoji/1f989.png differ
diff --git a/images/emoji/1f98a.png b/images/emoji/1f98a.png
new file mode 100644
index 000000000..aaf1dad35
Binary files /dev/null and b/images/emoji/1f98a.png differ
diff --git a/images/emoji/1f98b.png b/images/emoji/1f98b.png
new file mode 100644
index 000000000..5631fe992
Binary files /dev/null and b/images/emoji/1f98b.png differ
diff --git a/images/emoji/1f98c.png b/images/emoji/1f98c.png
new file mode 100644
index 000000000..4a501f880
Binary files /dev/null and b/images/emoji/1f98c.png differ
diff --git a/images/emoji/1f98d.png b/images/emoji/1f98d.png
new file mode 100644
index 000000000..4f2f9bb38
Binary files /dev/null and b/images/emoji/1f98d.png differ
diff --git a/images/emoji/1f98e.png b/images/emoji/1f98e.png
new file mode 100644
index 000000000..836387605
Binary files /dev/null and b/images/emoji/1f98e.png differ
diff --git a/images/emoji/1f98f.png b/images/emoji/1f98f.png
new file mode 100644
index 000000000..12f4e0d9d
Binary files /dev/null and b/images/emoji/1f98f.png differ
diff --git a/images/emoji/1f990.png b/images/emoji/1f990.png
new file mode 100644
index 000000000..49eff28a7
Binary files /dev/null and b/images/emoji/1f990.png differ
diff --git a/images/emoji/1f991.png b/images/emoji/1f991.png
new file mode 100644
index 000000000..f01eeba24
Binary files /dev/null and b/images/emoji/1f991.png differ
diff --git a/images/emoji/1f9c0.png b/images/emoji/1f9c0.png
new file mode 100644
index 000000000..00e997622
Binary files /dev/null and b/images/emoji/1f9c0.png differ
diff --git a/images/emoji/203c.png b/images/emoji/203c.png
new file mode 100644
index 000000000..58a9c528f
Binary files /dev/null and b/images/emoji/203c.png differ
diff --git a/images/emoji/2049.png b/images/emoji/2049.png
new file mode 100644
index 000000000..509813e9b
Binary files /dev/null and b/images/emoji/2049.png differ
diff --git a/images/emoji/2122.png b/images/emoji/2122.png
new file mode 100644
index 000000000..7a0c44a2c
Binary files /dev/null and b/images/emoji/2122.png differ
diff --git a/images/emoji/2139.png b/images/emoji/2139.png
new file mode 100644
index 000000000..871f2db93
Binary files /dev/null and b/images/emoji/2139.png differ
diff --git a/images/emoji/2194.png b/images/emoji/2194.png
new file mode 100644
index 000000000..7937f24f2
Binary files /dev/null and b/images/emoji/2194.png differ
diff --git a/images/emoji/2195.png b/images/emoji/2195.png
new file mode 100644
index 000000000..dfa32b971
Binary files /dev/null and b/images/emoji/2195.png differ
diff --git a/images/emoji/2196.png b/images/emoji/2196.png
new file mode 100644
index 000000000..f38718fbe
Binary files /dev/null and b/images/emoji/2196.png differ
diff --git a/images/emoji/2197.png b/images/emoji/2197.png
new file mode 100644
index 000000000..c43e12d0f
Binary files /dev/null and b/images/emoji/2197.png differ
diff --git a/images/emoji/2198.png b/images/emoji/2198.png
new file mode 100644
index 000000000..7e807da73
Binary files /dev/null and b/images/emoji/2198.png differ
diff --git a/images/emoji/2199.png b/images/emoji/2199.png
new file mode 100644
index 000000000..88b377160
Binary files /dev/null and b/images/emoji/2199.png differ
diff --git a/images/emoji/21a9.png b/images/emoji/21a9.png
new file mode 100644
index 000000000..ba45c2ad9
Binary files /dev/null and b/images/emoji/21a9.png differ
diff --git a/images/emoji/21aa.png b/images/emoji/21aa.png
new file mode 100644
index 000000000..e7258ad32
Binary files /dev/null and b/images/emoji/21aa.png differ
diff --git a/images/emoji/231a.png b/images/emoji/231a.png
new file mode 100644
index 000000000..64819bc6e
Binary files /dev/null and b/images/emoji/231a.png differ
diff --git a/images/emoji/231b.png b/images/emoji/231b.png
new file mode 100644
index 000000000..a5db2d1d3
Binary files /dev/null and b/images/emoji/231b.png differ
diff --git a/images/emoji/2328.png b/images/emoji/2328.png
new file mode 100644
index 000000000..75027cb9a
Binary files /dev/null and b/images/emoji/2328.png differ
diff --git a/images/emoji/23cf.png b/images/emoji/23cf.png
new file mode 100644
index 000000000..ec5cfc489
Binary files /dev/null and b/images/emoji/23cf.png differ
diff --git a/images/emoji/23e9.png b/images/emoji/23e9.png
new file mode 100644
index 000000000..c406fedfd
Binary files /dev/null and b/images/emoji/23e9.png differ
diff --git a/images/emoji/23ea.png b/images/emoji/23ea.png
new file mode 100644
index 000000000..e22e2bd3d
Binary files /dev/null and b/images/emoji/23ea.png differ
diff --git a/images/emoji/23eb.png b/images/emoji/23eb.png
new file mode 100644
index 000000000..13543d5ee
Binary files /dev/null and b/images/emoji/23eb.png differ
diff --git a/images/emoji/23ec.png b/images/emoji/23ec.png
new file mode 100644
index 000000000..90193bfcb
Binary files /dev/null and b/images/emoji/23ec.png differ
diff --git a/images/emoji/23ed.png b/images/emoji/23ed.png
new file mode 100644
index 000000000..f8880d33b
Binary files /dev/null and b/images/emoji/23ed.png differ
diff --git a/images/emoji/23ee.png b/images/emoji/23ee.png
new file mode 100644
index 000000000..1ffd0566c
Binary files /dev/null and b/images/emoji/23ee.png differ
diff --git a/images/emoji/23ef.png b/images/emoji/23ef.png
new file mode 100644
index 000000000..a9f857139
Binary files /dev/null and b/images/emoji/23ef.png differ
diff --git a/images/emoji/23f0.png b/images/emoji/23f0.png
new file mode 100644
index 000000000..cdbc2fbb9
Binary files /dev/null and b/images/emoji/23f0.png differ
diff --git a/images/emoji/23f1.png b/images/emoji/23f1.png
new file mode 100644
index 000000000..6a3a2ef64
Binary files /dev/null and b/images/emoji/23f1.png differ
diff --git a/images/emoji/23f2.png b/images/emoji/23f2.png
new file mode 100644
index 000000000..8a3be574c
Binary files /dev/null and b/images/emoji/23f2.png differ
diff --git a/images/emoji/23f3.png b/images/emoji/23f3.png
new file mode 100644
index 000000000..b93b15ed6
Binary files /dev/null and b/images/emoji/23f3.png differ
diff --git a/images/emoji/23f8.png b/images/emoji/23f8.png
new file mode 100644
index 000000000..4f07e7ebf
Binary files /dev/null and b/images/emoji/23f8.png differ
diff --git a/images/emoji/23f9.png b/images/emoji/23f9.png
new file mode 100644
index 000000000..cfa99988a
Binary files /dev/null and b/images/emoji/23f9.png differ
diff --git a/images/emoji/23fa.png b/images/emoji/23fa.png
new file mode 100644
index 000000000..ada52830f
Binary files /dev/null and b/images/emoji/23fa.png differ
diff --git a/images/emoji/24c2.png b/images/emoji/24c2.png
new file mode 100644
index 000000000..8a3506fc1
Binary files /dev/null and b/images/emoji/24c2.png differ
diff --git a/images/emoji/25aa.png b/images/emoji/25aa.png
new file mode 100644
index 000000000..48595d3e1
Binary files /dev/null and b/images/emoji/25aa.png differ
diff --git a/images/emoji/25ab.png b/images/emoji/25ab.png
new file mode 100644
index 000000000..d7ebdb0c0
Binary files /dev/null and b/images/emoji/25ab.png differ
diff --git a/images/emoji/25b6.png b/images/emoji/25b6.png
new file mode 100644
index 000000000..4e2b68285
Binary files /dev/null and b/images/emoji/25b6.png differ
diff --git a/images/emoji/25c0.png b/images/emoji/25c0.png
new file mode 100644
index 000000000..ee38e3b03
Binary files /dev/null and b/images/emoji/25c0.png differ
diff --git a/images/emoji/25fb.png b/images/emoji/25fb.png
new file mode 100644
index 000000000..8daacf570
Binary files /dev/null and b/images/emoji/25fb.png differ
diff --git a/images/emoji/25fc.png b/images/emoji/25fc.png
new file mode 100644
index 000000000..05a30a6aa
Binary files /dev/null and b/images/emoji/25fc.png differ
diff --git a/images/emoji/25fd.png b/images/emoji/25fd.png
new file mode 100644
index 000000000..ae8741267
Binary files /dev/null and b/images/emoji/25fd.png differ
diff --git a/images/emoji/25fe.png b/images/emoji/25fe.png
new file mode 100644
index 000000000..39765bba6
Binary files /dev/null and b/images/emoji/25fe.png differ
diff --git a/images/emoji/2600.png b/images/emoji/2600.png
new file mode 100644
index 000000000..fd521ae31
Binary files /dev/null and b/images/emoji/2600.png differ
diff --git a/images/emoji/2601.png b/images/emoji/2601.png
new file mode 100644
index 000000000..5b4f57f77
Binary files /dev/null and b/images/emoji/2601.png differ
diff --git a/images/emoji/2602.png b/images/emoji/2602.png
new file mode 100644
index 000000000..97fe859e7
Binary files /dev/null and b/images/emoji/2602.png differ
diff --git a/images/emoji/2603.png b/images/emoji/2603.png
new file mode 100644
index 000000000..896f28502
Binary files /dev/null and b/images/emoji/2603.png differ
diff --git a/images/emoji/2604.png b/images/emoji/2604.png
new file mode 100644
index 000000000..d775d6387
Binary files /dev/null and b/images/emoji/2604.png differ
diff --git a/images/emoji/260e.png b/images/emoji/260e.png
new file mode 100644
index 000000000..0fbb8c12c
Binary files /dev/null and b/images/emoji/260e.png differ
diff --git a/images/emoji/2611.png b/images/emoji/2611.png
new file mode 100644
index 000000000..284d95738
Binary files /dev/null and b/images/emoji/2611.png differ
diff --git a/images/emoji/2614.png b/images/emoji/2614.png
new file mode 100644
index 000000000..5b35b7ff6
Binary files /dev/null and b/images/emoji/2614.png differ
diff --git a/images/emoji/2615.png b/images/emoji/2615.png
new file mode 100644
index 000000000..553061471
Binary files /dev/null and b/images/emoji/2615.png differ
diff --git a/images/emoji/2618.png b/images/emoji/2618.png
new file mode 100644
index 000000000..f202aecfe
Binary files /dev/null and b/images/emoji/2618.png differ
diff --git a/images/emoji/261d-1f3fb.png b/images/emoji/261d-1f3fb.png
new file mode 100644
index 000000000..6a9db21d6
Binary files /dev/null and b/images/emoji/261d-1f3fb.png differ
diff --git a/images/emoji/261d-1f3fc.png b/images/emoji/261d-1f3fc.png
new file mode 100644
index 000000000..15aa9ea0e
Binary files /dev/null and b/images/emoji/261d-1f3fc.png differ
diff --git a/images/emoji/261d-1f3fd.png b/images/emoji/261d-1f3fd.png
new file mode 100644
index 000000000..652b73a9c
Binary files /dev/null and b/images/emoji/261d-1f3fd.png differ
diff --git a/images/emoji/261d-1f3fe.png b/images/emoji/261d-1f3fe.png
new file mode 100644
index 000000000..692bad926
Binary files /dev/null and b/images/emoji/261d-1f3fe.png differ
diff --git a/images/emoji/261d-1f3ff.png b/images/emoji/261d-1f3ff.png
new file mode 100644
index 000000000..1e1b10fb7
Binary files /dev/null and b/images/emoji/261d-1f3ff.png differ
diff --git a/images/emoji/261d.png b/images/emoji/261d.png
new file mode 100644
index 000000000..f4978ff0f
Binary files /dev/null and b/images/emoji/261d.png differ
diff --git a/images/emoji/2620.png b/images/emoji/2620.png
new file mode 100644
index 000000000..b459df922
Binary files /dev/null and b/images/emoji/2620.png differ
diff --git a/images/emoji/2622.png b/images/emoji/2622.png
new file mode 100644
index 000000000..3b46199fe
Binary files /dev/null and b/images/emoji/2622.png differ
diff --git a/images/emoji/2623.png b/images/emoji/2623.png
new file mode 100644
index 000000000..007b4fc2d
Binary files /dev/null and b/images/emoji/2623.png differ
diff --git a/images/emoji/2626.png b/images/emoji/2626.png
new file mode 100644
index 000000000..0530e33a4
Binary files /dev/null and b/images/emoji/2626.png differ
diff --git a/images/emoji/262a.png b/images/emoji/262a.png
new file mode 100644
index 000000000..e18263645
Binary files /dev/null and b/images/emoji/262a.png differ
diff --git a/images/emoji/262e.png b/images/emoji/262e.png
new file mode 100644
index 000000000..86033faf4
Binary files /dev/null and b/images/emoji/262e.png differ
diff --git a/images/emoji/262f.png b/images/emoji/262f.png
new file mode 100644
index 000000000..f2900f633
Binary files /dev/null and b/images/emoji/262f.png differ
diff --git a/images/emoji/2638.png b/images/emoji/2638.png
new file mode 100644
index 000000000..3666db001
Binary files /dev/null and b/images/emoji/2638.png differ
diff --git a/images/emoji/2639.png b/images/emoji/2639.png
new file mode 100644
index 000000000..6ae71f233
Binary files /dev/null and b/images/emoji/2639.png differ
diff --git a/images/emoji/263a.png b/images/emoji/263a.png
new file mode 100644
index 000000000..e9e53c03d
Binary files /dev/null and b/images/emoji/263a.png differ
diff --git a/images/emoji/2648.png b/images/emoji/2648.png
new file mode 100644
index 000000000..21a189d0e
Binary files /dev/null and b/images/emoji/2648.png differ
diff --git a/images/emoji/2649.png b/images/emoji/2649.png
new file mode 100644
index 000000000..b2a370df4
Binary files /dev/null and b/images/emoji/2649.png differ
diff --git a/images/emoji/264a.png b/images/emoji/264a.png
new file mode 100644
index 000000000..1a09698cf
Binary files /dev/null and b/images/emoji/264a.png differ
diff --git a/images/emoji/264b.png b/images/emoji/264b.png
new file mode 100644
index 000000000..a64af07cb
Binary files /dev/null and b/images/emoji/264b.png differ
diff --git a/images/emoji/264c.png b/images/emoji/264c.png
new file mode 100644
index 000000000..30158d34d
Binary files /dev/null and b/images/emoji/264c.png differ
diff --git a/images/emoji/264d.png b/images/emoji/264d.png
new file mode 100644
index 000000000..a6b56c2cb
Binary files /dev/null and b/images/emoji/264d.png differ
diff --git a/images/emoji/264e.png b/images/emoji/264e.png
new file mode 100644
index 000000000..8fd133a35
Binary files /dev/null and b/images/emoji/264e.png differ
diff --git a/images/emoji/264f.png b/images/emoji/264f.png
new file mode 100644
index 000000000..c31a99204
Binary files /dev/null and b/images/emoji/264f.png differ
diff --git a/images/emoji/2650.png b/images/emoji/2650.png
new file mode 100644
index 000000000..f8d94ff29
Binary files /dev/null and b/images/emoji/2650.png differ
diff --git a/images/emoji/2651.png b/images/emoji/2651.png
new file mode 100644
index 000000000..6293d31d4
Binary files /dev/null and b/images/emoji/2651.png differ
diff --git a/images/emoji/2652.png b/images/emoji/2652.png
new file mode 100644
index 000000000..641a4f688
Binary files /dev/null and b/images/emoji/2652.png differ
diff --git a/images/emoji/2653.png b/images/emoji/2653.png
new file mode 100644
index 000000000..7f6f646a9
Binary files /dev/null and b/images/emoji/2653.png differ
diff --git a/images/emoji/2660.png b/images/emoji/2660.png
new file mode 100644
index 000000000..f822f184c
Binary files /dev/null and b/images/emoji/2660.png differ
diff --git a/images/emoji/2663.png b/images/emoji/2663.png
new file mode 100644
index 000000000..4f2abf791
Binary files /dev/null and b/images/emoji/2663.png differ
diff --git a/images/emoji/2665.png b/images/emoji/2665.png
new file mode 100644
index 000000000..393c3ed52
Binary files /dev/null and b/images/emoji/2665.png differ
diff --git a/images/emoji/2666.png b/images/emoji/2666.png
new file mode 100644
index 000000000..1f25f51f9
Binary files /dev/null and b/images/emoji/2666.png differ
diff --git a/images/emoji/2668.png b/images/emoji/2668.png
new file mode 100644
index 000000000..3d9df2d94
Binary files /dev/null and b/images/emoji/2668.png differ
diff --git a/images/emoji/267b.png b/images/emoji/267b.png
new file mode 100644
index 000000000..9221f095c
Binary files /dev/null and b/images/emoji/267b.png differ
diff --git a/images/emoji/267f.png b/images/emoji/267f.png
new file mode 100644
index 000000000..4e5b2698e
Binary files /dev/null and b/images/emoji/267f.png differ
diff --git a/images/emoji/2692.png b/images/emoji/2692.png
new file mode 100644
index 000000000..3bee30ec5
Binary files /dev/null and b/images/emoji/2692.png differ
diff --git a/images/emoji/2693.png b/images/emoji/2693.png
new file mode 100644
index 000000000..b036f70a0
Binary files /dev/null and b/images/emoji/2693.png differ
diff --git a/images/emoji/2694.png b/images/emoji/2694.png
new file mode 100644
index 000000000..907e96071
Binary files /dev/null and b/images/emoji/2694.png differ
diff --git a/images/emoji/2696.png b/images/emoji/2696.png
new file mode 100644
index 000000000..0757eda16
Binary files /dev/null and b/images/emoji/2696.png differ
diff --git a/images/emoji/2697.png b/images/emoji/2697.png
new file mode 100644
index 000000000..307a73242
Binary files /dev/null and b/images/emoji/2697.png differ
diff --git a/images/emoji/2699.png b/images/emoji/2699.png
new file mode 100644
index 000000000..2a1cc2c0f
Binary files /dev/null and b/images/emoji/2699.png differ
diff --git a/images/emoji/269b.png b/images/emoji/269b.png
new file mode 100644
index 000000000..5f4567aa0
Binary files /dev/null and b/images/emoji/269b.png differ
diff --git a/images/emoji/269c.png b/images/emoji/269c.png
new file mode 100644
index 000000000..c9250d27f
Binary files /dev/null and b/images/emoji/269c.png differ
diff --git a/images/emoji/26a0.png b/images/emoji/26a0.png
new file mode 100644
index 000000000..35691c2ed
Binary files /dev/null and b/images/emoji/26a0.png differ
diff --git a/images/emoji/26a1.png b/images/emoji/26a1.png
new file mode 100644
index 000000000..47e68e48e
Binary files /dev/null and b/images/emoji/26a1.png differ
diff --git a/images/emoji/26aa.png b/images/emoji/26aa.png
new file mode 100644
index 000000000..c19e15684
Binary files /dev/null and b/images/emoji/26aa.png differ
diff --git a/images/emoji/26ab.png b/images/emoji/26ab.png
new file mode 100644
index 000000000..b62b87170
Binary files /dev/null and b/images/emoji/26ab.png differ
diff --git a/images/emoji/26b0.png b/images/emoji/26b0.png
new file mode 100644
index 000000000..fb2932aa5
Binary files /dev/null and b/images/emoji/26b0.png differ
diff --git a/images/emoji/26b1.png b/images/emoji/26b1.png
new file mode 100644
index 000000000..6b5b35034
Binary files /dev/null and b/images/emoji/26b1.png differ
diff --git a/images/emoji/26bd.png b/images/emoji/26bd.png
new file mode 100644
index 000000000..28cfa218d
Binary files /dev/null and b/images/emoji/26bd.png differ
diff --git a/images/emoji/26be.png b/images/emoji/26be.png
new file mode 100644
index 000000000..f8463f153
Binary files /dev/null and b/images/emoji/26be.png differ
diff --git a/images/emoji/26c4.png b/images/emoji/26c4.png
new file mode 100644
index 000000000..20c177c2a
Binary files /dev/null and b/images/emoji/26c4.png differ
diff --git a/images/emoji/26c5.png b/images/emoji/26c5.png
new file mode 100644
index 000000000..a55e59c34
Binary files /dev/null and b/images/emoji/26c5.png differ
diff --git a/images/emoji/26c8.png b/images/emoji/26c8.png
new file mode 100644
index 000000000..31a26a1b6
Binary files /dev/null and b/images/emoji/26c8.png differ
diff --git a/images/emoji/26ce.png b/images/emoji/26ce.png
new file mode 100644
index 000000000..0a780a700
Binary files /dev/null and b/images/emoji/26ce.png differ
diff --git a/images/emoji/26cf.png b/images/emoji/26cf.png
new file mode 100644
index 000000000..6370fe6d7
Binary files /dev/null and b/images/emoji/26cf.png differ
diff --git a/images/emoji/26d1.png b/images/emoji/26d1.png
new file mode 100644
index 000000000..7140a6760
Binary files /dev/null and b/images/emoji/26d1.png differ
diff --git a/images/emoji/26d3.png b/images/emoji/26d3.png
new file mode 100644
index 000000000..57f46139a
Binary files /dev/null and b/images/emoji/26d3.png differ
diff --git a/images/emoji/26d4.png b/images/emoji/26d4.png
new file mode 100644
index 000000000..476800fc5
Binary files /dev/null and b/images/emoji/26d4.png differ
diff --git a/images/emoji/26e9.png b/images/emoji/26e9.png
new file mode 100644
index 000000000..5a344975b
Binary files /dev/null and b/images/emoji/26e9.png differ
diff --git a/images/emoji/26ea.png b/images/emoji/26ea.png
new file mode 100644
index 000000000..24df10f1a
Binary files /dev/null and b/images/emoji/26ea.png differ
diff --git a/images/emoji/26f0.png b/images/emoji/26f0.png
new file mode 100644
index 000000000..6722ebdd2
Binary files /dev/null and b/images/emoji/26f0.png differ
diff --git a/images/emoji/26f1.png b/images/emoji/26f1.png
new file mode 100644
index 000000000..258e1e757
Binary files /dev/null and b/images/emoji/26f1.png differ
diff --git a/images/emoji/26f2.png b/images/emoji/26f2.png
new file mode 100644
index 000000000..293f5d91c
Binary files /dev/null and b/images/emoji/26f2.png differ
diff --git a/images/emoji/26f3.png b/images/emoji/26f3.png
new file mode 100644
index 000000000..f65a21d8a
Binary files /dev/null and b/images/emoji/26f3.png differ
diff --git a/images/emoji/26f4.png b/images/emoji/26f4.png
new file mode 100644
index 000000000..41816b3ae
Binary files /dev/null and b/images/emoji/26f4.png differ
diff --git a/images/emoji/26f5.png b/images/emoji/26f5.png
new file mode 100644
index 000000000..772ef11da
Binary files /dev/null and b/images/emoji/26f5.png differ
diff --git a/images/emoji/26f7.png b/images/emoji/26f7.png
new file mode 100644
index 000000000..2eb3bdce2
Binary files /dev/null and b/images/emoji/26f7.png differ
diff --git a/images/emoji/26f8.png b/images/emoji/26f8.png
new file mode 100644
index 000000000..c56b7b8a5
Binary files /dev/null and b/images/emoji/26f8.png differ
diff --git a/images/emoji/26f9-1f3fb.png b/images/emoji/26f9-1f3fb.png
new file mode 100644
index 000000000..43f97e7c3
Binary files /dev/null and b/images/emoji/26f9-1f3fb.png differ
diff --git a/images/emoji/26f9-1f3fc.png b/images/emoji/26f9-1f3fc.png
new file mode 100644
index 000000000..f892fd596
Binary files /dev/null and b/images/emoji/26f9-1f3fc.png differ
diff --git a/images/emoji/26f9-1f3fd.png b/images/emoji/26f9-1f3fd.png
new file mode 100644
index 000000000..e109997a9
Binary files /dev/null and b/images/emoji/26f9-1f3fd.png differ
diff --git a/images/emoji/26f9-1f3fe.png b/images/emoji/26f9-1f3fe.png
new file mode 100644
index 000000000..354e8f9c2
Binary files /dev/null and b/images/emoji/26f9-1f3fe.png differ
diff --git a/images/emoji/26f9-1f3ff.png b/images/emoji/26f9-1f3ff.png
new file mode 100644
index 000000000..9581dbbea
Binary files /dev/null and b/images/emoji/26f9-1f3ff.png differ
diff --git a/images/emoji/26f9.png b/images/emoji/26f9.png
new file mode 100644
index 000000000..63bff9c3e
Binary files /dev/null and b/images/emoji/26f9.png differ
diff --git a/images/emoji/26fa.png b/images/emoji/26fa.png
new file mode 100644
index 000000000..3fddcfc56
Binary files /dev/null and b/images/emoji/26fa.png differ
diff --git a/images/emoji/26fd.png b/images/emoji/26fd.png
new file mode 100644
index 000000000..05b187944
Binary files /dev/null and b/images/emoji/26fd.png differ
diff --git a/images/emoji/2702.png b/images/emoji/2702.png
new file mode 100644
index 000000000..270571c8c
Binary files /dev/null and b/images/emoji/2702.png differ
diff --git a/images/emoji/2705.png b/images/emoji/2705.png
new file mode 100644
index 000000000..e55f087e5
Binary files /dev/null and b/images/emoji/2705.png differ
diff --git a/images/emoji/2708.png b/images/emoji/2708.png
new file mode 100644
index 000000000..268d2ac3c
Binary files /dev/null and b/images/emoji/2708.png differ
diff --git a/images/emoji/2709.png b/images/emoji/2709.png
new file mode 100644
index 000000000..ec77ac375
Binary files /dev/null and b/images/emoji/2709.png differ
diff --git a/images/emoji/270a-1f3fb.png b/images/emoji/270a-1f3fb.png
new file mode 100644
index 000000000..02809e2dd
Binary files /dev/null and b/images/emoji/270a-1f3fb.png differ
diff --git a/images/emoji/270a-1f3fc.png b/images/emoji/270a-1f3fc.png
new file mode 100644
index 000000000..5de348103
Binary files /dev/null and b/images/emoji/270a-1f3fc.png differ
diff --git a/images/emoji/270a-1f3fd.png b/images/emoji/270a-1f3fd.png
new file mode 100644
index 000000000..0d5240129
Binary files /dev/null and b/images/emoji/270a-1f3fd.png differ
diff --git a/images/emoji/270a-1f3fe.png b/images/emoji/270a-1f3fe.png
new file mode 100644
index 000000000..a95c0dd63
Binary files /dev/null and b/images/emoji/270a-1f3fe.png differ
diff --git a/images/emoji/270a-1f3ff.png b/images/emoji/270a-1f3ff.png
new file mode 100644
index 000000000..a2f092fd8
Binary files /dev/null and b/images/emoji/270a-1f3ff.png differ
diff --git a/images/emoji/270a.png b/images/emoji/270a.png
new file mode 100644
index 000000000..de33592bf
Binary files /dev/null and b/images/emoji/270a.png differ
diff --git a/images/emoji/270b-1f3fb.png b/images/emoji/270b-1f3fb.png
new file mode 100644
index 000000000..3b752902c
Binary files /dev/null and b/images/emoji/270b-1f3fb.png differ
diff --git a/images/emoji/270b-1f3fc.png b/images/emoji/270b-1f3fc.png
new file mode 100644
index 000000000..44e2a514c
Binary files /dev/null and b/images/emoji/270b-1f3fc.png differ
diff --git a/images/emoji/270b-1f3fd.png b/images/emoji/270b-1f3fd.png
new file mode 100644
index 000000000..5bb62a752
Binary files /dev/null and b/images/emoji/270b-1f3fd.png differ
diff --git a/images/emoji/270b-1f3fe.png b/images/emoji/270b-1f3fe.png
new file mode 100644
index 000000000..c7f8c9ec2
Binary files /dev/null and b/images/emoji/270b-1f3fe.png differ
diff --git a/images/emoji/270b-1f3ff.png b/images/emoji/270b-1f3ff.png
new file mode 100644
index 000000000..c601b58a7
Binary files /dev/null and b/images/emoji/270b-1f3ff.png differ
diff --git a/images/emoji/270b.png b/images/emoji/270b.png
new file mode 100644
index 000000000..6b2954315
Binary files /dev/null and b/images/emoji/270b.png differ
diff --git a/images/emoji/270c-1f3fb.png b/images/emoji/270c-1f3fb.png
new file mode 100644
index 000000000..6ac54a745
Binary files /dev/null and b/images/emoji/270c-1f3fb.png differ
diff --git a/images/emoji/270c-1f3fc.png b/images/emoji/270c-1f3fc.png
new file mode 100644
index 000000000..6dd966986
Binary files /dev/null and b/images/emoji/270c-1f3fc.png differ
diff --git a/images/emoji/270c-1f3fd.png b/images/emoji/270c-1f3fd.png
new file mode 100644
index 000000000..a615e53f0
Binary files /dev/null and b/images/emoji/270c-1f3fd.png differ
diff --git a/images/emoji/270c-1f3fe.png b/images/emoji/270c-1f3fe.png
new file mode 100644
index 000000000..33a34bd5a
Binary files /dev/null and b/images/emoji/270c-1f3fe.png differ
diff --git a/images/emoji/270c-1f3ff.png b/images/emoji/270c-1f3ff.png
new file mode 100644
index 000000000..45ad14b6c
Binary files /dev/null and b/images/emoji/270c-1f3ff.png differ
diff --git a/images/emoji/270c.png b/images/emoji/270c.png
new file mode 100644
index 000000000..70c5516ff
Binary files /dev/null and b/images/emoji/270c.png differ
diff --git a/images/emoji/270d-1f3fb.png b/images/emoji/270d-1f3fb.png
new file mode 100644
index 000000000..7923d8ebb
Binary files /dev/null and b/images/emoji/270d-1f3fb.png differ
diff --git a/images/emoji/270d-1f3fc.png b/images/emoji/270d-1f3fc.png
new file mode 100644
index 000000000..bcb304e15
Binary files /dev/null and b/images/emoji/270d-1f3fc.png differ
diff --git a/images/emoji/270d-1f3fd.png b/images/emoji/270d-1f3fd.png
new file mode 100644
index 000000000..fd885fd2d
Binary files /dev/null and b/images/emoji/270d-1f3fd.png differ
diff --git a/images/emoji/270d-1f3fe.png b/images/emoji/270d-1f3fe.png
new file mode 100644
index 000000000..d065b8c64
Binary files /dev/null and b/images/emoji/270d-1f3fe.png differ
diff --git a/images/emoji/270d-1f3ff.png b/images/emoji/270d-1f3ff.png
new file mode 100644
index 000000000..a44b3dd75
Binary files /dev/null and b/images/emoji/270d-1f3ff.png differ
diff --git a/images/emoji/270d.png b/images/emoji/270d.png
new file mode 100644
index 000000000..85639f8ac
Binary files /dev/null and b/images/emoji/270d.png differ
diff --git a/images/emoji/270f.png b/images/emoji/270f.png
new file mode 100644
index 000000000..3833d590f
Binary files /dev/null and b/images/emoji/270f.png differ
diff --git a/images/emoji/2712.png b/images/emoji/2712.png
new file mode 100644
index 000000000..872d0ae15
Binary files /dev/null and b/images/emoji/2712.png differ
diff --git a/images/emoji/2714.png b/images/emoji/2714.png
new file mode 100644
index 000000000..03bd69537
Binary files /dev/null and b/images/emoji/2714.png differ
diff --git a/images/emoji/2716.png b/images/emoji/2716.png
new file mode 100644
index 000000000..e47cc1b68
Binary files /dev/null and b/images/emoji/2716.png differ
diff --git a/images/emoji/271d.png b/images/emoji/271d.png
new file mode 100644
index 000000000..42b10e822
Binary files /dev/null and b/images/emoji/271d.png differ
diff --git a/images/emoji/2721.png b/images/emoji/2721.png
new file mode 100644
index 000000000..fc59d0dde
Binary files /dev/null and b/images/emoji/2721.png differ
diff --git a/images/emoji/2728.png b/images/emoji/2728.png
new file mode 100644
index 000000000..169bc10b0
Binary files /dev/null and b/images/emoji/2728.png differ
diff --git a/images/emoji/2733.png b/images/emoji/2733.png
new file mode 100644
index 000000000..3307ffa62
Binary files /dev/null and b/images/emoji/2733.png differ
diff --git a/images/emoji/2734.png b/images/emoji/2734.png
new file mode 100644
index 000000000..820179bda
Binary files /dev/null and b/images/emoji/2734.png differ
diff --git a/images/emoji/2744.png b/images/emoji/2744.png
new file mode 100644
index 000000000..db319a77e
Binary files /dev/null and b/images/emoji/2744.png differ
diff --git a/images/emoji/2747.png b/images/emoji/2747.png
new file mode 100644
index 000000000..6aa7b6ec9
Binary files /dev/null and b/images/emoji/2747.png differ
diff --git a/images/emoji/274c.png b/images/emoji/274c.png
new file mode 100644
index 000000000..9f9ed0f7a
Binary files /dev/null and b/images/emoji/274c.png differ
diff --git a/images/emoji/274e.png b/images/emoji/274e.png
new file mode 100644
index 000000000..dae487f1f
Binary files /dev/null and b/images/emoji/274e.png differ
diff --git a/images/emoji/2753.png b/images/emoji/2753.png
new file mode 100644
index 000000000..5a58f3458
Binary files /dev/null and b/images/emoji/2753.png differ
diff --git a/images/emoji/2754.png b/images/emoji/2754.png
new file mode 100644
index 000000000..6e7824c75
Binary files /dev/null and b/images/emoji/2754.png differ
diff --git a/images/emoji/2755.png b/images/emoji/2755.png
new file mode 100644
index 000000000..9b64da8bf
Binary files /dev/null and b/images/emoji/2755.png differ
diff --git a/images/emoji/2757.png b/images/emoji/2757.png
new file mode 100644
index 000000000..2c1440642
Binary files /dev/null and b/images/emoji/2757.png differ
diff --git a/images/emoji/2763.png b/images/emoji/2763.png
new file mode 100644
index 000000000..91b520be4
Binary files /dev/null and b/images/emoji/2763.png differ
diff --git a/images/emoji/2764.png b/images/emoji/2764.png
new file mode 100644
index 000000000..638cb72dc
Binary files /dev/null and b/images/emoji/2764.png differ
diff --git a/images/emoji/2795.png b/images/emoji/2795.png
new file mode 100644
index 000000000..40799798a
Binary files /dev/null and b/images/emoji/2795.png differ
diff --git a/images/emoji/2796.png b/images/emoji/2796.png
new file mode 100644
index 000000000..054211caf
Binary files /dev/null and b/images/emoji/2796.png differ
diff --git a/images/emoji/2797.png b/images/emoji/2797.png
new file mode 100644
index 000000000..df32ab21b
Binary files /dev/null and b/images/emoji/2797.png differ
diff --git a/images/emoji/27a1.png b/images/emoji/27a1.png
new file mode 100644
index 000000000..4755670b5
Binary files /dev/null and b/images/emoji/27a1.png differ
diff --git a/images/emoji/27b0.png b/images/emoji/27b0.png
new file mode 100644
index 000000000..440aa56d5
Binary files /dev/null and b/images/emoji/27b0.png differ
diff --git a/images/emoji/27bf.png b/images/emoji/27bf.png
new file mode 100644
index 000000000..0b82c8fe3
Binary files /dev/null and b/images/emoji/27bf.png differ
diff --git a/images/emoji/2934.png b/images/emoji/2934.png
new file mode 100644
index 000000000..f29bfcfc0
Binary files /dev/null and b/images/emoji/2934.png differ
diff --git a/images/emoji/2935.png b/images/emoji/2935.png
new file mode 100644
index 000000000..2d9d24bca
Binary files /dev/null and b/images/emoji/2935.png differ
diff --git a/images/emoji/2b05.png b/images/emoji/2b05.png
new file mode 100644
index 000000000..8c685e0a8
Binary files /dev/null and b/images/emoji/2b05.png differ
diff --git a/images/emoji/2b06.png b/images/emoji/2b06.png
new file mode 100644
index 000000000..af8218a87
Binary files /dev/null and b/images/emoji/2b06.png differ
diff --git a/images/emoji/2b07.png b/images/emoji/2b07.png
new file mode 100644
index 000000000..b8eefd0b1
Binary files /dev/null and b/images/emoji/2b07.png differ
diff --git a/images/emoji/2b1b.png b/images/emoji/2b1b.png
new file mode 100644
index 000000000..162f2bb42
Binary files /dev/null and b/images/emoji/2b1b.png differ
diff --git a/images/emoji/2b1c.png b/images/emoji/2b1c.png
new file mode 100644
index 000000000..6f06c1c79
Binary files /dev/null and b/images/emoji/2b1c.png differ
diff --git a/images/emoji/2b50.png b/images/emoji/2b50.png
new file mode 100644
index 000000000..c93094707
Binary files /dev/null and b/images/emoji/2b50.png differ
diff --git a/images/emoji/2b55.png b/images/emoji/2b55.png
new file mode 100644
index 000000000..3fe75ce46
Binary files /dev/null and b/images/emoji/2b55.png differ
diff --git a/images/emoji/3030.png b/images/emoji/3030.png
new file mode 100644
index 000000000..001c8d6e4
Binary files /dev/null and b/images/emoji/3030.png differ
diff --git a/images/emoji/303d.png b/images/emoji/303d.png
new file mode 100644
index 000000000..70453d415
Binary files /dev/null and b/images/emoji/303d.png differ
diff --git a/images/emoji/3297.png b/images/emoji/3297.png
new file mode 100644
index 000000000..ba8c89d95
Binary files /dev/null and b/images/emoji/3297.png differ
diff --git a/images/emoji/3299.png b/images/emoji/3299.png
new file mode 100644
index 000000000..5fd72608e
Binary files /dev/null and b/images/emoji/3299.png differ
diff --git a/images/emoji/README b/images/emoji/README
new file mode 100644
index 000000000..ab478b753
--- /dev/null
+++ b/images/emoji/README
@@ -0,0 +1,2 @@
+These files supplied by emojione. License is CC BY 4.0. Attribution is required for commercial use.
+See http://emojione.com
diff --git a/include/BaseObject.php b/include/BaseObject.php
deleted file mode 100644
index a88978a83..000000000
--- a/include/BaseObject.php
+++ /dev/null
@@ -1,38 +0,0 @@
-fallback_description;
@@ -143,11 +139,7 @@ class PermissionDescription {
case PERMS_NETWORK: return 'fa-share-alt-square'; // fa-share-alt-square is very similiar to the hubzilla logo, but we should create our own logo class to use
case PERMS_SITE: return 'fa-sitemap';
case PERMS_CONTACTS: return 'fa-group';
- case PERMS_SPECIFIC:
- // Because we're describing the permissions of an item with an empty ACL,
- // the owner will be the only person able to see it if the permissions are
- // set to "only specified connections".
- return 'fa-eye-slash';
+ case PERMS_SPECIFIC: return 'fa-list';
case PERMS_AUTHED: return '';
case PERMS_PENDING: return '';
default: return '';
diff --git a/include/account.php b/include/account.php
index 5998609d4..caf12878e 100644
--- a/include/account.php
+++ b/include/account.php
@@ -11,7 +11,7 @@ require_once('include/text.php');
require_once('include/language.php');
require_once('include/datetime.php');
require_once('include/crypto.php');
-require_once('include/identity.php');
+require_once('include/channel.php');
function check_account_email($email) {
@@ -229,7 +229,7 @@ function verify_email_address($arr) {
$hash = random_string();
- $r = q("INSERT INTO register ( hash, created, uid, password, language ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
+ $r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
dbesc($hash),
dbesc(datetime_convert()),
intval($arr['account']['account_id']),
@@ -283,7 +283,7 @@ function send_reg_approval_email($arr) {
$hash = random_string();
- $r = q("INSERT INTO register ( hash, created, uid, password, language ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
+ $r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
dbesc($hash),
dbesc(datetime_convert()),
intval($arr['account']['account_id']),
@@ -387,7 +387,7 @@ function account_allow($hash) {
intval($register[0]['uid'])
);
- push_lang($register[0]['language']);
+ push_lang($register[0]['lang']);
$email_tpl = get_intltext_template("register_open_eml.tpl");
$email_tpl = replace_macros($email_tpl, array(
@@ -656,7 +656,8 @@ function account_service_class_allows($aid, $property, $usage = false) {
* @todo Should we merge this with account_service_class_fetch()?
*/
function service_class_fetch($uid, $property) {
- $a = get_app();
+
+
if($uid == local_channel()) {
$service_class = App::$account['account_service_class'];
}
diff --git a/include/acl_selectors.php b/include/acl_selectors.php
index ce0a32798..89d054e3b 100644
--- a/include/acl_selectors.php
+++ b/include/acl_selectors.php
@@ -11,13 +11,11 @@ require_once("include/PermissionDescription.php");
function group_select($selname,$selclass,$preselected = false,$size = 4) {
- $a = get_app();
-
$o = '';
$o .= "\r\n";
- $r = q("SELECT * FROM `groups` WHERE `deleted` = 0 AND `uid` = %d ORDER BY `name` ASC",
+ $r = q("SELECT * FROM `groups` WHERE `deleted` = 0 AND `uid` = %d ORDER BY `gname` ASC",
intval(local_channel())
);
@@ -34,7 +32,7 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) {
$selected = " selected=\"selected\" ";
else
$selected = '';
- $trimmed = mb_substr($rr['name'],0,12);
+ $trimmed = mb_substr($rr['gname'],0,12);
$o .= "$trimmed \r\n";
}
@@ -51,7 +49,6 @@ function group_select($selname,$selclass,$preselected = false,$size = 4) {
/* MicMee 20130114 function contact_selector no longer in use, sql table contact does no longer exist
function contact_selector($selname, $selclass, $preselected = false, $options) {
- $a = get_app();
$mutual = false;
$networks = null;
@@ -157,7 +154,6 @@ function contact_selector($selname, $selclass, $preselected = false, $options) {
function contact_select($selname, $selclass, $preselected = false, $size = 4, $privmail = false, $celeb = false, $privatenet = false, $tabindex = null) {
- $a = get_app();
$o = '';
@@ -230,14 +226,14 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
$allow_cid = $allow_gid = $deny_cid = $deny_gid = false;
$showall_origin = '';
$showall_icon = 'fa-globe';
-
+ $role = get_pconfig(local_channel(),'system','permissions_role');
if(! $emptyACL_description) {
$showall_caption = t('Visible to your default audience');
} else if (is_a($emptyACL_description, 'PermissionDescription')) {
$showall_caption = $emptyACL_description->get_permission_description();
- $showall_origin = $emptyACL_description->get_permission_origin_description();
+ $showall_origin = (($role === 'custom') ? $emptyACL_description->get_permission_origin_description() : '');
$showall_icon = $emptyACL_description->get_permission_icon();
} else {
@@ -269,9 +265,11 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
$tpl = get_markup_template("acl_selector.tpl");
$o = replace_macros($tpl, array(
'$showall' => $showall_caption,
+ '$onlyme' => t('Only me'),
'$showallOrigin' => $showall_origin,
'$showallIcon' => $showall_icon,
- '$showlimited' => t("Limit access:"),
+ '$select_label' => t('Who can see this?'),
+ '$showlimited' => t('Custom selection'),
'$showlimitedDesc' => t('Select "Show" to allow viewing. "Don\'t show" lets you override and limit the scope of "Show".'),
'$show' => t("Show"),
'$hide' => t("Don't show"),
diff --git a/include/activities.php b/include/activities.php
index 9ba191391..3271db993 100644
--- a/include/activities.php
+++ b/include/activities.php
@@ -1,7 +1,6 @@
nuke();
return api_apply_template("user", $type, array('$user' => null));
}
@@ -514,7 +512,7 @@ require_once('include/api_auth.php');
return false;
}
- require_once('include/identity.php');
+ require_once('include/channel.php');
json_return_and_die(identity_basic_export(api_user(),(($_REQUEST['posts']) ? intval($_REQUEST['posts']) : 0 )));
}
@@ -556,7 +554,7 @@ require_once('include/api_auth.php');
dbesc($_REQUEST['file_id'])
);
if($r) {
- unset($r[0]['data']);
+ unset($r[0]['content']);
$ret = array('attach' => $r[0]);
json_return_and_die($ret);
}
@@ -582,21 +580,21 @@ require_once('include/api_auth.php');
$length = intval($ptr['filesize']);
if($ptr['is_dir'])
- $ptr['data'] = '';
+ $ptr['content'] = '';
elseif(! intval($r[0]['os_storage'])) {
$ptr['start'] = $start;
- $x = substr(dbunescbin($ptr['data'],$start,$length));
+ $x = substr(dbunescbin($ptr['content'],$start,$length));
$ptr['length'] = strlen($x);
- $ptr['data'] = base64_encode($x);
+ $ptr['content'] = base64_encode($x);
}
else {
- $fp = fopen(dbunescbin($ptr['data']),'r');
+ $fp = fopen(dbunescbin($ptr['content']),'r');
if($fp) {
$seek = fseek($fp,$start,SEEK_SET);
$x = fread($fp,$length);
$ptr['start'] = $start;
$ptr['length'] = strlen($x);
- $ptr['data'] = base64_encode($x);
+ $ptr['content'] = base64_encode($x);
}
}
@@ -619,11 +617,11 @@ require_once('include/api_auth.php');
);
if($r) {
if($r[0]['is_dir'])
- $r[0]['data'] = '';
+ $r[0]['content'] = '';
elseif(intval($r[0]['os_storage']))
- $r[0]['data'] = base64_encode(file_get_contents(dbunescbin($r[0]['data'])));
+ $r[0]['content'] = base64_encode(file_get_contents(dbunescbin($r[0]['content'])));
else
- $r[0]['data'] = base64_encode(dbunescbin($r[0]['data']));
+ $r[0]['content'] = base64_encode(dbunescbin($r[0]['content']));
$ret = array('attach' => $r[0]);
json_return_and_die($ret);
@@ -649,16 +647,16 @@ require_once('include/api_auth.php');
if (api_user()===false) return false;
if(! $_REQUEST['photo_id']) return false;
$scale = ((array_key_exists('scale',$_REQUEST)) ? intval($_REQUEST['scale']) : 0);
- $r = q("select * from photo where uid = %d and resource_id = '%s' and scale = %d limit 1",
+ $r = q("select * from photo where uid = %d and resource_id = '%s' and imgscale = %d limit 1",
intval(local_channel()),
dbesc($_REQUEST['photo_id']),
intval($scale)
);
if($r) {
- $data = dbunescbin($r[0]['data']);
+ $data = dbunescbin($r[0]['content']);
if(array_key_exists('os_storage',$r[0]) && intval($r[0]['os_storage']))
$data = file_get_contents($data);
- $r[0]['data'] = base64_encode($data);
+ $r[0]['content'] = base64_encode($data);
$ret = array('photo' => $r[0]);
$i = q("select id from item where uid = %d and resource_type = 'photo' and resource_id = '%s' limit 1",
intval(local_channel()),
@@ -1904,13 +1902,17 @@ require_once('include/api_auth.php');
//logger('api_format_items: ' . print_r($user_info,true));
- $a = get_app();
$ret = array();
+ $x = array('items' => $r,'api_user' => api_user(),'user_info' => $user_info);
+ call_hooks('api_format_items',$x);
+ $r = $x['items'];
+
if(! $r)
return $ret;
foreach($r as $item) {
+
localize_item($item);
$status_user = (($item['author_xchan']==$user_info['guid'])?$user_info: api_item_get_user($a,$item));
@@ -2107,10 +2109,10 @@ require_once('include/api_auth.php');
'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl,
'shorturllength' => '30',
'hubzilla' => array(
- 'PLATFORM_NAME' => Zotlabs\Project\System::get_platform_name(),
- 'STD_VERSION' => Zotlabs\Project\System::get_project_version(),
+ 'PLATFORM_NAME' => Zotlabs\Lib\System::get_platform_name(),
+ 'STD_VERSION' => Zotlabs\Lib\System::get_project_version(),
'ZOT_REVISION' => ZOT_REVISION,
- 'DB_UPDATE_VERSION' => Zotlabs\Project\System::get_update_version()
+ 'DB_UPDATE_VERSION' => Zotlabs\Lib\System::get_update_version()
)
));
@@ -2143,12 +2145,12 @@ require_once('include/api_auth.php');
if($type === 'xml') {
header("Content-type: application/xml");
- echo '' . "\r\n" . '' . Zotlabs\Project\System::get_project_version() . ' ' . "\r\n";
+ echo '' . "\r\n" . '' . Zotlabs\Lib\System::get_project_version() . ' ' . "\r\n";
killme();
}
elseif($type === 'json') {
header("Content-type: application/json");
- echo '"' . Zotlabs\Project\System::get_project_version() . '"';
+ echo '"' . Zotlabs\Lib\System::get_project_version() . '"';
killme();
}
}
diff --git a/include/apps.php b/include/apps.php
deleted file mode 100644
index 7439be6d4..000000000
--- a/include/apps.php
+++ /dev/null
@@ -1,658 +0,0 @@
- $v) {
- if(strpos($v,'http') === 0)
- $ret[$k] = zid($v);
- }
-
- if(array_key_exists('desc',$ret))
- $ret['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['desc']);
-
- if(array_key_exists('target',$ret))
- $ret['target'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['target']);
-
- if(array_key_exists('requires',$ret)) {
- $requires = explode(',',$ret['requires']);
- foreach($requires as $require) {
- $require = trim(strtolower($require));
- switch($require) {
- case 'nologin':
- if(local_channel())
- unset($ret);
- break;
- case 'admin':
- if(! is_site_admin())
- unset($ret);
- break;
- case 'local_channel':
- if(! local_channel())
- unset($ret);
- break;
- case 'public_profile':
- if(! is_public_profile())
- unset($ret);
- break;
- case 'observer':
- if(! $observer)
- unset($ret);
- break;
- default:
- if(! (local_channel() && feature_enabled(local_channel(),$require)))
- unset($ret);
- break;
-
- }
- }
- }
- if($ret) {
- if($translate)
- translate_system_apps($ret);
- return $ret;
- }
- return false;
-}
-
-
-function translate_system_apps(&$arr) {
- $apps = array(
- 'Site Admin' => t('Site Admin'),
- 'Bug Report' => t('Bug Report'),
- 'View Bookmarks' => t('View Bookmarks'),
- 'My Chatrooms' => t('My Chatrooms'),
- 'Connections' => t('Connections'),
- 'Firefox Share' => t('Firefox Share'),
- 'Remote Diagnostics' => t('Remote Diagnostics'),
- 'Suggest Channels' => t('Suggest Channels'),
- 'Login' => t('Login'),
- 'Channel Manager' => t('Channel Manager'),
- 'Grid' => t('Grid'),
- 'Settings' => t('Settings'),
- 'Files' => t('Files'),
- 'Webpages' => t('Webpages'),
- 'Channel Home' => t('Channel Home'),
- 'View Profile' => t('View Profile'),
- 'Photos' => t('Photos'),
- 'Events' => t('Events'),
- 'Directory' => t('Directory'),
- 'Help' => t('Help'),
- 'Mail' => t('Mail'),
- 'Mood' => t('Mood'),
- 'Poke' => t('Poke'),
- 'Chat' => t('Chat'),
- 'Search' => t('Search'),
- 'Probe' => t('Probe'),
- 'Suggest' => t('Suggest'),
- 'Random Channel' => t('Random Channel'),
- 'Invite' => t('Invite'),
- 'Features' => t('Features'),
- 'Language' => t('Language'),
- 'Post' => t('Post'),
- 'Profile Photo' => t('Profile Photo')
- );
-
- if(array_key_exists($arr['name'],$apps))
- $arr['name'] = $apps[$arr['name']];
-
-}
-
-
-// papp is a portable app
-
-function app_render($papp,$mode = 'view') {
-
- /**
- * modes:
- * view: normal mode for viewing an app via bbcode from a conversation or page
- * provides install/update button if you're logged in locally
- * list: normal mode for viewing an app on the app page
- * no buttons are shown
- * edit: viewing the app page in editing mode provides a delete button
- */
-
- $installed = false;
-
- if(! $papp)
- return;
-
- if(! $papp['photo'])
- $papp['photo'] = z_root() . '/' . get_default_profile_photo(80);
-
-
-
- $papp['papp'] = papp_encode($papp);
-
- if(! strstr($papp['url'],'://'))
- $papp['url'] = z_root() . ((strpos($papp['url'],'/') === 0) ? '' : '/') . $papp['url'];
-
- foreach($papp as $k => $v) {
- if(strpos($v,'http') === 0 && $k != 'papp')
- $papp[$k] = zid($v);
- if($k === 'desc')
- $papp['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$papp['desc']);
-
- if($k === 'requires') {
- $requires = explode(',',$v);
- foreach($requires as $require) {
- $require = trim(strtolower($require));
- switch($require) {
- case 'nologin':
- if(local_channel())
- return '';
- break;
- case 'admin':
- if(! is_site_admin())
- return '';
- break;
- case 'local_channel':
- if(! local_channel())
- return '';
- break;
- case 'public_profile':
- if(! is_public_profile())
- return '';
- break;
- case 'observer':
- $observer = App::get_observer();
- if(! $observer)
- return '';
- break;
- default:
- if(! (local_channel() && feature_enabled(local_channel(),$require)))
- return '';
- break;
-
- }
- }
-
- }
- }
-
- $hosturl = '';
-
- if(local_channel()) {
- $installed = app_installed(local_channel(),$papp);
- $hosturl = z_root() . '/';
- }
- elseif(remote_channel()) {
- $observer = App::get_observer();
- if($observer && $observer['xchan_network'] === 'zot') {
- // some folks might have xchan_url redirected offsite, use the connurl
- $x = parse_url($observer['xchan_connurl']);
- if($x) {
- $hosturl = $x['scheme'] . '://' . $x['host'] . '/';
- }
- }
- }
-
- $install_action = (($installed) ? t('Update') : t('Install'));
-
- return replace_macros(get_markup_template('app.tpl'),array(
- '$app' => $papp,
- '$hosturl' => $hosturl,
- '$purchase' => (($papp['page'] && (! $installed)) ? t('Purchase') : ''),
- '$install' => (($hosturl && $mode == 'view') ? $install_action : ''),
- '$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
- '$delete' => ((local_channel() && $installed && $mode == 'edit') ? t('Delete') : '')
- ));
-}
-
-
-function app_install($uid,$app) {
- $app['uid'] = $uid;
-
- if(app_installed($uid,$app))
- $x = app_update($app);
- else
- $x = app_store($app);
-
- if($x['success']) {
- $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
- dbesc($x['app_id']),
- intval($uid)
- );
- if($r) {
- if(! $r[0]['app_system']) {
- if($app['categories'] && (! $app['term'])) {
- $r[0]['term'] = q("select * from term where otype = %d and oid = d",
- intval(TERM_OBJ_APP),
- intval($r[0]['id'])
- );
- build_sync_packet($uid,array('app' => $r[0]));
- }
- }
- }
- return $x['app_id'];
- }
- return false;
-}
-
-function app_destroy($uid,$app) {
-
-
- if($uid && $app['guid']) {
-
- $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
- dbesc($app['guid']),
- intval($uid)
- );
- if($x) {
- $x[0]['app_deleted'] = 1;
- q("delete from term where otype = %d and oid = %d",
- intval(TERM_OBJ_APP),
- intval($x[0]['id'])
- );
- if($x[0]['app_system']) {
- $r = q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d",
- dbesc($app['guid']),
- intval($uid)
- );
- }
- else {
- $r = q("delete from app where app_id = '%s' and app_channel = %d",
- dbesc($app['guid']),
- intval($uid)
- );
-
- // we don't sync system apps - they may be completely different on the other system
- build_sync_packet($uid,array('app' => $x));
- }
- }
- }
-}
-
-
-function app_installed($uid,$app) {
-
- $r = q("select id from app where app_id = '%s' and app_version = '%s' and app_channel = %d limit 1",
- dbesc((array_key_exists('guid',$app)) ? $app['guid'] : ''),
- dbesc((array_key_exists('version',$app)) ? $app['version'] : ''),
- intval($uid)
- );
- return(($r) ? true : false);
-
-}
-
-
-function app_list($uid, $deleted = false, $cat = '') {
- if($deleted)
- $sql_extra = " and app_deleted = 1 ";
- else
- $sql_extra = " and app_deleted = 0 ";
-
- if($cat) {
- $r = q("select oid from term where otype = %d and term = '%s'",
- intval(TERM_OBJ_APP),
- dbesc($cat)
- );
- if(! $r)
- return $r;
- $sql_extra .= " and app.id in ( ";
- $s = '';
- foreach($r as $rr) {
- if($s)
- $s .= ',';
- $s .= intval($rr['oid']);
- }
- $sql_extra .= $s . ') ';
- }
-
- $r = q("select * from app where app_channel = %d $sql_extra order by app_name asc",
- intval($uid)
- );
- if($r) {
- for($x = 0; $x < count($r); $x ++) {
- if(! $r[$x]['app_system'])
- $r[$x]['type'] = 'personal';
- $r[$x]['term'] = q("select * from term where otype = %d and oid = %d",
- intval(TERM_OBJ_APP),
- intval($r[$x]['id'])
- );
- }
- }
- return($r);
-}
-
-
-function app_decode($s) {
- $x = base64_decode(str_replace(array(' ',"\r","\n",' '),array('','','',''),$s));
- return json_decode($x,true);
-}
-
-
-function app_store($arr) {
-
- // logger('app_store: ' . print_r($arr,true));
-
- $darray = array();
- $ret = array('success' => false);
-
- $darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : '');
- $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0);
-
- if((! $darray['app_url']) || (! $darray['app_channel']))
- return $ret;
-
- if($arr['photo'] && ! strstr($arr['photo'],z_root())) {
- $x = import_xchan_photo($arr['photo'],get_observer_hash(),true);
- $arr['photo'] = $x[1];
- }
-
-
- $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : random_string(). '.' . App::get_hostname());
- $darray['app_sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
- $darray['app_author'] = ((x($arr,'author')) ? $arr['author'] : get_observer_hash());
- $darray['app_name'] = ((x($arr,'name')) ? escape_tags($arr['name']) : t('Unknown'));
- $darray['app_desc'] = ((x($arr,'desc')) ? escape_tags($arr['desc']) : '');
- $darray['app_photo'] = ((x($arr,'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80));
- $darray['app_version'] = ((x($arr,'version')) ? escape_tags($arr['version']) : '');
- $darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : '');
- $darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : '');
- $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : '');
- $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : '');
- $darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0);
- $darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0);
-
- $created = datetime_convert();
-
- $r = q("insert into app ( app_id, app_sig, app_author, app_name, app_desc, app_url, app_photo, app_version, app_channel, app_addr, app_price, app_page, app_requires, app_created, app_edited, app_system, app_deleted ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d )",
- dbesc($darray['app_id']),
- dbesc($darray['app_sig']),
- dbesc($darray['app_author']),
- dbesc($darray['app_name']),
- dbesc($darray['app_desc']),
- dbesc($darray['app_url']),
- dbesc($darray['app_photo']),
- dbesc($darray['app_version']),
- intval($darray['app_channel']),
- dbesc($darray['app_addr']),
- dbesc($darray['app_price']),
- dbesc($darray['app_page']),
- dbesc($darray['app_requires']),
- dbesc($created),
- dbesc($created),
- intval($darray['app_system']),
- intval($darray['app_deleted'])
- );
- if($r) {
- $ret['success'] = true;
- $ret['app_id'] = $darray['app_id'];
- }
- if($arr['categories']) {
- $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
- dbesc($darray['app_id']),
- intval($darray['app_channel'])
- );
- $y = explode(',',$arr['categories']);
- if($y) {
- foreach($y as $t) {
- $t = trim($t);
- if($t) {
- store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t)));
- }
- }
- }
- }
-
- return $ret;
-}
-
-
-function app_update($arr) {
-
- $darray = array();
- $ret = array('success' => false);
-
- $darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : '');
- $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0);
- $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : 0);
-
- if((! $darray['app_url']) || (! $darray['app_channel']) || (! $darray['app_id']))
- return $ret;
-
- if($arr['photo'] && ! strstr($arr['photo'],z_root())) {
- $x = import_xchan_photo($arr['photo'],get_observer_hash(),true);
- $arr['photo'] = $x[1];
- }
-
- $darray['app_sig'] = ((x($arr,'sig')) ? $arr['sig'] : '');
- $darray['app_author'] = ((x($arr,'author')) ? $arr['author'] : get_observer_hash());
- $darray['app_name'] = ((x($arr,'name')) ? escape_tags($arr['name']) : t('Unknown'));
- $darray['app_desc'] = ((x($arr,'desc')) ? escape_tags($arr['desc']) : '');
- $darray['app_photo'] = ((x($arr,'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80));
- $darray['app_version'] = ((x($arr,'version')) ? escape_tags($arr['version']) : '');
- $darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : '');
- $darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : '');
- $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : '');
- $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : '');
- $darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0);
- $darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0);
-
- $edited = datetime_convert();
-
- $r = q("update app set app_sig = '%s', app_author = '%s', app_name = '%s', app_desc = '%s', app_url = '%s', app_photo = '%s', app_version = '%s', app_addr = '%s', app_price = '%s', app_page = '%s', app_requires = '%s', app_edited = '%s', app_system = %d, app_deleted = %d where app_id = '%s' and app_channel = %d",
- dbesc($darray['app_sig']),
- dbesc($darray['app_author']),
- dbesc($darray['app_name']),
- dbesc($darray['app_desc']),
- dbesc($darray['app_url']),
- dbesc($darray['app_photo']),
- dbesc($darray['app_version']),
- dbesc($darray['app_addr']),
- dbesc($darray['app_price']),
- dbesc($darray['app_page']),
- dbesc($darray['app_requires']),
- dbesc($edited),
- intval($darray['app_system']),
- intval($darray['app_deleted']),
- dbesc($darray['app_id']),
- intval($darray['app_channel'])
- );
- if($r) {
- $ret['success'] = true;
- $ret['app_id'] = $darray['app_id'];
- }
-
- $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
- dbesc($darray['app_id']),
- intval($darray['app_channel'])
- );
- if($x) {
- q("delete from term where otype = %d and oid = %d",
- intval(TERM_OBJ_APP),
- intval($x[0]['id'])
- );
- if($arr['categories']) {
- $y = explode(',',$arr['categories']);
- if($y) {
- foreach($y as $t) {
- $t = trim($t);
- if($t) {
- store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t)));
- }
- }
- }
- }
- }
-
- return $ret;
-
-}
-
-
-function app_encode($app,$embed = false) {
-
- $ret = array();
-
- $ret['type'] = 'personal';
-
- if($app['app_id'])
- $ret['guid'] = $app['app_id'];
-
- if($app['app_id'])
- $ret['guid'] = $app['app_id'];
-
- if($app['app_sig'])
- $ret['sig'] = $app['app_sig'];
-
- if($app['app_author'])
- $ret['author'] = $app['app_author'];
-
- if($app['app_name'])
- $ret['name'] = $app['app_name'];
-
- if($app['app_desc'])
- $ret['desc'] = $app['app_desc'];
-
- if($app['app_url'])
- $ret['url'] = $app['app_url'];
-
- if($app['app_photo'])
- $ret['photo'] = $app['app_photo'];
-
- if($app['app_version'])
- $ret['version'] = $app['app_version'];
-
- if($app['app_addr'])
- $ret['addr'] = $app['app_addr'];
-
- if($app['app_price'])
- $ret['price'] = $app['app_price'];
-
- if($app['app_page'])
- $ret['page'] = $app['app_page'];
-
- if($app['app_requires'])
- $ret['requires'] = $app['app_requires'];
-
- if($app['app_system'])
- $ret['system'] = $app['app_system'];
-
- if($app['app_deleted'])
- $ret['deleted'] = $app['app_deleted'];
-
- if($app['term']) {
- $s = '';
- foreach($app['term'] as $t) {
- if($s)
- $s .= ',';
- $s .= $t['term'];
- }
- $ret['categories'] = $s;
- }
-
-
- if(! $embed)
- return $ret;
-
- if(array_key_exists('categories',$ret))
- unset($ret['categories']);
-
- $j = json_encode($ret);
- return '[app]' . chunk_split(base64_encode($j),72,"\n") . '[/app]';
-
-}
-
-
-function papp_encode($papp) {
- return chunk_split(base64_encode(json_encode($papp)),72,"\n");
-
-}
-
-
diff --git a/include/attach.php b/include/attach.php
index ae4681994..78efde51f 100644
--- a/include/attach.php
+++ b/include/attach.php
@@ -720,7 +720,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$edited = $created;
if($options === 'replace') {
- $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', filesize = %d, os_storage = %d, is_photo = %d, data = '%s', edited = '%s' where id = %d and uid = %d",
+ $r = q("update attach set filename = '%s', filetype = '%s', folder = '%s', filesize = %d, os_storage = %d, is_photo = %d, content = '%s', edited = '%s' where id = %d and uid = %d",
dbesc($filename),
dbesc($mimetype),
dbesc($folder_hash),
@@ -734,7 +734,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
);
}
elseif($options === 'revise') {
- $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
+ $r = q("insert into attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, content, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
intval($x[0]['aid']),
intval($channel_id),
@@ -775,7 +775,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
}
else {
- $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, data, created, edited, allow_cid, allow_gid,deny_cid, deny_gid )
+ $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, folder, filesize, revision, os_storage, is_photo, content, created, edited, allow_cid, allow_gid,deny_cid, deny_gid )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
intval($channel['channel_account_id']),
intval($channel_id),
@@ -1032,7 +1032,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
$created = datetime_convert();
- $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, folder, os_storage, is_dir, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
+ $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, filetype, filesize, revision, folder, os_storage, is_dir, content, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', %d, %d, '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
intval($channel['channel_account_id']),
intval($channel_id),
@@ -1275,16 +1275,16 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
// delete a file from filesystem
if(intval($r[0]['os_storage'])) {
- $y = q("SELECT data FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
+ $y = q("SELECT content FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1",
dbesc($resource),
intval($channel_id)
);
if($y) {
- if(strpos($y[0]['data'],'store') === false)
- $f = 'store/' . $channel_address . '/' . $y[0]['data'];
+ if(strpos($y[0]['content'],'store') === false)
+ $f = 'store/' . $channel_address . '/' . $y[0]['content'];
else
- $f = $y[0]['data'];
+ $f = $y[0]['content'];
if(is_dir($f))
@rmdir($f);
@@ -1585,13 +1585,13 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
$arr['deny_gid'] = perms2str($u_arr_deny_gid);
$arr['item_private'] = $private;
$arr['verb'] = ACTIVITY_UPDATE;
- $arr['object'] = $u_jsonobject;
+ $arr['obj'] = $u_jsonobject;
$arr['body'] = '';
$post = item_store($arr);
$item_id = $post['item_id'];
if($item_id) {
- proc_run('php',"include/notifier.php","activity",$item_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$item_id));
}
call_hooks('post_local_end', $arr);
@@ -1620,14 +1620,14 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
$arr['deny_gid'] = perms2str($arr_deny_gid);
$arr['item_private'] = $private;
$arr['verb'] = (($update) ? ACTIVITY_UPDATE : ACTIVITY_POST);
- $arr['object'] = (($update) ? $u_jsonobject : $jsonobject);
+ $arr['obj'] = (($update) ? $u_jsonobject : $jsonobject);
$arr['body'] = '';
$post = item_store($arr);
$item_id = $post['item_id'];
if($item_id) {
- proc_run('php',"include/notifier.php","activity",$item_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','activity',$item_id));
}
call_hooks('post_local_end', $arr);
@@ -1854,21 +1854,19 @@ function attach_export_data($channel, $resource_id, $deleted = false) {
} while($hash_ptr);
-
-
$paths = array_reverse($paths);
$ret['attach'] = $paths;
if($attach_ptr['is_photo']) {
- $r = q("select * from photo where resource_id = '%s' and uid = %d order by scale asc",
+ $r = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale asc",
dbesc($resource_id),
intval($channel['channel_id'])
);
if($r) {
for($x = 0; $x < count($r); $x ++) {
- $r[$x]['data'] = base64_encode($r[$x]['data']);
+ $r[$x]['content'] = base64_encode($r[$x]['content']);
}
$ret['photo'] = $r;
}
diff --git a/include/auth.php b/include/auth.php
index 9643da8eb..01fcf0094 100644
--- a/include/auth.php
+++ b/include/auth.php
@@ -101,7 +101,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
// process logout request
$args = array('channel_id' => local_channel());
call_hooks('logging_out', $args);
- \Zotlabs\Web\Session::nuke();
+ App::$session->nuke();
info( t('Logged out.') . EOL);
goaway(z_root());
}
@@ -117,7 +117,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
intval(ACCOUNT_ROLE_ADMIN)
);
if($x) {
- \Zotlabs\Web\Session::new_cookie(60 * 60 * 24); // one day
+ App::$session->new_cookie(60 * 60 * 24); // one day
$_SESSION['last_login_date'] = datetime_convert();
unset($_SESSION['visitor_id']); // no longer a visitor
authenticate_success($x[0], true, true);
@@ -141,7 +141,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
if(x($_SESSION, 'uid') || x($_SESSION, 'account_id')) {
- Zotlabs\Web\Session::return_check();
+ App::$session->return_check();
$r = q("select * from account where account_id = %d limit 1",
intval($_SESSION['account_id'])
@@ -155,14 +155,14 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
}
if(strcmp(datetime_convert('UTC','UTC','now - 12 hours'), $_SESSION['last_login_date']) > 0 ) {
$_SESSION['last_login_date'] = datetime_convert();
- Zotlabs\Web\Session::extend_cookie();
+ App::$session->extend_cookie();
$login_refresh = true;
}
authenticate_success($r[0], false, false, false, $login_refresh);
}
else {
$_SESSION['account_id'] = 0;
- \Zotlabs\Web\Session::nuke();
+ App::$session->nuke();
goaway(z_root());
}
} // end logged in user returning
@@ -170,7 +170,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) &&
else {
if(isset($_SESSION)) {
- \Zotlabs\Web\Session::nuke();
+ App::$session->nuke();
}
// handle a fresh login request
@@ -242,11 +242,11 @@ else {
if($_POST['remember_me']) {
$_SESSION['remember_me'] = 1;
- \Zotlabs\Web\Session::new_cookie(31449600); // one year
+ App::$session->new_cookie(31449600); // one year
}
else {
$_SESSION['remember_me'] = 0;
- \Zotlabs\Web\Session::new_cookie(0); // 0 means delete on browser exit
+ App::$session->new_cookie(0); // 0 means delete on browser exit
}
// if we haven't failed up this point, log them in.
diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php
index 9167cb5ad..c7d0e56b1 100644
--- a/include/bb2diaspora.php
+++ b/include/bb2diaspora.php
@@ -479,8 +479,6 @@ function unescape_underscores_in_links($m) {
function format_event_diaspora($ev) {
- $a = get_app();
-
if(! ((is_array($ev)) && count($ev)))
return '';
diff --git a/include/bbcode.php b/include/bbcode.php
index fd2d2f97a..42741b392 100644
--- a/include/bbcode.php
+++ b/include/bbcode.php
@@ -165,11 +165,10 @@ function bb_parse_crypt($match) {
}
function bb_parse_app($match) {
- require_once('include/apps.php');
- $app = app_decode($match[1]);
+ $app = Zotlabs\Lib\Apps::app_decode($match[1]);
if ($app)
- return app_render($app);
+ return Zotlabs\Lib\Apps::app_render($app);
}
function bb_parse_element($match) {
@@ -276,7 +275,6 @@ function bb_location($match) {
* @return string HTML iframe with content of $match[1]
*/
function bb_iframe($match) {
- $a = get_app();
$sandbox = ((strpos($match[1], App::get_hostname())) ? ' sandbox="allow-scripts" ' : '');
@@ -450,8 +448,6 @@ function bb_sanitize_style($input) {
function bb_observer($Text) {
- $a = get_app();
-
$observer = App::get_observer();
if ((strpos($Text,'[/observer]') !== false) || (strpos($Text,'[/rpost]') !== false)) {
@@ -481,9 +477,12 @@ function bb_observer($Text) {
return $Text;
}
-
-
-
+function bb_code($match) {
+ if(strpos($match[0], " "))
+ return '' . trim($match[1]) . '
';
+ else
+ return '' . trim($match[1]) . '
';
+}
@@ -789,12 +788,9 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "$2 ", $Text);
}
- // Declare the format for [code] layout
- $CodeLayout = '$1
';
-
// Check for [code] text
if (strpos($Text,'[code]') !== false) {
- $Text = preg_replace("/\[code\](.*?)\[\/code\]/ism", "$CodeLayout", $Text);
+ $Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism", 'bb_code', $Text);
}
// Check for [spoiler] text
@@ -985,6 +981,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false)
$Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism",'',$Text);
$Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism",'',$Text);
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
+ $Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text);
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
diff --git a/include/identity.php b/include/channel.php
similarity index 87%
rename from include/identity.php
rename to include/channel.php
index 807f850db..087bd4162 100644
--- a/include/identity.php
+++ b/include/channel.php
@@ -1,6 +1,6 @@
PLATFORM_NAME, 'version' => STD_VERSION, 'database' => DB_UPDATE_VERSION, 'server_role' => Zotlabs\Project\System::get_server_role());
+ $ret['compatibility'] = array('project' => PLATFORM_NAME, 'version' => STD_VERSION, 'database' => DB_UPDATE_VERSION, 'server_role' => Zotlabs\Lib\System::get_server_role());
$r = q("select * from channel where channel_id = %d limit 1",
intval($channel_id)
@@ -550,18 +550,18 @@ function identity_basic_export($channel_id, $items = false) {
if($r)
$ret['config'] = $r;
- $r = q("select type, data, os_storage from photo where scale = 4 and photo_usage = %d and uid = %d limit 1",
+ $r = q("select mimetype, content, os_storage from photo where imgscale = 4 and photo_usage = %d and uid = %d limit 1",
intval(PHOTO_PROFILE),
intval($channel_id)
);
if($r) {
- $ret['photo'] = array('type' => $r[0]['type'], 'data' => (($r[0]['os_storage']) ? base64url_encode(file_get_contents($r[0]['data'])) : base64url_encode($r[0]['data'])));
+ $ret['photo'] = array('type' => $r[0]['mimetype'], 'data' => (($r[0]['os_storage']) ? base64url_encode(file_get_contents($r[0]['content'])) : base64url_encode($r[0]['content'])));
}
// All other term types will be included in items, if requested.
- $r = q("select * from term where type in (%d,%d) and uid = %d",
+ $r = q("select * from term where ttype in (%d,%d) and uid = %d",
intval(TERM_SAVEDSEARCH),
intval(TERM_THING),
intval($channel_id)
@@ -847,7 +847,7 @@ function profile_load(&$a, $nickname, $profile = '') {
$extra_fields = array();
- require_once('include/identity.php');
+ require_once('include/channel.php');
$profile_fields_basic = get_profile_fields_basic();
$profile_fields_advanced = get_profile_fields_advanced();
@@ -1004,8 +1004,6 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
call_hooks('profile_sidebar_enter', $profile);
- require_once('include/Contact.php');
-
if($show_connect) {
// This will return an empty string if we're already connected.
@@ -1110,156 +1108,12 @@ function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = fa
}
-/**
- * @FIXME or remove
- */
- function get_birthdays() {
-
- $o = '';
-
- if(! local_channel())
- return $o;
-
- $bd_format = t('g A l F d') ; // 8 AM Friday January 18
- $bd_short = t('F d');
-
- $r = q("SELECT `event`.*, `event`.`id` AS `eid`, `contact`.* FROM `event`
- LEFT JOIN `contact` ON `contact`.`id` = `event`.`cid`
- WHERE `event`.`uid` = %d AND `type` = 'birthday' AND `start` < '%s' AND `finish` > '%s'
- ORDER BY `start` ASC ",
- intval(local_channel()),
- dbesc(datetime_convert('UTC','UTC','now + 6 days')),
- dbesc(datetime_convert('UTC','UTC','now'))
- );
-
- if($r && count($r)) {
- $total = 0;
- $now = strtotime('now');
- $cids = array();
-
- $istoday = false;
- foreach($r as $rr) {
- if(strlen($rr['name']))
- $total ++;
- if((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now))
- $istoday = true;
- }
- $classtoday = $istoday ? ' birthday-today ' : '';
- if($total) {
- foreach($r as &$rr) {
- if(! strlen($rr['name']))
- continue;
-
- // avoid duplicates
-
- if(in_array($rr['cid'],$cids))
- continue;
- $cids[] = $rr['cid'];
-
- $today = (((strtotime($rr['start'] . ' +00:00') < $now) && (strtotime($rr['finish'] . ' +00:00') > $now)) ? true : false);
- $sparkle = '';
- $url = $rr['url'];
- if($rr['network'] === NETWORK_DFRN) {
- $sparkle = " sparkle";
- $url = z_root() . '/redir/' . $rr['cid'];
- }
-
- $rr['link'] = $url;
- $rr['title'] = $rr['name'];
- $rr['date'] = day_translate(datetime_convert('UTC', App::$timezone, $rr['start'], $rr['adjust'] ? $bd_format : $bd_short)) . (($today) ? ' ' . t('[today]') : '');
- $rr['startime'] = Null;
- $rr['today'] = $today;
- }
- }
- }
- $tpl = get_markup_template("birthdays_reminder.tpl");
- return replace_macros($tpl, array(
- '$baseurl' => z_root(),
- '$classtoday' => $classtoday,
- '$count' => $total,
- '$event_reminders' => t('Birthday Reminders'),
- '$event_title' => t('Birthdays this week:'),
- '$events' => $r,
- '$lbr' => '{', // raw brackets mess up if/endif macro processing
- '$rbr' => '}'
- ));
- }
-
-
-/**
- * @FIXME
- */
- function get_events() {
-
- require_once('include/bbcode.php');
-
- if(! local_channel())
- return $o;
-
- $bd_format = t('g A l F d') ; // 8 AM Friday January 18
- $bd_short = t('F d');
-
- $r = q("SELECT `event`.* FROM `event`
- WHERE `event`.`uid` = %d AND `type` != 'birthday' AND `start` < '%s' AND `start` > '%s'
- ORDER BY `start` ASC ",
- intval(local_channel()),
- dbesc(datetime_convert('UTC','UTC','now + 6 days')),
- dbesc(datetime_convert('UTC','UTC','now - 1 days'))
- );
-
- if($r && count($r)) {
- $now = strtotime('now');
- $istoday = false;
- foreach($r as $rr) {
- if(strlen($rr['name']))
- $total ++;
-
- $strt = datetime_convert('UTC',$rr['convert'] ? App::$timezone : 'UTC',$rr['start'],'Y-m-d');
- if($strt === datetime_convert('UTC',App::$timezone,'now','Y-m-d'))
- $istoday = true;
- }
- $classtoday = (($istoday) ? 'event-today' : '');
-
- foreach($r as &$rr) {
- if($rr['adjust'])
- $md = datetime_convert('UTC',App::$timezone,$rr['start'],'Y/m');
- else
- $md = datetime_convert('UTC','UTC',$rr['start'],'Y/m');
- $md .= "/#link-".$rr['id'];
-
- $title = substr(strip_tags(bbcode($rr['desc'])),0,32) . '... ';
- if(! $title)
- $title = t('[No description]');
-
- $strt = datetime_convert('UTC',$rr['convert'] ? App::$timezone : 'UTC',$rr['start']);
- $today = ((substr($strt,0,10) === datetime_convert('UTC',App::$timezone,'now','Y-m-d')) ? true : false);
-
- $rr['link'] = $md;
- $rr['title'] = $title;
- $rr['date'] = day_translate(datetime_convert('UTC', $rr['adjust'] ? App::$timezone : 'UTC', $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
- $rr['startime'] = $strt;
- $rr['today'] = $today;
- }
- }
-
- $tpl = get_markup_template("events_reminder.tpl");
- return replace_macros($tpl, array(
- '$baseurl' => z_root(),
- '$classtoday' => $classtoday,
- '$count' => count($r),
- '$event_reminders' => t('Event Reminders'),
- '$event_title' => t('Events this week:'),
- '$events' => $r,
- ));
- }
-
-
function advanced_profile(&$a) {
require_once('include/text.php');
if(! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),'view_profile'))
return '';
- if(App::$profile['name']) {
+ if(App::$profile['fullname']) {
$profile_fields_basic = get_profile_fields_basic();
$profile_fields_advanced = get_profile_fields_advanced();
@@ -1283,7 +1137,7 @@ function advanced_profile(&$a) {
$profile = array();
- $profile['fullname'] = array( t('Full Name:'), App::$profile['name'] ) ;
+ $profile['fullname'] = array( t('Full Name:'), App::$profile['fullname'] ) ;
if(App::$profile['gender']) $profile['gender'] = array( t('Gender:'), App::$profile['gender'] );
@@ -1331,8 +1185,8 @@ function advanced_profile(&$a) {
if(App::$profile['marital'])
$profile['marital'] = array( t('Status:'), App::$profile['marital']);
- if(App::$profile['with'])
- $profile['marital']['with'] = bbcode(App::$profile['with']);
+ if(App::$profile['partner'])
+ $profile['marital']['partner'] = bbcode(App::$profile['partner']);
if(strlen(App::$profile['howlong']) && App::$profile['howlong'] !== NULL_DATE) {
$profile['howlong'] = relative_date(App::$profile['howlong'], t('for %1$d %2$s'));
@@ -1372,7 +1226,7 @@ function advanced_profile(&$a) {
if($txt = prepare_text(App::$profile['romance'])) $profile['romance'] = array( t('Love/Romance:'), $txt);
- if($txt = prepare_text(App::$profile['work'])) $profile['work'] = array( t('Work/employment:'), $txt);
+ if($txt = prepare_text(App::$profile['employment'])) $profile['employment'] = array( t('Work/employment:'), $txt);
if($txt = prepare_text(App::$profile['education'])) $profile['education'] = array( t('School/education:'), $txt );
@@ -1439,7 +1293,7 @@ function get_my_address() {
function zid_init(&$a) {
$tmp_str = get_my_address();
if(validate_email($tmp_str)) {
- proc_run('php','include/gprobe.php',bin2hex($tmp_str));
+ Zotlabs\Daemon\Master::Summon(array('Gprobe',bin2hex($tmp_str)));
$arr = array('zid' => $tmp_str, 'url' => App::$cmd);
call_hooks('zid_init',$arr);
if(! local_channel()) {
@@ -1569,7 +1423,7 @@ function get_online_status($nick) {
$ret = array('result' => false);
- if(get_config('system','block_public') && ! local_channel() && ! remote_channel())
+ if(observer_prohibited())
return $ret;
$r = q("select channel_id, channel_hash from channel where channel_address = '%s' limit 1",
@@ -1660,7 +1514,7 @@ function get_profile_fields_basic($filter = 0) {
$profile_fields_basic = (($filter == 0) ? get_config('system','profile_fields_basic') : null);
if(! $profile_fields_basic)
- $profile_fields_basic = array('name','pdesc','chandesc','gender','dob','dob_tz','address','locality','region','postal_code','country_name','marital','sexual','homepage','hometown','keywords','about','contact');
+ $profile_fields_basic = array('fullname','pdesc','chandesc','gender','dob','dob_tz','address','locality','region','postal_code','country_name','marital','sexual','homepage','hometown','keywords','about','contact');
$x = array();
if($profile_fields_basic)
@@ -1675,7 +1529,7 @@ function get_profile_fields_advanced($filter = 0) {
$basic = get_profile_fields_basic($filter);
$profile_fields_advanced = (($filter == 0) ? get_config('system','profile_fields_advanced') : null);
if(! $profile_fields_advanced)
- $profile_fields_advanced = array('with','howlong','politic','religion','likes','dislikes','interest','channels','music','book','film','tv','romance','work','education');
+ $profile_fields_advanced = array('partner','howlong','politic','religion','likes','dislikes','interest','channels','music','book','film','tv','romance','employment','education');
$x = array();
if($basic)
@@ -1787,7 +1641,7 @@ function auto_channel_create($account_id) {
function get_cover_photo($channel_id,$format = 'bbcode', $res = PHOTO_RES_COVER_1200) {
- $r = q("select height, width, resource_id, type from photo where uid = %d and scale = %d and photo_usage = %d",
+ $r = q("select height, width, resource_id, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d",
intval($channel_id),
intval($res),
intval(PHOTO_COVER)
@@ -1810,8 +1664,8 @@ function get_cover_photo($channel_id,$format = 'bbcode', $res = PHOTO_RES_COVER_
default:
$output = array(
'width' => $r[0]['width'],
- 'height' => $r[0]['type'],
- 'type' => $r[0]['type'],
+ 'height' => $r[0]['height'],
+ 'type' => $r[0]['mimetype'],
'url' => $url
);
break;
@@ -1836,19 +1690,19 @@ function get_zcard($channel,$observer_hash = '',$args = array()) {
$width = 425;
$size = 'hz_small';
$cover_size = PHOTO_RES_COVER_425;
- $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']);
+ $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']);
}
elseif($maxwidth <= 900) {
$width = 900;
$size = 'hz_medium';
$cover_size = PHOTO_RES_COVER_850;
- $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']);
+ $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']);
}
elseif($maxwidth <= 1200) {
$width = 1200;
$size = 'hz_large';
$cover_size = PHOTO_RES_COVER_1200;
- $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
+ $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
}
// $scale = (float) $maxwidth / $width;
@@ -1858,7 +1712,7 @@ function get_zcard($channel,$observer_hash = '',$args = array()) {
$channel['channel_addr'] = $channel['channel_address'] . '@' . App::get_hostname();
$zcard = array('chan' => $channel);
- $r = q("select height, width, resource_id, scale, type from photo where uid = %d and scale = %d and photo_usage = %d",
+ $r = q("select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d",
intval($channel['channel_id']),
intval($cover_size),
intval(PHOTO_COVER)
@@ -1866,7 +1720,7 @@ function get_zcard($channel,$observer_hash = '',$args = array()) {
if($r) {
$cover = $r[0];
- $cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['scale'];
+ $cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale'];
}
else {
$cover = $pphoto;
@@ -1902,25 +1756,25 @@ function get_zcard_embed($channel,$observer_hash = '',$args = array()) {
$width = 425;
$size = 'hz_small';
$cover_size = PHOTO_RES_COVER_425;
- $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']);
+ $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']);
}
elseif($maxwidth <= 900) {
$width = 900;
$size = 'hz_medium';
$cover_size = PHOTO_RES_COVER_850;
- $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']);
+ $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']);
}
elseif($maxwidth <= 1200) {
$width = 1200;
$size = 'hz_large';
$cover_size = PHOTO_RES_COVER_1200;
- $pphoto = array('type' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
+ $pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']);
}
$channel['channel_addr'] = $channel['channel_address'] . '@' . App::get_hostname();
$zcard = array('chan' => $channel);
- $r = q("select height, width, resource_id, scale, type from photo where uid = %d and scale = %d and photo_usage = %d",
+ $r = q("select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d",
intval($channel['channel_id']),
intval($cover_size),
intval(PHOTO_COVER)
@@ -1928,7 +1782,7 @@ function get_zcard_embed($channel,$observer_hash = '',$args = array()) {
if($r) {
$cover = $r[0];
- $cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['scale'];
+ $cover['href'] = z_root() . '/photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale'];
}
else {
$cover = $pphoto;
@@ -1947,3 +1801,26 @@ function get_zcard_embed($channel,$observer_hash = '',$args = array()) {
return $o;
}
+
+
+function channelx_by_nick($nick) {
+ $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and channel_removed = 0 LIMIT 1",
+ dbesc($nick)
+ );
+ return(($r) ? $r[0] : false);
+}
+
+function channelx_by_hash($hash) {
+ $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_hash = '%s' and channel_removed = 0 LIMIT 1",
+ dbesc($hash)
+ );
+ return(($r) ? $r[0] : false);
+}
+
+function channelx_by_n($id) {
+ $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_id = %d and channel_removed = 0 LIMIT 1",
+ dbesc($id)
+ );
+ return(($r) ? $r[0] : false);
+}
+
diff --git a/include/chat.php b/include/chat.php
deleted file mode 100644
index 604402045..000000000
--- a/include/chat.php
+++ /dev/null
@@ -1,262 +0,0 @@
- false);
-
- $name = trim($arr['name']);
- if(! $name) {
- $ret['message'] = t('Missing room name');
- return $ret;
- }
-
- $r = q("select cr_id from chatroom where cr_uid = %d and cr_name = '%s' limit 1",
- intval($channel['channel_id']),
- dbesc($name)
- );
- if($r) {
- $ret['message'] = t('Duplicate room name');
- return $ret;
- }
-
- $r = q("select count(cr_id) as total from chatroom where cr_aid = %d",
- intval($channel['channel_account_id'])
- );
- if($r)
- $limit = service_class_fetch($channel['channel_id'], 'chatrooms');
-
- if(($r) && ($limit !== false) && ($r[0]['total'] >= $limit)) {
- $ret['message'] = upgrade_message();
- return $ret;
- }
-
- if(! array_key_exists('expire', $arr))
- $arr['expire'] = 120; // minutes, e.g. 2 hours
-
- $created = datetime_convert();
-
- $x = q("insert into chatroom ( cr_aid, cr_uid, cr_name, cr_created, cr_edited, cr_expire, allow_cid, allow_gid, deny_cid, deny_gid )
- values ( %d, %d , '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s' ) ",
- intval($channel['channel_account_id']),
- intval($channel['channel_id']),
- dbesc($name),
- dbesc($created),
- dbesc($created),
- intval($arr['expire']),
- dbesc($arr['allow_cid']),
- dbesc($arr['allow_gid']),
- dbesc($arr['deny_cid']),
- dbesc($arr['deny_gid'])
- );
-
- if($x)
- $ret['success'] = true;
-
- return $ret;
-}
-
-
-function chatroom_destroy($channel,$arr) {
-
- $ret = array('success' => false);
-
- if(intval($arr['cr_id']))
- $sql_extra = " and cr_id = " . intval($arr['cr_id']) . " ";
- elseif(trim($arr['cr_name']))
- $sql_extra = " and cr_name = '" . protect_sprintf(dbesc(trim($arr['cr_name']))) . "' ";
- else {
- $ret['message'] = t('Invalid room specifier.');
- return $ret;
- }
-
- $r = q("select * from chatroom where cr_uid = %d $sql_extra limit 1",
- intval($channel['channel_id'])
- );
- if(! $r) {
- $ret['message'] = t('Invalid room specifier.');
- return $ret;
- }
-
- build_sync_packet($channel['channel_id'],array('chatroom' => $r));
-
- q("delete from chatroom where cr_id = %d",
- intval($r[0]['cr_id'])
- );
- if($r[0]['cr_id']) {
- q("delete from chatpresence where cp_room = %d",
- intval($r[0]['cr_id'])
- );
- q("delete from chat where chat_room = %d",
- intval($r[0]['cr_id'])
- );
- }
-
- $ret['success'] = true;
- return $ret;
-}
-
-
-function chatroom_enter($observer_xchan, $room_id, $status, $client) {
-
- if(! $room_id || ! $observer_xchan)
- return;
-
- $r = q("select * from chatroom where cr_id = %d limit 1",
- intval($room_id)
- );
- if(! $r) {
- notice( t('Room not found.') . EOL);
- return false;
- }
- require_once('include/security.php');
- $sql_extra = permissions_sql($r[0]['cr_uid']);
-
- $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1",
- intval($room_id),
- intval($r[0]['cr_uid'])
- );
- if(! $x) {
- notice( t('Permission denied.') . EOL);
- return false;
- }
-
- $limit = service_class_fetch($r[0]['cr_uid'], 'chatters_inroom');
- if($limit !== false) {
- $y = q("select count(*) as total from chatpresence where cp_room = %d",
- intval($room_id)
- );
- if($y && $y[0]['total'] > $limit) {
- notice( t('Room is full') . EOL);
- return false;
- }
- }
-
- if(intval($x[0]['cr_expire'])) {
- $r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d",
- db_utcnow(),
- db_quoteinterval( intval($x[0]['cr_expire']) . ' MINUTE' ),
- intval($x[0]['cr_id'])
- );
- }
-
- $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d limit 1",
- dbesc($observer_xchan),
- intval($room_id)
- );
- if($r) {
- q("update chatpresence set cp_last = '%s' where cp_id = %d and cp_client = '%s'",
- dbesc(datetime_convert()),
- intval($r[0]['cp_id']),
- dbesc($client)
- );
- return true;
- }
-
- $r = q("insert into chatpresence ( cp_room, cp_xchan, cp_last, cp_status, cp_client )
- values ( %d, '%s', '%s', '%s', '%s' )",
- intval($room_id),
- dbesc($observer_xchan),
- dbesc(datetime_convert()),
- dbesc($status),
- dbesc($client)
- );
-
- return $r;
-}
-
-
-function chatroom_leave($observer_xchan, $room_id, $client) {
- if(! $room_id || ! $observer_xchan)
- return;
-
- $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d and cp_client = '%s' limit 1",
- dbesc($observer_xchan),
- intval($room_id),
- dbesc($client)
- );
- if($r) {
- q("delete from chatpresence where cp_id = %d",
- intval($r[0]['cp_id'])
- );
- }
-
- return true;
-}
-
-
-function chatroom_list($uid) {
- require_once('include/security.php');
- $sql_extra = permissions_sql($uid);
-
- $r = q("select allow_cid, allow_gid, deny_cid, deny_gid, cr_name, cr_expire, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name",
- intval($uid)
- );
-
- return $r;
-}
-
-function chatroom_list_count($uid) {
- require_once('include/security.php');
- $sql_extra = permissions_sql($uid);
-
- $r = q("select count(*) as total from chatroom where cr_uid = %d $sql_extra",
- intval($uid)
- );
-
- return $r[0]['total'];
-}
-
-/**
- * create a chat message via API.
- * It is the caller's responsibility to enter the room.
- */
-
-function chat_message($uid, $room_id, $xchan, $text) {
-
- $ret = array('success' => false);
-
- if(! $text)
- return;
-
- $sql_extra = permissions_sql($uid);
-
- $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra",
- intval($uid),
- intval($room_id)
- );
- if(! $r)
- return $ret;
-
- $arr = array(
- 'chat_room' => $room_id,
- 'chat_xchan' => $xchan,
- 'chat_text' => $text
- );
-
- call_hooks('chat_message', $arr);
-
- $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text )
- values( %d, '%s', '%s', '%s' )",
- intval($room_id),
- dbesc($xchan),
- dbesc(datetime_convert()),
- dbesc($arr['chat_text'])
- );
-
- $ret['success'] = true;
- return $ret;
-}
diff --git a/include/checksites.php b/include/checksites.php
deleted file mode 100644
index e9c08c202..000000000
--- a/include/checksites.php
+++ /dev/null
@@ -1,62 +0,0 @@
- 1) && ($argv[1]))
- $site_id = $argv[1];
-
- if($site_id)
- $sql_options = " and site_url = '" . dbesc($argv[1]) . "' ";
-
- $days = intval(get_config('system','sitecheckdays'));
- if($days < 1)
- $days = 30;
-
- $r = q("select * from site where site_dead = 0 and site_update < %s - INTERVAL %s and site_type = %d $sql_options ",
- db_utcnow(), db_quoteinterval($days . ' DAY'),
- intval(SITE_TYPE_ZOT)
- );
-
- if(! $r)
- return;
-
- foreach($r as $rr) {
- if(! strcasecmp($rr['site_url'],z_root()))
- continue;
-
- $x = ping_site($rr['site_url']);
- if($x['success']) {
- logger('checksites: ' . $rr['site_url']);
- q("update site set site_update = '%s' where site_url = '%s' ",
- dbesc(datetime_convert()),
- dbesc($rr['site_url'])
- );
- }
- else {
- logger('marking dead site: ' . $x['message']);
- q("update site set site_dead = 1 where site_url = '%s' ",
- dbesc($rr['site_url'])
- );
- }
- }
-
- return;
-}
-
-if (array_search(__file__,get_included_files())===0){
- checksites_run($argv,$argc);
- killme();
-}
diff --git a/include/cli_startup.php b/include/cli_startup.php
index a99164d4c..a4c1f629a 100644
--- a/include/cli_startup.php
+++ b/include/cli_startup.php
@@ -6,36 +6,7 @@ require_once('boot.php');
function cli_startup() {
- global $a, $db, $default_timezone;
-
- if(is_null($a)) {
- $a = new miniApp;
- }
-
- App::init();
-
- if(is_null($db)) {
- @include(".htconfig.php");
-
- $a->convert();
-
- if(! defined('UNO'))
- define('UNO', 0);
-
- App::$timezone = ((x($default_timezone)) ? $default_timezone : 'UTC');
- date_default_timezone_set(App::$timezone);
-
- require_once('include/dba/dba_driver.php');
- $db = dba_factory($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type);
- unset($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type);
- };
-
- \Zotlabs\Web\Session::init();
-
- load_config('system');
-
+ sys_boot();
App::set_baseurl(get_config('system','baseurl'));
- load_hooks();
-
}
\ No newline at end of file
diff --git a/include/cli_suggest.php b/include/cli_suggest.php
deleted file mode 100644
index 321ffd2e0..000000000
--- a/include/cli_suggest.php
+++ /dev/null
@@ -1,22 +0,0 @@
-config is used for hub specific configurations. It overrides the
* configurations from .htconfig file. The storage is of size TEXT.
* - pconfig is used for channel specific configurations and takes a
@@ -34,751 +30,102 @@
*
*/
-/**
- * @brief Loads the hub's configuration from database to a cached storage.
- *
- * Retrieve a category ($family) of config variables from database to a cached
- * storage in the global App::$config[$family].
- *
- * @param string $family
- * The category of the configuration value
- */
+
+use Zotlabs\Lib as Zlib;
+
function load_config($family) {
- global $a;
-
- if(! array_key_exists($family, App::$config))
- App::$config[$family] = array();
-
- if(! array_key_exists('config_loaded', App::$config[$family])) {
- $r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family));
- if($r !== false) {
- if($r) {
- foreach($r as $rr) {
- $k = $rr['k'];
- App::$config[$family][$k] = $rr['v'];
- }
- }
- App::$config[$family]['config_loaded'] = true;
- }
- }
+ Zlib\Config::Load($family);
}
-/**
- * @brief Get a particular config variable given the category name ($family)
- * and a key.
- *
- * Get a particular config variable from the given category ($family) and the
- * $key from a cached storage in App::$config[$family]. If a key is found in the
- * DB but does not exist in local config cache, pull it into the cache so we
- * do not have to hit the DB again for this item.
- *
- * Returns false if not set.
- *
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to query
- * @return mixed Return value or false on error or if not set
- */
function get_config($family, $key) {
- global $a;
-
- if((! array_key_exists($family, App::$config)) || (! array_key_exists('config_loaded', App::$config[$family])))
- load_config($family);
-
- if(array_key_exists('config_loaded', App::$config[$family])) {
- if(! array_key_exists($key, App::$config[$family])) {
- return false;
- }
- return ((! is_array(App::$config[$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$family][$key]))
- ? unserialize(App::$config[$family][$key])
- : App::$config[$family][$key]
- );
- }
- return false;
+ return Zlib\Config::Get($family,$key);
}
-/**
- * @brief Returns a value directly from the database configuration storage.
- *
- * This function queries directly the database and bypasses the chached storage
- * from get_config($family, $key).
- *
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to query
- * @return mixed
- */
-function get_config_from_storage($family, $key) {
- $ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1",
- dbesc($family),
- dbesc($key)
- );
- return $ret;
-}
-
-/**
- * @brief Sets a configuration value for the hub.
- *
- * Stores a config value ($value) in the category ($family) under the key ($key).
- *
- * @note Please do not store booleans - convert to 0/1 integer values!
- *
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to set
- * @param mixed $value
- * The value to store in the configuration
- * @return mixed
- * Return the set value, or false if the database update failed
- */
function set_config($family, $key, $value) {
- global $a;
-
- // manage array value
- $dbvalue = ((is_array($value)) ? serialize($value) : $value);
- $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
-
- if(get_config($family, $key) === false || (! get_config_from_storage($family, $key))) {
- $ret = q("INSERT INTO config ( cat, k, v ) VALUES ( '%s', '%s', '%s' ) ",
- dbesc($family),
- dbesc($key),
- dbesc($dbvalue)
- );
- if($ret) {
- App::$config[$family][$key] = $value;
- $ret = $value;
- }
- return $ret;
- }
-
- $ret = q("UPDATE config SET v = '%s' WHERE cat = '%s' AND k = '%s'",
- dbesc($dbvalue),
- dbesc($family),
- dbesc($key)
- );
-
- if($ret) {
- App::$config[$family][$key] = $value;
- $ret = $value;
- }
- return $ret;
+ return Zlib\Config::Set($family,$key,$value);
}
-/**
- * @brief Deletes the given key from the hub's configuration database.
- *
- * Removes the configured value from the stored cache in App::$config[$family]
- * and removes it from the database.
- *
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to delete
- * @return mixed
- */
function del_config($family, $key) {
- global $a;
- $ret = false;
-
- if(array_key_exists($family, App::$config) && array_key_exists($key, App::$config[$family]))
- unset(App::$config[$family][$key]);
- $ret = q("DELETE FROM config WHERE cat = '%s' AND k = '%s'",
- dbesc($family),
- dbesc($key)
- );
- return $ret;
+ return Zlib\Config::Delete($family,$key);
}
-
-/**
- * @brief Loads all configuration values of a channel into a cached storage.
- *
- * All configuration values of the given channel are stored in global cache
- * which is available under the global variable App::$config[$uid].
- *
- * @param string $uid
- * The channel_id
- * @return void|false Nothing or false if $uid is false
- */
function load_pconfig($uid) {
- global $a;
-
- if($uid === false)
- return false;
-
- if(! array_key_exists($uid, App::$config))
- App::$config[$uid] = array();
-
- $r = q("SELECT * FROM pconfig WHERE uid = %d",
- intval($uid)
- );
-
- if($r) {
- foreach($r as $rr) {
- $k = $rr['k'];
- $c = $rr['cat'];
- if(! array_key_exists($c, App::$config[$uid])) {
- App::$config[$uid][$c] = array();
- App::$config[$uid][$c]['config_loaded'] = true;
- }
- App::$config[$uid][$c][$k] = $rr['v'];
- }
- }
+ Zlib\PConfig::Load($uid);
}
-/**
- * @brief Get a particular channel's config variable given the category name
- * ($family) and a key.
- *
- * Get a particular channel's config value from the given category ($family)
- * and the $key from a cached storage in App::$config[$uid].
- *
- * Returns false if not set.
- *
- * @param string $uid
- * The channel_id
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to query
- * @param boolean $instore (deprecated, without function)
- * @return mixed Stored value or false if it does not exist
- */
function get_pconfig($uid, $family, $key, $instore = false) {
-// logger('include/config.php: get_pconfig() deprecated instore param used', LOGGER_DEBUG);
- global $a;
-
- if($uid === false)
- return false;
-
- if(! array_key_exists($uid, App::$config))
- load_pconfig($uid);
-
- if((! array_key_exists($family, App::$config[$uid])) || (! array_key_exists($key, App::$config[$uid][$family])))
- return false;
-
- return ((! is_array(App::$config[$uid][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$uid][$family][$key]))
- ? unserialize(App::$config[$uid][$family][$key])
- : App::$config[$uid][$family][$key]
- );
+ return Zlib\PConfig::Get($uid,$family,$key,$instore = false);
}
-/**
- * @brief Sets a configuration value for a channel.
- *
- * Stores a config value ($value) in the category ($family) under the key ($key)
- * for the channel_id $uid.
- *
- * @note Please do not store booleans - convert to 0/1 integer values!
- *
- * @param string $uid
- * The channel_id
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to set
- * @param string $value
- * The value to store
- * @return mixed Stored $value or false
- */
function set_pconfig($uid, $family, $key, $value) {
- global $a;
-
- // this catches subtle errors where this function has been called
- // with local_channel() when not logged in (which returns false)
- // and throws an error in array_key_exists below.
- // we provide a function backtrace in the logs so that we can find
- // and fix the calling function.
-
- if($uid === false) {
- btlogger('UID is FALSE!', LOGGER_NORMAL, LOG_ERR);
- return;
- }
-
- // manage array value
- $dbvalue = ((is_array($value)) ? serialize($value) : $value);
- $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
-
- if(get_pconfig($uid, $family, $key) === false) {
- if(! array_key_exists($uid, App::$config))
- App::$config[$uid] = array();
- if(! array_key_exists($family, App::$config[$uid]))
- App::$config[$uid][$family] = array();
-
- // keep a separate copy for all variables which were
- // set in the life of this page. We need this to
- // synchronise channel clones.
-
- if(! array_key_exists('transient', App::$config[$uid]))
- App::$config[$uid]['transient'] = array();
- if(! array_key_exists($family, App::$config[$uid]['transient']))
- App::$config[$uid]['transient'][$family] = array();
-
- App::$config[$uid][$family][$key] = $value;
- App::$config[$uid]['transient'][$family][$key] = $value;
-
- $ret = q("INSERT INTO pconfig ( uid, cat, k, v ) VALUES ( %d, '%s', '%s', '%s' ) ",
- intval($uid),
- dbesc($family),
- dbesc($key),
- dbesc($dbvalue)
- );
- if($ret)
- return $value;
-
- return $ret;
- }
-
- $ret = q("UPDATE pconfig SET v = '%s' WHERE uid = %d and cat = '%s' AND k = '%s'",
- dbesc($dbvalue),
- intval($uid),
- dbesc($family),
- dbesc($key)
- );
-
- // keep a separate copy for all variables which were
- // set in the life of this page. We need this to
- // synchronise channel clones.
-
- if(! array_key_exists('transient', App::$config[$uid]))
- App::$config[$uid]['transient'] = array();
- if(! array_key_exists($family, App::$config[$uid]['transient']))
- App::$config[$uid]['transient'][$family] = array();
-
- App::$config[$uid][$family][$key] = $value;
- App::$config[$uid]['transient'][$family][$key] = $value;
-
- if($ret)
- return $value;
-
- return $ret;
+ return Zlib\PConfig::Set($uid,$family,$key,$value);
}
-/**
- * @brief Deletes the given key from the channel's configuration.
- *
- * Removes the configured value from the stored cache in App::$config[$uid]
- * and removes it from the database.
- *
- * @param string $uid
- * The channel_id
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to delete
- * @return mixed
- */
function del_pconfig($uid, $family, $key) {
- global $a;
- $ret = false;
-
- if (x(App::$config[$uid][$family], $key))
- unset(App::$config[$uid][$family][$key]);
- $ret = q("DELETE FROM pconfig WHERE uid = %d AND cat = '%s' AND k = '%s'",
- intval($uid),
- dbesc($family),
- dbesc($key)
- );
-
- return $ret;
+ return Zlib\PConfig::Delete($uid,$family,$key);
}
-
-/**
- * @brief Loads a full xchan's configuration into a cached storage.
- *
- * All configuration values of the given observer hash are stored in global
- * cache which is available under the global variable App::$config[$xchan].
- *
- * @param string $xchan
- * The observer's hash
- * @return void|false Returns false if xchan is not set
- */
function load_xconfig($xchan) {
- global $a;
-
- if(! $xchan)
- return false;
-
- if(! array_key_exists($xchan, App::$config))
- App::$config[$xchan] = array();
-
- $r = q("SELECT * FROM xconfig WHERE xchan = '%s'",
- dbesc($xchan)
- );
-
- if($r) {
- foreach($r as $rr) {
- $k = $rr['k'];
- $c = $rr['cat'];
- if(! array_key_exists($c, App::$config[$xchan])) {
- App::$config[$xchan][$c] = array();
- App::$config[$xchan][$c]['config_loaded'] = true;
- }
- App::$config[$xchan][$c][$k] = $rr['v'];
- }
- }
+ Zlib\XConfig::Load($xchan);
}
-/**
- * @brief Get a particular observer's config variable given the category
- * name ($family) and a key.
- *
- * Get a particular observer's config value from the given category ($family)
- * and the $key from a cached storage in App::$config[$xchan].
- *
- * Returns false if not set.
- *
- * @param string $xchan
- * The observer's hash
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to query
- * @return mixed Stored $value or false if it does not exist
- */
function get_xconfig($xchan, $family, $key) {
- global $a;
-
- if(! $xchan)
- return false;
-
- if(! array_key_exists($xchan, App::$config))
- load_xconfig($xchan);
-
- if((! array_key_exists($family, App::$config[$xchan])) || (! array_key_exists($key, App::$config[$xchan][$family])))
- return false;
-
- return ((! is_array(App::$config[$xchan][$family][$key])) && (preg_match('|^a:[0-9]+:{.*}$|s', App::$config[$xchan][$family][$key]))
- ? unserialize(App::$config[$xchan][$family][$key])
- : App::$config[$xchan][$family][$key]
- );
+ return Zlib\XConfig::Get($xchan,$family,$key);
}
-/**
- * @brief Sets a configuration value for an observer.
- *
- * Stores a config value ($value) in the category ($family) under the key ($key)
- * for the observer's $xchan hash.
- *
- * @note Please do not store booleans - convert to 0/1 integer values!
- *
- * @param string $xchan
- * The observer's hash
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to set
- * @param string $value
- * The value to store
- * @return mixed Stored $value or false
- */
function set_xconfig($xchan, $family, $key, $value) {
- global $a;
-
- // manage array value
- $dbvalue = ((is_array($value)) ? serialize($value) : $value);
- $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
-
- if(get_xconfig($xchan, $family, $key) === false) {
- if(! array_key_exists($xchan, App::$config))
- App::$config[$xchan] = array();
- if(! array_key_exists($family, App::$config[$xchan]))
- App::$config[$xchan][$family] = array();
-
- App::$config[$xchan][$family][$key] = $value;
- $ret = q("INSERT INTO xconfig ( xchan, cat, k, v ) VALUES ( '%s', '%s', '%s', '%s' ) ",
- dbesc($xchan),
- dbesc($family),
- dbesc($key),
- dbesc($dbvalue)
- );
- if($ret)
- return $value;
- return $ret;
- }
-
- $ret = q("UPDATE xconfig SET v = '%s' WHERE xchan = '%s' and cat = '%s' AND k = '%s'",
- dbesc($dbvalue),
- dbesc($xchan),
- dbesc($family),
- dbesc($key)
- );
-
- App::$config[$xchan][$family][$key] = $value;
-
- if($ret)
- return $value;
- return $ret;
+ return Zlib\XConfig::Set($xchan,$family,$key,$value);
}
-/**
- * @brief Deletes the given key from the observer's config.
- *
- * Removes the configured value from the stored cache in App::$config[$xchan]
- * and removes it from the database.
- *
- * @param string $xchan
- * The observer's hash
- * @param string $family
- * The category of the configuration value
- * @param string $key
- * The configuration key to delete
- * @return mixed
- */
function del_xconfig($xchan, $family, $key) {
- global $a;
- $ret = false;
-
- if(x(App::$config[$xchan][$family], $key))
- unset(App::$config[$xchan][$family][$key]);
- $ret = q("DELETE FROM xconfig WHERE xchan = '%s' AND cat = '%s' AND k = '%s'",
- dbesc($xchan),
- dbesc($family),
- dbesc($key)
- );
- return $ret;
+ return Zlib\XConfig::Delete($xchan,$family,$key);
}
-
-// account configuration storage is built on top of the under-utilised xconfig
-
function load_aconfig($account_id) {
- load_xconfig('a_' . $account_id);
+ Zlib\AConfig::Load($account_id);
}
function get_aconfig($account_id, $family, $key) {
- return get_xconfig('a_' . $account_id, $family, $key);
+ return Zlib\AConfig::Get($account_id, $family, $key);
}
function set_aconfig($account_id, $family, $key, $value) {
- return set_xconfig('a_' . $account_id, $family, $key, $value);
+ return Zlib\AConfig::Set($account_id, $family, $key, $value);
}
function del_aconfig($account_id, $family, $key) {
- return del_xconfig('a_' . $account_id, $family, $key);
+ return Zlib\AConfig::Delete($account_id, $family, $key);
}
function load_abconfig($chash,$xhash) {
- $r = q("select * from abconfig where chan = '%s' and xchan = '%s'",
- dbesc($chash),
- dbesc($xhash)
- );
- return $r;
+ Zlib\AbConfig::Load($chash,$xhash);
}
function get_abconfig($chash,$xhash,$family,$key) {
- $r = q("select * from abconfig where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' limit 1",
- dbesc($chash),
- dbesc($xhash),
- dbesc($family),
- dbesc($key)
- );
- if($r) {
- return ((preg_match('|^a:[0-9]+:{.*}$|s', $r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
- }
- return false;
+ return Zlib\AbConfig::Get($chash,$xhash,$family,$key);
}
-
function set_abconfig($chash,$xhash,$family,$key,$value) {
-
- $dbvalue = ((is_array($value)) ? serialize($value) : $value);
- $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
-
- if(get_abconfig($chash,$xhash,$family,$key) === false) {
- $r = q("insert into abconfig ( chan, xchan, cat, k, v ) values ( '%s', '%s', '%s', '%s', '%s' ) ",
- dbesc($chash),
- dbesc($xhash),
- dbesc($family),
- dbesc($key),
- dbesc($dbvalue)
- );
- }
- else {
- $r = q("update abconfig set v = '%s' where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' ",
- dbesc($dbvalue),
- dbesc($chash),
- dbesc($xhash),
- dbesc($family),
- dbesc($key)
- );
- }
- if($r)
- return $value;
- return false;
+ return Zlib\AbConfig::Set($chash,$xhash,$family,$key,$value);
}
-
function del_abconfig($chash,$xhash,$family,$key) {
-
- $r = q("delete from abconfig where chan = '%s' and xchan = '%s' and cat = '%s' and k = '%s' ",
- dbesc($chash),
- dbesc($xhash),
- dbesc($family),
- dbesc($key)
- );
-
- return $r;
+ return Zlib\AbConfig::Delete($chash,$xhash,$family,$key);
}
-
-
-
-
+function load_iconfig(&$item) {
+ Zlib\IConfig::Load($item);
+}
function get_iconfig(&$item, $family, $key) {
-
- $is_item = false;
- if(is_array($item)) {
- $is_item = true;
- if((! array_key_exists('iconfig',$item)) || (! is_array($item['iconfig'])))
- $item['iconfig'] = array();
-
- if(array_key_exists('item_id',$item))
- $iid = $item['item_id'];
- else
- $iid = $item['id'];
- }
- elseif(intval($item))
- $iid = $item;
-
- if(! $iid)
- return false;
-
- if(is_array($item) && array_key_exists('iconfig',$item) && is_array($item['iconfig'])) {
- foreach($item['iconfig'] as $c) {
- if($c['iid'] == $iid && $c['cat'] == $family && $c['k'] == $key)
- return $c['v'];
- }
- }
-
- $r = q("select * from iconfig where iid = %d and cat = '%s' and k = '%s' limit 1",
- intval($iid),
- dbesc($family),
- dbesc($key)
- );
- if($r) {
- $r[0]['v'] = ((preg_match('|^a:[0-9]+:{.*}$|s',$r[0]['v'])) ? unserialize($r[0]['v']) : $r[0]['v']);
- if($is_item)
- $item['iconfig'][] = $r[0];
- return $r[0]['v'];
- }
- return false;
-
+ return Zlib\IConfig::Get($item, $family, $key);
}
-/**
- * set_iconfig(&$item, $family, $key, $value, $sharing = false);
- *
- * $item - item array or item id. If passed an array the iconfig meta information is
- * added to the item structure (which will need to be saved with item_store eventually).
- * If passed an id, the DB is updated, but may not be federated and/or cloned.
- * $family - namespace of meta variable
- * $key - key of meta variable
- * $value - value of meta variable
- * $sharing - boolean (default false); if true the meta information is propagated with the item
- * to other sites/channels, mostly useful when $item is an array and has not yet been stored/delivered.
- * If the meta information is added after delivery and you wish it to be shared, it may be necessary to
- * alter the item edited timestamp and invoke the delivery process on the updated item. The edited
- * timestamp needs to be altered in order to trigger an item_store_update() at the receiving end.
- */
-
-
function set_iconfig(&$item, $family, $key, $value, $sharing = false) {
-
- $dbvalue = ((is_array($value)) ? serialize($value) : $value);
- $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
-
- $is_item = false;
- $idx = null;
-
- if(is_array($item)) {
- $is_item = true;
- if((! array_key_exists('iconfig',$item)) || (! is_array($item['iconfig'])))
- $item['iconfig'] = array();
- elseif($item['iconfig']) {
- for($x = 0; $x < count($item['iconfig']); $x ++) {
- if($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
- $idx = $x;
- }
- }
- }
- $entry = array('cat' => $family, 'k' => $key, 'v' => $value, 'sharing' => $sharing);
-
- if(is_null($idx))
- $item['iconfig'][] = $entry;
- else
- $item['iconfig'][$idx] = $entry;
- return $value;
- }
-
- if(intval($item))
- $iid = intval($item);
-
- if(! $iid)
- return false;
-
- if(get_iconfig($item, $family, $key) === false) {
- $r = q("insert into iconfig( iid, cat, k, v, sharing ) values ( %d, '%s', '%s', '%s', %d ) ",
- intval($iid),
- dbesc($family),
- dbesc($key),
- dbesc($dbvalue),
- intval($sharing)
- );
- }
- else {
- $r = q("update iconfig set v = '%s', sharing = %d where iid = %d and cat = '%s' and k = '%s' ",
- dbesc($dbvalue),
- intval($sharing),
- intval($iid),
- dbesc($family),
- dbesc($key)
- );
- }
-
- if(! $r)
- return false;
-
- return $value;
+ return Zlib\IConfig::Set($item, $family, $key, $value, $sharing);
}
-
-
function del_iconfig(&$item, $family, $key) {
-
-
- $is_item = false;
- $idx = null;
-
- if(is_array($item)) {
- $is_item = true;
- if(is_array($item['iconfig'])) {
- for($x = 0; $x < count($item['iconfig']); $x ++) {
- if($item['iconfig'][$x]['cat'] == $family && $item['iconfig'][$x]['k'] == $key) {
- unset($item['iconfig'][$x]);
- }
- }
- }
- return true;
- }
-
- if(intval($item))
- $iid = intval($item);
-
- if(! $iid)
- return false;
-
- return q("delete from iconfig where iid = %d and cat = '%s' and k = '%s' ",
- intval($iid),
- dbesc($family),
- dbesc($key)
- );
-
+ return Zlib\IConfig::Delete($item, $family, $key);
}
-
diff --git a/include/Contact.php b/include/connections.php
similarity index 94%
rename from include/Contact.php
rename to include/connections.php
index e011c60c8..2d10b8354 100644
--- a/include/Contact.php
+++ b/include/connections.php
@@ -48,32 +48,9 @@ function abook_self($channel_id) {
return(($r) ? $r[0] : array());
}
-function channelx_by_nick($nick) {
- $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_address = '%s' and channel_removed = 0 LIMIT 1",
- dbesc($nick)
- );
- return(($r) ? $r[0] : false);
-}
-
-function channelx_by_hash($hash) {
- $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_hash = '%s' and channel_removed = 0 LIMIT 1",
- dbesc($hash)
- );
- return(($r) ? $r[0] : false);
-}
-
-function channelx_by_n($id) {
- $r = q("SELECT * FROM channel left join xchan on channel_hash = xchan_hash WHERE channel_id = %d and channel_removed = 0 LIMIT 1",
- dbesc($id)
- );
- return(($r) ? $r[0] : false);
-}
-
function vcard_from_xchan($xchan, $observer = null, $mode = '') {
- $a = get_app();
-
if(! $xchan) {
if(App::$poi) {
$xchan = App::$poi;
@@ -198,7 +175,7 @@ function account_remove($account_id,$local = true,$unset_session=true) {
// Don't let anybody nuke the only admin account.
- $r = q("select account_id from account where (account_roles & %d)>0",
+ $r = q("select account_id from account where (account_roles & %d) > 0",
intval(ACCOUNT_ROLE_ADMIN)
);
@@ -267,7 +244,7 @@ function channel_remove($channel_id, $local = true, $unset_session=false) {
if(! $channel_id)
return;
- $a = get_app();
+
logger('Removing channel: ' . $channel_id);
logger('channel_remove: local only: ' . intval($local));
@@ -303,8 +280,7 @@ function channel_remove($channel_id, $local = true, $unset_session=false) {
dbesc($channel['channel_hash'])
);
- proc_run('php','include/notifier.php','purge_all',$channel_id);
-
+ Zotlabs\Daemon\Master::Summon(array('Notifier','purge_all',$channel_id));
}
q("DELETE FROM `groups` WHERE `uid` = %d", intval($channel_id));
@@ -386,10 +362,10 @@ function channel_remove($channel_id, $local = true, $unset_session=false) {
@rrmdir($f);
}
- proc_run('php','include/directory.php',$channel_id);
+ Zotlabs\Daemon\Master::Summon(array('Directory',$channel_id));
if($channel_id == local_channel() && $unset_session) {
- \Zotlabs\Web\Session::nuke();
+ App::$session->nuke();
goaway(z_root());
}
@@ -614,7 +590,8 @@ function random_profile() {
for($i = 0; $i < $retryrandom; $i++) {
- $r = q("select xchan_url from xchan left join hubloc on hubloc_hash = xchan_hash where hubloc_connected > %s - interval %s order by $randfunc limit 1",
+ $r = q("select xchan_url from xchan left join hubloc on hubloc_hash = xchan_hash where xchan_addr not like '%s' and hubloc_connected > %s - interval %s order by $randfunc limit 1",
+ dbesc('sys@%'),
db_utcnow(), db_quoteinterval('30 day')
);
diff --git a/include/contact_selectors.php b/include/contact_selectors.php
deleted file mode 100644
index 0de4ece00..000000000
--- a/include/contact_selectors.php
+++ /dev/null
@@ -1,97 +0,0 @@
-\r\n";
-
- $r = q("SELECT profile_guid, profile_name FROM `profile` WHERE `uid` = %d",
- intval($_SESSION['uid']));
-
- if($r) {
- foreach($r as $rr) {
- $selected = (($rr['profile_guid'] == $current) ? " selected=\"selected\" " : "");
- $o .= "{$rr['profile_name']} \r\n";
- }
- }
- $o .= " \r\n";
- return $o;
-}
-
-/* unused currently
-
-function contact_reputation($current) {
-
- $o = '';
- $o .= " \r\n";
-
- $rep = array(
- 0 => t('Unknown | Not categorized'),
- 1 => t('Block immediately'),
- 2 => t('Shady, spammer, self-marketer'),
- 3 => t('Known to me, but no opinion'),
- 4 => t('OK, probably harmless'),
- 5 => t('Reputable, has my trust')
- );
-
- foreach($rep as $k => $v) {
- $selected = (($k == $current) ? " selected=\"selected\" " : "");
- $o .= "$v \r\n";
- }
- $o .= "\r\n";
- return $o;
-}
-
-*/
-
-function contact_poll_interval($current, $disabled = false) {
-
- $dis = (($disabled) ? ' disabled="disabled" ' : '');
- $o = '';
- $o .= " " . "\r\n";
-
- $rep = array(
- 0 => t('Frequently'),
- 1 => t('Hourly'),
- 2 => t('Twice daily'),
- 3 => t('Daily'),
- 4 => t('Weekly'),
- 5 => t('Monthly')
- );
-
- foreach($rep as $k => $v) {
- $selected = (($k == $current) ? " selected=\"selected\" " : "");
- $o .= "$v \r\n";
- }
- $o .= "\r\n";
- return $o;
-}
-
-
-function network_to_name($s) {
-
- $nets = array(
- NETWORK_DFRN => t('Friendica'),
- NETWORK_FRND => t('Friendica'),
- NETWORK_OSTATUS => t('OStatus'),
- NETWORK_GNUSOCIAL => t('GNU-Social'),
- NETWORK_FEED => t('RSS/Atom'),
- NETWORK_MAIL => t('Email'),
- NETWORK_DIASPORA => t('Diaspora'),
- NETWORK_FACEBOOK => t('Facebook'),
- NETWORK_ZOT => t('Zot'),
- NETWORK_LINKEDIN => t('LinkedIn'),
- NETWORK_XMPP => t('XMPP/IM'),
- NETWORK_MYSPACE => t('MySpace'),
- );
-
- call_hooks('network_to_name', $nets);
-
- $search = array_keys($nets);
- $replace = array_values($nets);
-
- return str_replace($search,$replace,$s);
-
-}
diff --git a/include/contact_widgets.php b/include/contact_widgets.php
index e62d57aa2..85c46b0d1 100644
--- a/include/contact_widgets.php
+++ b/include/contact_widgets.php
@@ -3,9 +3,6 @@
function findpeople_widget() {
- require_once('include/Contact.php');
-
- $a = get_app();
if(get_config('system','invitation_only')) {
$x = get_pconfig(local_channel(),'system','invites_remaining');
@@ -37,13 +34,12 @@ function findpeople_widget() {
function fileas_widget($baseurl,$selected = '') {
- $a = get_app();
if(! local_channel())
return '';
$terms = array();
- $r = q("select distinct(term) from term where uid = %d and type = %d order by term asc",
+ $r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
intval(local_channel()),
intval(TERM_FILE)
);
@@ -65,8 +61,6 @@ function fileas_widget($baseurl,$selected = '') {
}
function categories_widget($baseurl,$selected = '') {
-
- $a = get_app();
if(! feature_enabled(App::$profile['profile_uid'],'categories'))
return '';
@@ -78,7 +72,7 @@ function categories_widget($baseurl,$selected = '') {
from term join item on term.oid = item.id
where item.uid = %d
and term.uid = item.uid
- and term.type = %d
+ and term.ttype = %d
and term.otype = %d
and item.owner_xchan = '%s'
and item.item_wall = 1
@@ -108,8 +102,6 @@ function categories_widget($baseurl,$selected = '') {
function common_friends_visitor_widget($profile_uid) {
- $a = get_app();
-
if(local_channel() == $profile_uid)
return;
diff --git a/include/conversation.php b/include/conversation.php
index 8be0557e7..518193b08 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -93,15 +93,15 @@ function localize_item(&$item){
if (activity_match($item['verb'],ACTIVITY_LIKE) || activity_match($item['verb'],ACTIVITY_DISLIKE)){
- if(! $item['object'])
+ if(! $item['obj'])
return;
if(intval($item['item_thread_top']))
return;
- $obj = json_decode_plus($item['object']);
- if((! $obj) && ($item['object'])) {
- logger('localize_item: failed to decode object: ' . print_r($item['object'],true));
+ $obj = json_decode_plus($item['obj']);
+ if((! $obj) && ($item['obj'])) {
+ logger('localize_item: failed to decode object: ' . print_r($item['obj'],true));
}
if($obj['author'] && $obj['author']['link'])
@@ -186,7 +186,7 @@ function localize_item(&$item){
$Alink = $item['author']['xchan_url'];
- $obj= json_decode_plus($item['object']);
+ $obj= json_decode_plus($item['obj']);
$Blink = $Bphoto = '';
@@ -219,7 +219,7 @@ function localize_item(&$item){
$Aname = $item['author']['xchan_name'];
$Alink = $item['author']['xchan_url'];
- $obj= json_decode_plus($item['object']);
+ $obj= json_decode_plus($item['obj']);
$Blink = $Bphoto = '';
@@ -299,7 +299,7 @@ function localize_item(&$item){
}
$plink = '[zrl=' . $obj['plink'] . ']' . $post_type . '[/zrl]';
- $parsedobj = parse_xml_string($xmlhead.$item['object']);
+ $parsedobj = parse_xml_string($xmlhead.$item['obj']);
$tag = sprintf('#[zrl=%s]%s[/zrl]', $parsedobj->id, $parsedobj->content);
$item['body'] = sprintf( t('%1$s tagged %2$s\'s %3$s with %4$s'), $author, $objauthor, $plink, $tag );
@@ -316,7 +316,7 @@ function localize_item(&$item){
$xmlhead="<"."?xml version='1.0' encoding='UTF-8' ?".">";
- $obj = parse_xml_string($xmlhead.$item['object']);
+ $obj = parse_xml_string($xmlhead.$item['obj']);
if(strlen($obj->id)) {
$r = q("select * from item where mid = '%s' and uid = %d limit 1",
dbesc($obj->id),
@@ -754,10 +754,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
// Normal View
// logger('conv: items: ' . print_r($items,true));
- require_once('include/ConversationObject.php');
- require_once('include/ItemObject.php');
-
- $conv = new Conversation($mode, $preview, $prepared_item);
+ $conv = new Zotlabs\Lib\ThreadStream($mode, $preview, $prepared_item);
// In the display mode we don't have a profile owner.
@@ -806,7 +803,7 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
if($item['id'] == $item['parent']) {
- $item_object = new Item($item);
+ $item_object = new Zotlabs\Lib\ThreadItem($item);
$conv->add_thread($item_object);
if($page_mode === 'list') {
$item_object->set_template('conv_list.tpl');
@@ -861,8 +858,6 @@ function conversation(&$a, $items, $mode, $update, $page_mode = 'traditional', $
function best_link_url($item) {
- $a = get_app();
-
$best_url = '';
$sparkle = false;
@@ -891,7 +886,7 @@ function best_link_url($item) {
function item_photo_menu($item){
- $a = get_app();
+
$contact = null;
$ssl_state = false;
@@ -1110,7 +1105,6 @@ function status_editor($a, $x, $popup = false) {
$o = '';
- require_once('include/Contact.php');
$c = channelx_by_n($x['profile_uid']);
if($c && $c['channel_moved'])
return $o;
@@ -1163,7 +1157,7 @@ function status_editor($a, $x, $popup = false) {
$layoutselect = ' ';
if(array_key_exists('channel_select',$x) && $x['channel_select']) {
- require_once('include/identity.php');
+ require_once('include/channel.php');
$id_select = identity_selector();
}
else
@@ -1412,7 +1406,7 @@ function render_location_default($item) {
function prepare_page($item) {
- $a = get_app();
+
$naked = 1;
// $naked = ((get_pconfig($item['uid'],'system','nakedpage')) ? 1 : 0);
$observer = App::get_observer();
@@ -1446,7 +1440,7 @@ function prepare_page($item) {
function network_tabs() {
- $a = get_app();
+
$no_active='';
$starred_active = '';
$new_active = '';
@@ -1662,8 +1656,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
if ($p['chat'] && feature_enabled($uid,'ajaxchat')) {
- require_once('include/chat.php');
- $has_chats = chatroom_list_count($uid);
+ $has_chats = Zotlabs\Lib\Chatroom::list_count($uid);
if ($has_chats) {
$tabs[] = array(
'label' => t('Chatrooms'),
diff --git a/include/cronhooks.php b/include/cronhooks.php
deleted file mode 100644
index a314593d2..000000000
--- a/include/cronhooks.php
+++ /dev/null
@@ -1,23 +0,0 @@
-connected) {
+ $dns = ((self::$dbtype == DBTYPE_POSTGRES) ? 'postgres' : 'mysql')
+ . ':host=' . $server . (is_null($port) ? '' : ';port=' . $port)
+ . ';dbname=' . $db;
+ self::$dba->pdo_set(array($dns,$user,$pass));
+ }
+
+ define('NULL_DATE', self::$dba->get_null_date());
+ define('ACTIVE_DBTYPE', self::$dbtype);
+ return self::$dba;
}
- define('NULL_DATE', $dba->get_null_date());
- define('ACTIVE_DBTYPE', $dbtype);
- return $dba;
}
/**
@@ -60,6 +88,7 @@ abstract class dba_driver {
const UTC_NOW = 'UTC_TIMESTAMP()';
protected $db;
+ protected $pdo = array();
public $debug = 0;
public $connected = false;
@@ -183,6 +212,15 @@ abstract class dba_driver {
function unescapebin($str) {
return $str;
}
+
+ function pdo_set($x) {
+ $this->pdo = $x;
+ }
+
+ function pdo_get() {
+ return $this->pdo;
+ }
+
} // end abstract dba_driver class
@@ -206,8 +244,8 @@ function printable($s) {
function dbg($state) {
global $db;
- if($db)
- $db->dbg($state);
+ if(\DBA::$dba)
+ \DBA::$dba->dbg($state);
}
/**
@@ -221,21 +259,18 @@ function dbg($state) {
* @return Return an escaped string of the value to pass to a DB query.
*/
function dbesc($str) {
- global $db;
- if($db && $db->connected)
- return($db->escape($str));
+ if(\DBA::$dba && \DBA::$dba->connected)
+ return(\DBA::$dba->escape($str));
else
return(str_replace("'", "\\'", $str));
}
function dbescbin($str) {
- global $db;
- return $db->escapebin($str);
+ return \DBA::$dba->escapebin($str);
}
function dbunescbin($str) {
- global $db;
- return $db->unescapebin($str);
+ return \DBA::$dba->unescapebin($str);
}
function dbescdate($date) {
@@ -248,36 +283,25 @@ function dbescdate($date) {
}
function db_quoteinterval($txt) {
- global $db;
- return $db->quote_interval($txt);
+ return \DBA::$dba->quote_interval($txt);
}
function dbesc_identifier($str) {
- global $db;
- return $db->escape_identifier($str);
+ return \DBA::$dba->escape_identifier($str);
}
function db_utcnow() {
- global $db;
- return $db->utcnow();
+ return \DBA::$dba->utcnow();
}
function db_optimizetable($table) {
- global $db;
- $db->optimize_table($table);
+ \DBA::$dba->optimize_table($table);
}
function db_concat($fld, $sep) {
- global $db;
- return $db->concat($fld, $sep);
+ return \DBA::$dba->concat($fld, $sep);
}
-// Function: q($sql,$args);
-// Description: execute SQL query with printf style args.
-// Example: $r = q("SELECT * FROM `%s` WHERE `uid` = %d",
-// 'user', 1);
-
-
/**
* @brief Execute a SQL query with printf style args.
*
@@ -293,13 +317,13 @@ function db_concat($fld, $sep) {
* @param string $sql The SQL query to execute
* @return bool|array
*/
+
function q($sql) {
- global $db;
$args = func_get_args();
unset($args[0]);
- if($db && $db->connected) {
+ if(\DBA::$dba && \DBA::$dba->connected) {
$stmt = vsprintf($sql, $args);
if($stmt === false) {
if(version_compare(PHP_VERSION, '5.4.0') >= 0)
@@ -308,13 +332,14 @@ function q($sql) {
else
db_logger('dba: vsprintf error: ' . print_r(debug_backtrace(), true),LOGGER_NORMAL,LOG_CRIT);
}
- return $db->q($stmt);
+ return \DBA::$dba->q($stmt);
}
/*
* This will happen occasionally trying to store the
* session data after abnormal program termination
*/
+
db_logger('dba: no database: ' . print_r($args,true),LOGGER_NORMAL,LOG_CRIT);
return false;
@@ -328,10 +353,9 @@ function q($sql) {
* @param string $sql The SQL query to execute
*/
function dbq($sql) {
- global $db;
- if($db && $db->connected)
- $ret = $db->q($sql);
+ if(\DBA::$dba && \DBA::$dba->connected)
+ $ret = \DBA::$dba->q($sql);
else
$ret = false;
@@ -392,13 +416,18 @@ function db_getfunc($f) {
// The logger function may make DB calls internally to query the system logging parameters.
// This can cause a recursion if database debugging is enabled.
-// So this function preserves the current database debugging state and then turns it off while
-// doing the logger() call
+// So this function preserves the current database debugging state and then turns it off
+// temporarily while doing the logger() call
function db_logger($s,$level = LOGGER_NORMAL,$syslog = LOG_INFO) {
- global $db;
- $saved = $db->debug;
- $db->debug = false;
+
+ if(\DBA::$logging)
+ return;
+
+ $saved = \DBA::$dba->debug;
+ \DBA::$dba->debug = false;
+ \DBA::$logging = true;
logger($s,$level,$syslog);
- $db->debug = $saved;
+ \DBA::$logging = false;
+ \DBA::$dba->debug = $saved;
}
\ No newline at end of file
diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php
new file mode 100755
index 000000000..7255a2b66
--- /dev/null
+++ b/include/dba/dba_pdo.php
@@ -0,0 +1,95 @@
+driver_dbtype = 'mysql'; // (($dbtype == DBTYPE_POSTGRES) ? 'postgres' : 'mysql');
+ $dns = $this->driver_dbtype
+ . ':host=' . $server . (is_null($port) ? '' : ';port=' . $port)
+ . ';dbname=' . $db;
+
+
+ try {
+ $this->db = new PDO($dns,$user,$pass);
+ $this->db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
+ }
+ catch(PDOException $e) {
+ if(file_exists('dbfail.out')) {
+ file_put_contents('dbfail.out', datetime_convert() . "\nConnect: " . $e->getMessage() . "\n", FILE_APPEND);
+ }
+
+ return false;
+ }
+
+ $this->connected = true;
+ return true;
+
+ }
+
+ function q($sql) {
+ if((! $this->db) || (! $this->connected))
+ return false;
+
+ $this->error = '';
+ $select = ((stripos($sql,'select') === 0) ? true : false);
+
+ try {
+ $result = $this->db->query($sql);
+ }
+ catch(PDOException $e) {
+
+ $this->error = $e->getMessage();
+ if($this->error) {
+ db_logger('dba_mysqli: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR);
+ if(file_exists('dbfail.out')) {
+ file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . "\n" . $this->error . "\n", FILE_APPEND);
+ }
+ }
+ }
+
+ if(!($select)) {
+ if($this->debug) {
+ db_logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returns ' . (($result) ? 'true' : 'false'), LOGGER_NORMAL,(($result) ? LOG_INFO : LOG_ERR));
+ }
+ return $result;
+ }
+
+ if($this->debug) {
+ db_logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returned ' . count($result) . ' results.', LOGGER_NORMAL, LOG_INFO);
+ }
+
+ $r = array();
+ if($result) {
+ foreach($result as $x) {
+ $r[] = $x;
+ }
+ if($this->debug) {
+ db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO);
+ }
+ }
+ return $r;
+ }
+
+ function escape($str) {
+ if($this->db && $this->connected) {
+ return substr(substr(@$this->db->quote($str),1),0,-1);
+ }
+ }
+
+ function close() {
+ if($this->db)
+ $this->db = null;
+ $this->connected = false;
+ }
+
+ function getdriver() {
+ return 'pdo';
+ }
+
+}
\ No newline at end of file
diff --git a/include/deliver.php b/include/deliver.php
deleted file mode 100644
index 40df543d5..000000000
--- a/include/deliver.php
+++ /dev/null
@@ -1,87 +0,0 @@
- json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $mm)))));
- zot_import($msg,z_root());
- }
- }
- else {
- $msg = array('body' => json_encode(array('success' => true, 'pickup' => array(array('notify' => $notify,'message' => $m)))));
- $dresult = zot_import($msg,z_root());
- }
-
- remove_queue_item($r[0]['outq_hash']);
-
- if($dresult && is_array($dresult)) {
- foreach($dresult as $xx) {
- if(is_array($xx) && array_key_exists('message_id',$xx)) {
- if(delivery_report_is_storable($xx)) {
- q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ",
- dbesc($xx['message_id']),
- dbesc($xx['location']),
- dbesc($xx['recipient']),
- dbesc($xx['status']),
- dbesc(datetime_convert($xx['date'])),
- dbesc($xx['sender'])
- );
- }
- }
- }
- }
-
- q("delete from dreport where dreport_queue = '%s'",
- dbesc($argv[$x])
- );
- }
- }
-
- // otherwise it's a remote delivery - call queue_deliver() with the $immediate flag
-
- queue_deliver($r[0],true);
-
- }
- }
-}
-
-if (array_search(__file__,get_included_files())===0){
- deliver_run($argv,$argc);
- killme();
-}
diff --git a/include/deliver_hooks.php b/include/deliver_hooks.php
deleted file mode 100644
index f0d6ba1b1..000000000
--- a/include/deliver_hooks.php
+++ /dev/null
@@ -1,29 +0,0 @@
- 2) {
- if($argv[2] === 'force')
- $force = true;
- if($argv[2] === 'nopush')
- $pushall = false;
- }
-
- logger('directory update', LOGGER_DEBUG);
-
- $dirmode = get_config('system','directory_mode');
- if($dirmode === false)
- $dirmode = DIRECTORY_MODE_NORMAL;
-
- $x = q("select * from channel where channel_id = %d limit 1",
- intval($argv[1])
- );
- if(! $x)
- return;
-
- $channel = $x[0];
-
- if($dirmode != DIRECTORY_MODE_NORMAL) {
-
- // this is an in-memory update and we don't need to send a network packet.
-
- local_dir_update($argv[1],$force);
-
- q("update channel set channel_dirdate = '%s' where channel_id = %d",
- dbesc(datetime_convert()),
- intval($channel['channel_id'])
- );
-
- // Now update all the connections
- if($pushall)
- proc_run('php','include/notifier.php','refresh_all',$channel['channel_id']);
-
- return;
- }
-
- // otherwise send the changes upstream
-
- $directory = find_upstream_directory($dirmode);
- $url = $directory['url'] . '/post';
-
- // ensure the upstream directory is updated
-
- $packet = zot_build_packet($channel,(($force) ? 'force_refresh' : 'refresh'));
- $z = zot_zot($url,$packet);
-
- // re-queue if unsuccessful
-
- if(! $z['success']) {
-
- /** @FIXME we aren't updating channel_dirdate if we have to queue
- * the directory packet. That means we'll try again on the next poll run.
- */
-
- $hash = random_string();
-
- queue_insert(array(
- 'hash' => $hash,
- 'account_id' => $channel['channel_account_id'],
- 'channel_id' => $channel['channel_id'],
- 'posturl' => $url,
- 'notify' => $packet,
- ));
-
- }
- else {
- q("update channel set channel_dirdate = '%s' where channel_id = %d",
- dbesc(datetime_convert()),
- intval($channel['channel_id'])
- );
- }
-
- // Now update all the connections
- if($pushall)
- proc_run('php','include/notifier.php','refresh_all',$channel['channel_id']);
-
-}
-
-if (array_search(__file__, get_included_files()) === 0) {
- directory_run($argv, $argc);
- killme();
-}
diff --git a/include/environment.php b/include/environment.php
index 47ad241a7..11d465b84 100644
--- a/include/environment.php
+++ b/include/environment.php
@@ -60,6 +60,8 @@ function phpiniSizeToBytes($val) {
$val *= 1024;
case 'k':
$val *= 1024;
+ default:
+ break;
}
return (int)$val;
diff --git a/include/event.php b/include/event.php
index e41bf2db7..a4118ec78 100644
--- a/include/event.php
+++ b/include/event.php
@@ -28,22 +28,22 @@ function format_event_html($ev) {
$o .= '
' . bbcode($ev['summary']) . ' ' . "\r\n";
$o .= '' . t('Starts:') . ' '
. (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
- $ev['start'] , $bd_format ))
+ $ev['dtstart'] , $bd_format ))
: day_translate(datetime_convert('UTC', 'UTC',
- $ev['start'] , $bd_format)))
+ $ev['dtstart'] , $bd_format)))
. '
' . "\r\n";
if(! $ev['nofinish'])
$o .= '' . t('Finishes:') . ' '
. (($ev['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(),
- $ev['finish'] , $bd_format ))
+ $ev['dtend'] , $bd_format ))
: day_translate(datetime_convert('UTC', 'UTC',
- $ev['finish'] , $bd_format )))
+ $ev['dtend'] , $bd_format )))
. '
' . "\r\n";
$o .= '' . bbcode($ev['description']) . '
' . "\r\n";
@@ -58,6 +58,37 @@ function format_event_html($ev) {
return $o;
}
+function format_event_obj($jobject) {
+ $event = array();
+
+ $object = json_decode($jobject,true);
+
+ //ensure compatibility with older items - this check can be removed at a later point
+ if(array_key_exists('description', $object)) {
+
+ $bd_format = t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8:01 AM
+
+ $event['header'] = replace_macros(get_markup_template('event_item_header.tpl'),array(
+ '$title' => bbcode($object['title']),
+ '$dtstart_label' => t('Starts:'),
+ '$dtstart_title' => datetime_convert('UTC', 'UTC', $object['dtstart'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
+ '$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['dtstart'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtstart'] , $bd_format))),
+ '$finish' => (($object['nofinish']) ? false : true),
+ '$dtend_label' => t('Finishes:'),
+ '$dtend_title' => datetime_convert('UTC','UTC',$object['dtend'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
+ '$dtend_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['dtend'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['dtend'] , $bd_format )))
+ ));
+
+ $event['content'] = replace_macros(get_markup_template('event_item_content.tpl'),array(
+ '$description' => bbcode($object['description']),
+ '$location_label' => t('Location:'),
+ '$location' => bbcode($object['location'])
+ ));
+
+ }
+
+ return $event;
+}
function ical_wrapper($ev) {
@@ -67,8 +98,8 @@ function ical_wrapper($ev) {
$o .= "BEGIN:VCALENDAR";
$o .= "\r\nVERSION:2.0";
$o .= "\r\nMETHOD:PUBLISH";
- $o .= "\r\nPRODID:-//" . get_config('system','sitename') . "//" . Zotlabs\Project\System::get_platform_name() . "//" . strtoupper(App::$language). "\r\n";
- if(array_key_exists('start', $ev))
+ $o .= "\r\nPRODID:-//" . get_config('system','sitename') . "//" . Zotlabs\Lib\System::get_platform_name() . "//" . strtoupper(App::$language). "\r\n";
+ if(array_key_exists('dtstart', $ev))
$o .= format_event_ical($ev);
else {
foreach($ev as $e) {
@@ -82,7 +113,7 @@ function ical_wrapper($ev) {
function format_event_ical($ev) {
- if($ev['type'] === 'task')
+ if($ev['etype'] === 'task')
return format_todo_ical($ev);
$o = '';
@@ -92,10 +123,10 @@ function format_event_ical($ev) {
$o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z');
$o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
$o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
- if($ev['start'])
- $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['start'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
- if($ev['finish'] && ! $ev['nofinish'])
- $o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['finish'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
+ if($ev['dtstart'])
+ $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
+ if($ev['dtend'] && ! $ev['nofinish'])
+ $o .= "\r\nDTEND:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['summary'])
$o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']);
if($ev['location'])
@@ -119,10 +150,10 @@ function format_todo_ical($ev) {
$o .= "\r\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z');
$o .= "\r\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
$o .= "\r\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
- if($ev['start'])
- $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['start'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
- if($ev['finish'] && ! $ev['nofinish'])
- $o .= "\r\nDUE:" . datetime_convert('UTC','UTC', $ev['finish'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
+ if($ev['dtstart'])
+ $o .= "\r\nDTSTART:" . datetime_convert('UTC','UTC', $ev['dtstart'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
+ if($ev['dtend'] && ! $ev['nofinish'])
+ $o .= "\r\nDUE:" . datetime_convert('UTC','UTC', $ev['dtend'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['summary'])
$o .= "\r\nSUMMARY:" . format_ical_text($ev['summary']);
if($ev['event_status']) {
@@ -166,15 +197,18 @@ function format_event_bbcode($ev) {
if($ev['description'])
$o .= '[event-description]' . $ev['description'] . '[/event-description]';
- if($ev['start'])
- $o .= '[event-start]' . $ev['start'] . '[/event-start]';
+ if($ev['dtstart'])
+ $o .= '[event-start]' . $ev['dtstart'] . '[/event-start]';
- if(($ev['finish']) && (! $ev['nofinish']))
- $o .= '[event-finish]' . $ev['finish'] . '[/event-finish]';
+ if(($ev['dtend']) && (! $ev['nofinish']))
+ $o .= '[event-finish]' . $ev['dtend'] . '[/event-finish]';
if($ev['location'])
$o .= '[event-location]' . $ev['location'] . '[/event-location]';
+ if($ev['event_hash'])
+ $o .= '[event-id]' . $ev['event_hash'] . '[/event-id]';
+
if($ev['adjust'])
$o .= '[event-adjust]' . $ev['adjust'] . '[/event-adjust]';
@@ -204,21 +238,24 @@ function bbtoevent($s) {
$ev['description'] = $match[1];
$match = '';
if(preg_match("/\[event\-start\](.*?)\[\/event\-start\]/is",$s,$match))
- $ev['start'] = $match[1];
+ $ev['dtstart'] = $match[1];
$match = '';
if(preg_match("/\[event\-finish\](.*?)\[\/event\-finish\]/is",$s,$match))
- $ev['finish'] = $match[1];
+ $ev['dtend'] = $match[1];
$match = '';
if(preg_match("/\[event\-location\](.*?)\[\/event\-location\]/is",$s,$match))
$ev['location'] = $match[1];
$match = '';
+ if(preg_match("/\[event\-id\](.*?)\[\/event\-id\]/is",$s,$match))
+ $ev['event_hash'] = $match[1];
+ $match = '';
if(preg_match("/\[event\-adjust\](.*?)\[\/event\-adjust\]/is",$s,$match))
$ev['adjust'] = $match[1];
- if(array_key_exists('start',$ev)) {
- if(array_key_exists('finish',$ev)) {
- if($ev['finish'] === $ev['start'])
+ if(array_key_exists('dtstart',$ev)) {
+ if(array_key_exists('dtend',$ev)) {
+ if($ev['dtend'] === $ev['dtstart'])
$ev['nofinish'] = 1;
- elseif($ev['finish'])
+ elseif($ev['dtend'])
$ev['nofinish'] = 0;
else
$ev['nofinish'] = 1;
@@ -254,8 +291,8 @@ function sort_by_date($arr) {
*/
function ev_compare($a, $b) {
- $date_a = (($a['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$a['start']) : $a['start']);
- $date_b = (($b['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$b['start']) : $b['start']);
+ $date_a = (($a['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$a['dtstart']) : $a['dtstart']);
+ $date_b = (($b['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$b['dtstart']) : $b['dtstart']);
if ($date_a === $date_b)
return strcasecmp($a['description'], $b['description']);
@@ -268,7 +305,7 @@ function event_store_event($arr) {
$arr['created'] = (($arr['created']) ? $arr['created'] : datetime_convert());
$arr['edited'] = (($arr['edited']) ? $arr['edited'] : datetime_convert());
- $arr['type'] = (($arr['type']) ? $arr['type'] : 'event' );
+ $arr['etype'] = (($arr['etype']) ? $arr['etype'] : 'event' );
$arr['event_xchan'] = (($arr['event_xchan']) ? $arr['event_xchan'] : '');
$arr['event_priority'] = (($arr['event_priority']) ? $arr['event_priority'] : 0);
@@ -278,45 +315,52 @@ function event_store_event($arr) {
else
$arr['event_status_date'] = NULL_DATE;
- // Existing event being modified
- if($arr['id'] || $arr['event_hash']) {
+ $existing_event = null;
- // has the event actually changed?
+ if($arr['event_hash']) {
+ $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
+ dbesc($arr['event_hash']),
+ intval($arr['uid'])
+ );
+ if($r) {
+ $existing_event = $r[0];
+ }
+ }
- if($arr['event_hash']) {
- $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
- dbesc($arr['event_hash']),
- intval($arr['uid'])
- );
+ if($arr['id']) {
+ $r = q("SELECT * FROM event WHERE id = %d AND uid = %d LIMIT 1",
+ intval($arr['id']),
+ intval($arr['uid'])
+ );
+ if($r) {
+ $existing_event = $r[0];
}
else {
- $r = q("SELECT * FROM event WHERE id = %d AND uid = %d LIMIT 1",
- intval($arr['id']),
- intval($arr['uid'])
- );
- }
-
- if(! $r)
return false;
+ }
+ }
- if($r[0]['edited'] === $arr['edited']) {
- // Nothing has changed. Return the ID.
- return $r[0];
+
+ if($existing_event) {
+
+ if($existing_event['edited'] >= $arr['edited']) {
+ // Nothing has changed.
+ return $existing_event;
}
- $hash = $r[0]['event_hash'];
+ $hash = $existing_event['event_hash'];
// The event changed. Update it.
$r = q("UPDATE `event` SET
`edited` = '%s',
- `start` = '%s',
- `finish` = '%s',
+ `dtstart` = '%s',
+ `dtend` = '%s',
`summary` = '%s',
`description` = '%s',
`location` = '%s',
- `type` = '%s',
+ `etype` = '%s',
`adjust` = %d,
`nofinish` = %d,
`event_status` = '%s',
@@ -332,12 +376,12 @@ function event_store_event($arr) {
WHERE `id` = %d AND `uid` = %d",
dbesc($arr['edited']),
- dbesc($arr['start']),
- dbesc($arr['finish']),
+ dbesc($arr['dtstart']),
+ dbesc($arr['dtend']),
dbesc($arr['summary']),
dbesc($arr['description']),
dbesc($arr['location']),
- dbesc($arr['type']),
+ dbesc($arr['etype']),
intval($arr['adjust']),
intval($arr['nofinish']),
dbesc($arr['event_status']),
@@ -350,7 +394,7 @@ function event_store_event($arr) {
dbesc($arr['allow_gid']),
dbesc($arr['deny_cid']),
dbesc($arr['deny_gid']),
- intval($r[0]['id']),
+ intval($existing_event['id']),
intval($arr['uid'])
);
} else {
@@ -360,10 +404,12 @@ function event_store_event($arr) {
if(array_key_exists('external_id',$arr))
$hash = $arr['external_id'];
+ elseif(array_key_exists('event_hash',$arr))
+ $hash = $arr['event_hash'];
else
$hash = random_string() . '@' . App::get_hostname();
- $r = q("INSERT INTO event ( uid,aid,event_xchan,event_hash,created,edited,start,finish,summary,description,location,type,
+ $r = q("INSERT INTO event ( uid,aid,event_xchan,event_hash,created,edited,dtstart,dtend,summary,description,location,etype,
adjust,nofinish, event_status, event_status_date, event_percent, event_repeat, event_sequence, event_priority, allow_cid,allow_gid,deny_cid,deny_gid)
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, '%s', %d, %d, '%s', '%s', '%s', '%s' ) ",
intval($arr['uid']),
@@ -372,12 +418,12 @@ function event_store_event($arr) {
dbesc($hash),
dbesc($arr['created']),
dbesc($arr['edited']),
- dbesc($arr['start']),
- dbesc($arr['finish']),
+ dbesc($arr['dtstart']),
+ dbesc($arr['dtend']),
dbesc($arr['summary']),
dbesc($arr['description']),
dbesc($arr['location']),
- dbesc($arr['type']),
+ dbesc($arr['etype']),
intval($arr['adjust']),
intval($arr['nofinish']),
dbesc($arr['event_status']),
@@ -426,7 +472,7 @@ function event_addtocal($item_id, $uid) {
$ev = bbtoevent($r[0]['body']);
- if(x($ev,'summary') && x($ev,'start')) {
+ if(x($ev,'summary') && x($ev,'dtstart')) {
$ev['event_xchan'] = $item['author_xchan'];
$ev['uid'] = $channel['channel_id'];
$ev['account'] = $channel['channel_account_id'];
@@ -436,7 +482,7 @@ function event_addtocal($item_id, $uid) {
// is this an edit?
- if($item['resource_type'] === 'event') {
+ if($item['resource_type'] === 'event' && (! $ev['event_hash'])) {
$ev['event_hash'] = $item['resource_id'];
}
@@ -472,7 +518,6 @@ function event_addtocal($item_id, $uid) {
if($z) {
build_sync_packet($channel['channel_id'],array('event_item' => array(encode_item($sync_item[0],true)),'event' => $z));
}
-
return true;
}
}
@@ -540,20 +585,20 @@ function event_import_ical($ical, $uid) {
// logger('dtstart: ' . var_export($dtstart,true));
- $ev['start'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
+ $ev['dtstart'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
$dtstart->format(\DateTime::W3C));
if(isset($ical->DTEND)) {
$dtend = $ical->DTEND->getDateTime();
- $ev['finish'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
+ $ev['dtend'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
$dtend->format(\DateTime::W3C));
}
else
$ev['nofinish'] = 1;
- if($ev['start'] === $ev['finish'])
+ if($ev['dtstart'] === $ev['dtend'])
$ev['nofinish'] = 1;
if(isset($ical->CREATED)) {
@@ -587,7 +632,7 @@ function event_import_ical($ical, $uid) {
$ev['external_id'] = $evuid;
}
- if($ev['summary'] && $ev['start']) {
+ if($ev['summary'] && $ev['dtstart']) {
$ev['event_xchan'] = $channel['channel_hash'];
$ev['uid'] = $channel['channel_id'];
$ev['account'] = $channel['channel_account_id'];
@@ -626,29 +671,24 @@ function event_import_ical_task($ical, $uid) {
$dtstart = $ical->DTSTART->getDateTime();
+ $ev['adjust'] = (($ical->DTSTART->isFloating()) ? 1 : 0);
+
// logger('dtstart: ' . var_export($dtstart,true));
- if(($dtstart->timezone_type == 2) || (($dtstart->timezone_type == 3) && ($dtstart->timezone === 'UTC'))) {
- $ev['adjust'] = 1;
- }
- else {
- $ev['adjust'] = 0;
- }
-
- $ev['start'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
+ $ev['dtstart'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
$dtstart->format(\DateTime::W3C));
if(isset($ical->DUE)) {
$dtend = $ical->DUE->getDateTime();
- $ev['finish'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
+ $ev['dtend'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
$dtend->format(\DateTime::W3C));
}
else
$ev['nofinish'] = 1;
- if($ev['start'] === $ev['finish'])
+ if($ev['dtstart'] === $ev['dtend'])
$ev['nofinish'] = 1;
if(isset($ical->CREATED)) {
@@ -713,9 +753,9 @@ function event_import_ical_task($ical, $uid) {
$ev['event_percent'] = (string) $ical->{'PERCENT-COMPLETE'} ;
}
- $ev['type'] = 'task';
+ $ev['etype'] = 'task';
- if($ev['summary'] && $ev['start']) {
+ if($ev['summary'] && $ev['dtstart']) {
$ev['event_xchan'] = $channel['channel_hash'];
$ev['uid'] = $channel['channel_id'];
$ev['account'] = $channel['channel_account_id'];
@@ -764,7 +804,10 @@ function event_store_item($arr, $event) {
$prefix = '';
// $birthday = false;
- if($event['type'] === 'birthday') {
+ if(($event) && array_key_exists('event_hash',$event) && (! array_key_exists('event_hash',$arr)))
+ $arr['event_hash'] = $event['event_hash'];
+
+ if($event['etype'] === 'birthday') {
if(! is_sys_channel($arr['uid']))
$prefix = t('This event has been added to your calendar.');
// $birthday = true;
@@ -788,21 +831,22 @@ function event_store_item($arr, $event) {
'type' => ACTIVITY_OBJ_EVENT,
'id' => z_root() . '/event/' . $r[0]['resource_id'],
'title' => $arr['summary'],
- 'start' => $arr['start'],
- 'finish' => $arr['finish'],
+ 'dtstart' => $arr['dtstart'],
+ 'dtend' => $arr['dtend'],
'nofinish' => $arr['nofinish'],
'description' => $arr['description'],
'location' => $arr['location'],
'adjust' => $arr['adjust'],
'content' => format_event_bbcode($arr),
'author' => array(
- 'name' => $r[0]['xchan_name'],
- 'address' => $r[0]['xchan_addr'],
- 'guid' => $r[0]['xchan_guid'],
- 'guid_sig' => $r[0]['xchan_guid_sig'],
- 'link' => array(
- array('rel' => 'alternate', 'type' => 'text/html', 'href' => $r[0]['xchan_url']),
- array('rel' => 'photo', 'type' => $r[0]['xchan_photo_mimetype'], 'href' => $r[0]['xchan_photo_m'])),
+ 'name' => $r[0]['xchan_name'],
+ 'address' => $r[0]['xchan_addr'],
+ 'guid' => $r[0]['xchan_guid'],
+ 'guid_sig' => $r[0]['xchan_guid_sig'],
+ 'link' => array(
+ array('rel' => 'alternate', 'type' => 'text/html', 'href' => $r[0]['xchan_url']),
+ array('rel' => 'photo', 'type' => $r[0]['xchan_photo_mimetype'], 'href' => $r[0]['xchan_photo_m'])
+ ),
),
));
@@ -813,7 +857,7 @@ function event_store_item($arr, $event) {
$sig = '';
- q("UPDATE item SET title = '%s', body = '%s', object = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', sig = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d",
+ q("UPDATE item SET title = '%s', body = '%s', obj = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', edited = '%s', sig = '%s', item_flags = %d, item_private = %d, obj_type = '%s' WHERE id = %d AND uid = %d",
dbesc($arr['summary']),
dbesc($prefix . format_event_bbcode($arr)),
dbesc($object),
@@ -837,12 +881,12 @@ function event_store_item($arr, $event) {
if(($arr['term']) && (is_array($arr['term']))) {
foreach($arr['term'] as $t) {
- q("insert into term (uid,oid,otype,type,term,url)
+ q("insert into term (uid,oid,otype,ttype,term,url)
values(%d,%d,%d,%d,'%s','%s') ",
intval($arr['uid']),
intval($r[0]['id']),
intval(TERM_OBJ_POST),
- intval($t['type']),
+ intval($t['ttype']),
dbesc($t['term']),
dbesc($t['url'])
);
@@ -929,12 +973,12 @@ function event_store_item($arr, $event) {
dbesc($arr['event_xchan'])
);
if($x) {
- $item_arr['object'] = json_encode(array(
+ $item_arr['obj'] = json_encode(array(
'type' => ACTIVITY_OBJ_EVENT,
'id' => z_root() . '/event/' . $event['event_hash'],
'title' => $arr['summary'],
- 'start' => $arr['start'],
- 'finish' => $arr['finish'],
+ 'dtstart' => $arr['dtstart'],
+ 'dtend' => $arr['dtend'],
'nofinish' => $arr['nofinish'],
'description' => $arr['description'],
'location' => $arr['location'],
@@ -984,7 +1028,7 @@ function tasks_fetch($arr) {
if($arr && $arr['all'] == 1)
$sql_extra = '';
- $r = q("select * from event where type = 'task' and uid = %d $sql_extra order by created desc",
+ $r = q("select * from event where etype = 'task' and uid = %d $sql_extra order by created desc",
intval(local_channel())
);
diff --git a/include/expire.php b/include/expire.php
deleted file mode 100644
index e75594b5f..000000000
--- a/include/expire.php
+++ /dev/null
@@ -1,98 +0,0 @@
- '');
- call_hooks('externals_url_select',$arr);
-
- if($arr['url']) {
- $url = $arr['url'];
- }
- else {
- $randfunc = db_getfunc('RAND');
-
- // fixme this query does not deal with directory realms.
-
- $r = q("select site_url, site_pull from site where site_url != '%s' and site_flags != %d and site_type = %d and site_dead = 0 order by $randfunc limit 1",
- dbesc(z_root()),
- intval(DIRECTORY_MODE_STANDALONE),
- intval(SITE_TYPE_ZOT)
- );
- if($r)
- $url = $r[0]['site_url'];
- }
-
- $blacklisted = false;
-
- if(! check_siteallowed($url)) {
- logger('blacklisted site: ' . $url);
- $blacklisted = true;
- }
-
- $attempts ++;
-
- // make sure we can eventually break out if somebody blacklists all known sites
-
- if($blacklisted) {
- if($attempts > 20)
- break;
- $attempts --;
- continue;
- }
-
- if($url) {
- if($r[0]['site_pull'] !== NULL_DATE)
- $mindate = urlencode(datetime_convert('','',$r[0]['site_pull'] . ' - 1 day'));
- else {
- $days = get_config('externals','since_days');
- if($days === false)
- $days = 15;
- $mindate = urlencode(datetime_convert('','','now - ' . intval($days) . ' days'));
- }
-
- $feedurl = $url . '/zotfeed?f=&mindate=' . $mindate;
-
- logger('externals: pulling public content from ' . $feedurl, LOGGER_DEBUG);
-
- $x = z_fetch_url($feedurl);
- if(($x) && ($x['success'])) {
-
- q("update site set site_pull = '%s' where site_url = '%s'",
- dbesc(datetime_convert()),
- dbesc($url)
- );
-
- $j = json_decode($x['body'],true);
- if($j['success'] && $j['messages']) {
- $sys = get_sys_channel();
- foreach($j['messages'] as $message) {
- // on these posts, clear any route info.
- $message['route'] = '';
- $results = process_delivery(array('hash' => 'undefined'), get_item_elements($message),
- array(array('hash' => $sys['xchan_hash'])), false, true);
- $total ++;
- }
- logger('externals: import_public_posts: ' . $total . ' messages imported', LOGGER_DEBUG);
- }
- }
- }
- }
-}
-
-if (array_search(__file__,get_included_files())===0){
- externals_run($argv,$argc);
- killme();
-}
diff --git a/include/features.php b/include/features.php
index 38700f9f5..6d38bcfb4 100644
--- a/include/features.php
+++ b/include/features.php
@@ -94,6 +94,7 @@ function get_features($filtered = true) {
t('Post/Comment Tools'),
array('commtag', t('Community Tagging'), t('Ability to tag existing posts'),false,get_config('feature_lock','commtag')),
array('categories', t('Post Categories'), t('Add categories to your posts'),false,get_config('feature_lock','categories')),
+ array('emojis', t('Emoji Reactions'), t('Add emoji reaction ability to posts'),true,get_config('feature_lock','emojis')),
array('filing', t('Saved Folders'), t('Ability to file posts under folders'),false,get_config('feature_lock','filing')),
array('dislike', t('Dislike Posts'), t('Ability to dislike posts/comments'),false,get_config('feature_lock','dislike')),
array('star_posts', t('Star Posts'), t('Ability to mark special posts with a star indicator'),false,get_config('feature_lock','star_posts')),
diff --git a/include/feedutils.php b/include/feedutils.php
new file mode 100644
index 000000000..685b2f982
--- /dev/null
+++ b/include/feedutils.php
@@ -0,0 +1,1315 @@
+ '1',
+ 'datequery' => $params['end'],
+ 'datequery2' => $params['begin'],
+ 'start' => $params['start'], // FIXME
+ 'records' => $params['records'], // FIXME
+ 'direction' => $params['direction'], // FIXME
+ 'pages' => $params['pages'],
+ 'order' => 'post',
+ 'top' => $params['top'],
+ 'cat' => $params['cat']
+ ), $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module);
+
+
+ $feed_template = get_markup_template('atom_feed.tpl');
+
+ $atom = '';
+
+ $atom .= replace_macros($feed_template, array(
+ '$version' => xmlify(Zotlabs\Lib\System::get_project_version()),
+ '$red' => xmlify(Zotlabs\Lib\System::get_platform_name()),
+ '$feed_id' => xmlify($channel['xchan_url']),
+ '$feed_title' => xmlify($channel['channel_name']),
+ '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) ,
+ '$hub' => '', // feed_hublinks(),
+ '$salmon' => '', // feed_salmonlinks($channel['channel_address']),
+ '$name' => xmlify($channel['channel_name']),
+ '$profile_page' => xmlify($channel['xchan_url']),
+ '$mimephoto' => xmlify($channel['xchan_photo_mimetype']),
+ '$photo' => xmlify($channel['xchan_photo_l']),
+ '$thumb' => xmlify($channel['xchan_photo_m']),
+ '$picdate' => '',
+ '$uridate' => '',
+ '$namdate' => '',
+ '$birthday' => '',
+ '$community' => '',
+ ));
+
+
+ call_hooks('atom_feed', $atom);
+
+ if($items) {
+ $type = 'html';
+ foreach($items as $item) {
+ if($item['item_private'])
+ continue;
+
+ /** @BUG $owner is undefined in this call */
+ $atom .= atom_entry($item, $type, null, $owner, true);
+ }
+ }
+
+ call_hooks('atom_feed_end', $atom);
+
+ $atom .= '' . "\r\n";
+
+ return $atom;
+}
+
+/**
+ * @brief
+ *
+ * @param array $item an associative array with
+ * * \b string \b verb
+ * @return string item's verb if set, default ACTIVITY_POST see boot.php
+ */
+function construct_verb($item) {
+ if ($item['verb'])
+ return $item['verb'];
+
+ return ACTIVITY_POST;
+}
+
+function construct_activity_object($item) {
+
+ if($item['obj']) {
+ $o = '' . "\r\n";
+ $r = json_decode($item['obj'],false);
+
+ if(! $r)
+ return '';
+ if($r->type)
+ $o .= '' . xmlify($r->type) . ' ' . "\r\n";
+ if($r->id)
+ $o .= '' . xmlify($r->id) . ' ' . "\r\n";
+ if($r->title)
+ $o .= '' . xmlify($r->title) . ' ' . "\r\n";
+ if($r->links) {
+ /** @FIXME!! */
+ if(substr($r->link,0,1) === '<') {
+ $r->link = preg_replace('/\ /',' ',$r->link);
+ $o .= $r->link;
+ }
+ else
+ $o .= ' ' . "\r\n";
+ }
+ if($r->content)
+ $o .= '' . xmlify(bbcode($r->content)) . ' ' . "\r\n";
+ $o .= ' ' . "\r\n";
+ return $o;
+ }
+
+ return '';
+}
+
+function construct_activity_target($item) {
+
+ if($item['target']) {
+ $o = '' . "\r\n";
+ $r = json_decode($item['target'],false);
+ if(! $r)
+ return '';
+ if($r->type)
+ $o .= '' . xmlify($r->type) . ' ' . "\r\n";
+ if($r->id)
+ $o .= '' . xmlify($r->id) . ' ' . "\r\n";
+ if($r->title)
+ $o .= '' . xmlify($r->title) . ' ' . "\r\n";
+ if($r->links) {
+ /** @FIXME !!! */
+ if(substr($r->link,0,1) === '<') {
+ if(strstr($r->link,'&') && (! strstr($r->link,'&')))
+ $r->link = str_replace('&','&', $r->link);
+ $r->link = preg_replace('/\ /',' ',$r->link);
+ $o .= $r->link;
+ }
+ else
+ $o .= ' ' . "\r\n";
+ }
+ if($r->content)
+ $o .= '' . xmlify(bbcode($r->content)) . ' ' . "\r\n";
+
+ $o .= ' ' . "\r\n";
+
+ return $o;
+ }
+
+ return '';
+}
+
+/**
+ * @param object $feed
+ * @param array $item
+ * @param[out] array $author
+ * @return multitype:multitype: string NULL number Ambigous Ambigous Ambigous , multitype:multitype:string unknown > multitype:NULL unknown
+ */
+function get_atom_elements($feed, $item, &$author) {
+
+ //$best_photo = array();
+
+ $res = array();
+
+ $found_author = $item->get_author();
+ if($found_author) {
+ $author['author_name'] = unxmlify($found_author->get_name());
+ $author['author_link'] = unxmlify($found_author->get_link());
+ $author['author_is_feed'] = false;
+ }
+ else {
+ $author['author_name'] = unxmlify($feed->get_title());
+ $author['author_link'] = unxmlify($feed->get_permalink());
+ $author['author_is_feed'] = true;
+ }
+
+ if(substr($author['author_link'],-1,1) == '/')
+ $author['author_link'] = substr($author['author_link'],0,-1);
+
+ $res['mid'] = base64url_encode(unxmlify($item->get_id()));
+ $res['title'] = unxmlify($item->get_title());
+ $res['body'] = unxmlify($item->get_content());
+ $res['plink'] = unxmlify($item->get_link(0));
+ $res['item_rss'] = 1;
+
+
+ // removing the content of the title if its identically to the body
+ // This helps with auto generated titles e.g. from tumblr
+
+ if (title_is_body($res["title"], $res["body"]))
+ $res['title'] = "";
+
+ if($res['plink'])
+ $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
+ else
+ $base_url = '';
+
+ // look for a photo. We should check media size and find the best one,
+ // but for now let's just find any author photo
+
+ $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
+
+ if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
+ $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+ foreach($base as $link) {
+ if(!x($author, 'author_photo') || ! $author['author_photo']) {
+ if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
+
+ $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
+
+ if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
+ $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+ if($base && count($base)) {
+ foreach($base as $link) {
+ if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
+ $author['author_link'] = unxmlify($link['attribs']['']['href']);
+ if(!x($author, 'author_photo') || ! $author['author_photo']) {
+ if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
+ }
+
+ // check for a yahoo media element (github etc.)
+
+ if(! $author['author_photo']) {
+ $rawmedia = $item->get_item_tags(NAMESPACE_YMEDIA,'thumbnail');
+ if($rawmedia && $rawmedia[0]['attribs']['']['url']) {
+ $author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url']));
+ }
+ }
+
+
+ // No photo/profile-link on the item - look at the feed level
+
+ if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) {
+ $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
+ if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
+ $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+ foreach($base as $link) {
+ if($link['attribs']['']['rel'] === 'alternate' && (! $author['author_link'])) {
+ $author['author_link'] = unxmlify($link['attribs']['']['href']);
+ $author['author_is_feed'] = true;
+ }
+ if(! $author['author_photo']) {
+ if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
+
+ $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
+
+ if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
+ $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+
+ if($base && count($base)) {
+ foreach($base as $link) {
+ if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
+ $author['author_link'] = unxmlify($link['attribs']['']['href']);
+ if(! (x($author,'author_photo'))) {
+ if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
+ }
+ }
+
+ $apps = $item->get_item_tags(NAMESPACE_STATUSNET,'notice_info');
+ if($apps && $apps[0]['attribs']['']['source']) {
+ $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
+ }
+
+ /*
+ * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it.
+ */
+
+ $have_real_body = false;
+
+ $rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
+ if($rawenv) {
+ $have_real_body = true;
+ $res['body'] = $rawenv[0]['data'];
+ $res['body'] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$res['body']);
+ // make sure nobody is trying to sneak some html tags by us
+ $res['body'] = notags(base64url_decode($res['body']));
+
+ // We could probably turn these old Friendica bbcode bookmarks into bookmark tags but we'd have to
+ // create a term table item for them. For now just make sure they stay as links.
+
+ $res['body'] = preg_replace('/\[bookmark(.*?)\](.*?)\[\/bookmark\]/','[url$1]$2[/url]',$res['body']);
+ }
+
+ $res['body'] = limit_body_size($res['body']);
+
+ // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
+ // the content type. Our own network only emits text normally, though it might have been converted to
+ // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will
+ // have to assume it is all html and needs to be purified.
+
+ // It doesn't matter all that much security wise - because before this content is used anywhere, we are
+ // going to escape any tags we find regardless, but this lets us import a limited subset of html from
+ // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
+ // html.
+
+ if((strpos($res['body'],'<') !== false) && (strpos($res['body'],'>') !== false)) {
+
+ $res['body'] = reltoabs($res['body'],$base_url);
+
+ $res['body'] = html2bb_video($res['body']);
+
+ $res['body'] = oembed_html2bbcode($res['body']);
+
+ $res['body'] = purify_html($res['body']);
+
+ $res['body'] = @html2bbcode($res['body']);
+ }
+ elseif(! $have_real_body) {
+
+ // it's not one of our messages and it has no tags
+ // so it's probably just text. We'll escape it just to be safe.
+
+ $res['body'] = escape_tags($res['body']);
+ }
+
+ if($res['plink'] && $res['title']) {
+ $res['body'] = '#^[url=' . $res['plink'] . ']' . $res['title'] . '[/url]' . "\n\n" . $res['body'];
+ $terms = array();
+ $terms[] = array(
+ 'otype' => TERM_OBJ_POST,
+ 'type' => TERM_BOOKMARK,
+ 'url' => $res['plink'],
+ 'term' => $res['title'],
+ );
+ }
+ elseif($res['plink']) {
+ $res['body'] = '#^[url]' . $res['plink'] . '[/url]' . "\n\n" . $res['body'];
+ $terms = array();
+ $terms[] = array(
+ 'otype' => TERM_OBJ_POST,
+ 'type' => TERM_BOOKMARK,
+ 'url' => $res['plink'],
+ 'term' => $res['plink'],
+ );
+ }
+
+ $private = $item->get_item_tags(NAMESPACE_DFRN,'private');
+ if($private && intval($private[0]['data']) > 0)
+ $res['item_private'] = ((intval($private[0]['data'])) ? 1 : 0);
+ else
+ $res['item_private'] = 0;
+
+ $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location');
+ if($rawlocation)
+ $res['location'] = unxmlify($rawlocation[0]['data']);
+
+ $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'published');
+ if($rawcreated)
+ $res['created'] = unxmlify($rawcreated[0]['data']);
+
+ $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'updated');
+ if($rawedited)
+ $res['edited'] = unxmlify($rawedited[0]['data']);
+
+ if((x($res,'edited')) && (! (x($res,'created'))))
+ $res['created'] = $res['edited'];
+
+ if(! $res['created'])
+ $res['created'] = $item->get_date('c');
+
+ if(! $res['edited'])
+ $res['edited'] = $item->get_date('c');
+
+
+ // Disallow time travelling posts
+
+ $d1 = strtotime($res['created']);
+ $d2 = strtotime($res['edited']);
+ $d3 = strtotime('now');
+
+ if($d1 > $d3)
+ $res['created'] = datetime_convert();
+ if($d2 > $d3)
+ $res['edited'] = datetime_convert();
+
+ $res['created'] = datetime_convert('UTC','UTC',$res['created']);
+ $res['edited'] = datetime_convert('UTC','UTC',$res['edited']);
+
+ $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
+ if(! $rawowner)
+ $rawowner = $item->get_item_tags(NAMESPACE_ZOT,'owner');
+
+ if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])
+ $author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
+ elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data'])
+ $author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
+ if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
+ $author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
+ elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])
+ $author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
+
+ if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
+ $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+
+ foreach($base as $link) {
+ if(!x($author, 'owner_photo') || ! $author['owner_photo']) {
+ if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
+ $author['owner_photo'] = unxmlify($link['attribs']['']['href']);
+ }
+ }
+ }
+
+ $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS,'point');
+ if($rawgeo)
+ $res['coord'] = unxmlify($rawgeo[0]['data']);
+
+
+ $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
+
+ // select between supported verbs
+
+ if($rawverb) {
+ $res['verb'] = unxmlify($rawverb[0]['data']);
+ }
+
+ // translate OStatus unfollow to activity streams if it happened to get selected
+
+ if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow'))
+ $res['verb'] = ACTIVITY_UNFOLLOW;
+
+ $cats = $item->get_categories();
+ if($cats) {
+ if(is_null($terms))
+ $terms = array();
+ foreach($cats as $cat) {
+ $term = $cat->get_term();
+ if(! $term)
+ $term = $cat->get_label();
+ $scheme = $cat->get_scheme();
+ $termurl = '';
+ if($scheme && $term && stristr($scheme,'X-DFRN:')) {
+ $termtype = ((substr($scheme,7,1) === '#') ? TERM_HASHTAG : TERM_MENTION);
+ $termurl = unxmlify(substr($scheme,9));
+ }
+ else {
+ $termtype = TERM_CATEGORY;
+ }
+ $termterm = notags(trim(unxmlify($term)));
+
+ if($termterm) {
+ $terms[] = array(
+ 'otype' => TERM_OBJ_POST,
+ 'ttype' => $termtype,
+ 'url' => $termurl,
+ 'term' => $termterm,
+ );
+ }
+ }
+ }
+
+ if(! is_null($terms))
+ $res['term'] = $terms;
+
+ $attach = $item->get_enclosures();
+ if($attach) {
+ $res['attach'] = array();
+ foreach($attach as $att) {
+ $len = intval($att->get_length());
+ $link = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_link()))));
+ $title = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_title()))));
+ $type = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_type()))));
+ if(strpos($type,';'))
+ $type = substr($type,0,strpos($type,';'));
+ if((! $link) || (strpos($link,'http') !== 0))
+ continue;
+
+ if(! $title)
+ $title = ' ';
+ if(! $type)
+ $type = 'application/octet-stream';
+
+ $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title );
+ }
+ }
+
+ $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
+
+ if($rawobj) {
+ $obj = array();
+
+ $child = $rawobj[0]['child'];
+ if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
+ $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
+ $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
+ }
+ if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
+ $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
+ $obj['type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
+ }
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'])
+ $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link'])
+ $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'])
+ $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
+ $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
+ if(! $body)
+ $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
+ // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
+ $obj['orig'] = xmlify($body);
+ if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
+ $body = purify_html($body);
+ $body = html2bbcode($body);
+ }
+
+ $obj['content'] = $body;
+ }
+
+ $res['obj'] = $obj;
+ }
+
+ $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target');
+
+ if($rawobj) {
+ $obj = array();
+
+ $child = $rawobj[0]['child'];
+ if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
+ $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
+ $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
+ }
+ if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
+ $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
+ $obj['type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
+ }
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'])
+ $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link'])
+ $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'])
+ $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
+ if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
+ $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
+ if(! $body)
+ $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
+
+ // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
+ $obj['orig'] = xmlify($body);
+ if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
+ $body = purify_html($body);
+ $body = html2bbcode($body);
+ }
+
+ $obj['content'] = $body;
+ }
+
+ $res['target'] = $obj;
+ }
+
+ $arr = array('feed' => $feed, 'item' => $item, 'result' => $res);
+
+ call_hooks('parse_atom', $arr);
+ logger('get_atom_elements: author: ' . print_r($author,true),LOGGER_DATA);
+
+ logger('get_atom_elements: ' . print_r($res,true),LOGGER_DATA);
+
+ return $res;
+}
+
+function encode_rel_links($links) {
+ $o = array();
+ if(! ((is_array($links)) && (count($links))))
+ return $o;
+
+ foreach($links as $link) {
+ $l = array();
+ if($link['attribs']['']['rel'])
+ $l['rel'] = $link['attribs']['']['rel'];
+ if($link['attribs']['']['type'])
+ $l['type'] = $link['attribs']['']['type'];
+ if($link['attribs']['']['href'])
+ $l['href'] = $link['attribs']['']['href'];
+ if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['width'])
+ $l['width'] = $link['attribs'][NAMESPACE_MEDIA]['width'];
+ if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['height'])
+ $l['height'] = $link['attribs'][NAMESPACE_MEDIA]['height'];
+
+ if($l)
+ $o[] = $l;
+ }
+ return $o;
+}
+
+/**
+ * @brief Process atom feed and update anything/everything we might need to update.
+ *
+ * @param array $xml
+ * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
+ * @param $importer
+ * The contact_record (joined to user_record) of the local user who owns this
+ * relationship. It is this person's stuff that is going to be updated.
+ * @param $contact
+ * The person who is sending us stuff. If not set, we MAY be processing a "follow" activity
+ * from an external network and MAY create an appropriate contact record. Otherwise, we MUST
+ * have a contact record.
+ * @param int $pass by default ($pass = 0) we cannot guarantee that a parent item has been
+ * imported prior to its children being seen in the stream unless we are certain
+ * of how the feed is arranged/ordered.
+ * * With $pass = 1, we only pull parent items out of the stream.
+ * * With $pass = 2, we only pull children (comments/likes).
+ *
+ * So running this twice, first with pass 1 and then with pass 2 will do the right
+ * thing regardless of feed ordering. This won't be adequate in a fully-threaded
+ * model where comments can have sub-threads. That would require some massive sorting
+ * to get all the feed items into a mostly linear ordering, and might still require
+ * recursion.
+ */
+function consume_feed($xml, $importer, &$contact, $pass = 0) {
+
+ require_once('library/simplepie/simplepie.inc');
+
+ if(! strlen($xml)) {
+ logger('consume_feed: empty input');
+ return;
+ }
+
+ $sys_expire = intval(get_config('system','default_expire_days'));
+ $chn_expire = intval($importer['channel_expire_days']);
+
+ $expire_days = $sys_expire;
+
+ if(($chn_expire != 0) && ($chn_expire < $sys_expire))
+ $expire_days = $chn_expire;
+
+ // logger('expire_days: ' . $expire_days);
+
+ $feed = new SimplePie();
+ $feed->set_raw_data($xml);
+ $feed->init();
+
+ if($feed->error())
+ logger('consume_feed: Error parsing XML: ' . $feed->error());
+
+ $permalink = $feed->get_permalink();
+
+ // Check at the feed level for updated contact name and/or photo
+
+ // process any deleted entries
+
+ $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
+ if(is_array($del_entries) && count($del_entries) && $pass != 2) {
+ foreach($del_entries as $dentry) {
+ $deleted = false;
+ if(isset($dentry['attribs']['']['ref'])) {
+ $mid = $dentry['attribs']['']['ref'];
+ $deleted = true;
+ if(isset($dentry['attribs']['']['when'])) {
+ $when = $dentry['attribs']['']['when'];
+ $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
+ }
+ else
+ $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
+ }
+
+ if($deleted && is_array($contact)) {
+ $r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1",
+ dbesc(base64url_encode($mid)),
+ dbesc($contact['xchan_hash']),
+ intval($importer['channel_id'])
+ );
+
+ if($r) {
+ $item = $r[0];
+
+ if(! intval($item['item_deleted'])) {
+ logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG);
+ drop_item($item['id'],false);
+ }
+ }
+ }
+ }
+ }
+
+ // Now process the feed
+
+ if($feed->get_item_quantity()) {
+
+ logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
+
+ $items = $feed->get_items();
+
+ foreach($items as $item) {
+
+ $is_reply = false;
+ $item_id = base64url_encode($item->get_id());
+
+ logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG);
+
+ $rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
+ if(isset($rawthread[0]['attribs']['']['ref'])) {
+ $is_reply = true;
+ $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
+ }
+
+ if($is_reply) {
+
+ if($pass == 1)
+ continue;
+
+ // Have we seen it? If not, import it.
+
+ $item_id = base64url_encode($item->get_id());
+ $author = array();
+ $datarray = get_atom_elements($feed,$item,$author);
+
+ if($contact['xchan_network'] === 'rss') {
+ $datarray['public_policy'] = 'specific';
+ $datarray['comment_policy'] = 'none';
+ }
+
+ if((! x($author,'author_name')) || ($author['author_is_feed']))
+ $author['author_name'] = $contact['xchan_name'];
+ if((! x($author,'author_link')) || ($author['author_is_feed']))
+ $author['author_link'] = $contact['xchan_url'];
+ if((! x($author,'author_photo'))|| ($author['author_is_feed']))
+ $author['author_photo'] = $contact['xchan_photo_m'];
+
+ $datarray['author_xchan'] = '';
+
+ if($author['author_link'] != $contact['xchan_url']) {
+ $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
+ if($x)
+ $datarray['author_xchan'] = $x;
+ }
+ if(! $datarray['author_xchan'])
+ $datarray['author_xchan'] = $contact['xchan_hash'];
+
+ $datarray['owner_xchan'] = $contact['xchan_hash'];
+
+ $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
+ dbesc($item_id),
+ intval($importer['channel_id'])
+ );
+
+
+ // Update content if 'updated' changes
+
+ if($r) {
+ if((x($datarray,'edited') !== false)
+ && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+
+ // do not accept (ignore) an earlier edit than one we currently have.
+ if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
+ continue;
+
+ update_feed_item($importer['channel_id'],$datarray);
+ }
+ continue;
+ }
+
+ $datarray['parent_mid'] = $parent_mid;
+ $datarray['aid'] = $importer['channel_account_id'];
+ $datarray['uid'] = $importer['channel_id'];
+
+ logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA);
+
+ $xx = item_store($datarray);
+ $r = $xx['item_id'];
+ continue;
+ }
+ else {
+
+ // Head post of a conversation. Have we seen it? If not, import it.
+
+ $item_id = base64url_encode($item->get_id());
+ $author = array();
+ $datarray = get_atom_elements($feed,$item,$author);
+
+ if($contact['xchan_network'] === 'rss') {
+ $datarray['public_policy'] = 'specific';
+ $datarray['comment_policy'] = 'none';
+ }
+
+
+ if(is_array($contact)) {
+ if((! x($author,'author_name')) || ($author['author_is_feed']))
+ $author['author_name'] = $contact['xchan_name'];
+ if((! x($author,'author_link')) || ($author['author_is_feed']))
+ $author['author_link'] = $contact['xchan_url'];
+ if((! x($author,'author_photo'))|| ($author['author_is_feed']))
+ $author['author_photo'] = $contact['xchan_photo_m'];
+ }
+
+ if((! x($author,'author_name')) || (! x($author,'author_link'))) {
+ logger('consume_feed: no author information! ' . print_r($author,true));
+ continue;
+ }
+
+ $datarray['author_xchan'] = '';
+
+ if(activity_match($datarray['verb'],ACTIVITY_FOLLOW) && $datarray['obj_type'] === ACTIVITY_OBJ_PERSON) {
+ $cb = array('item' => $datarray,'channel' => $importer, 'xchan' => null, 'author' => $author, 'caught' => false);
+ call_hooks('follow_from_feed',$cb);
+ if($cb['caught']) {
+ if($cb['return_code'])
+ http_status_exit($cb['return_code']);
+ continue;
+ }
+ }
+
+ if($author['author_link'] != $contact['xchan_url']) {
+ $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
+ if($x)
+ $datarray['author_xchan'] = $x;
+ }
+ if(! $datarray['author_xchan'])
+ $datarray['author_xchan'] = $contact['xchan_hash'];
+
+ $datarray['owner_xchan'] = $contact['xchan_hash'];
+
+ if(array_key_exists('created',$datarray) && $datarray['created'] != NULL_DATE && $expire_days) {
+ $t1 = $datarray['created'];
+ $t2 = datetime_convert('UTC','UTC','now - ' . $expire_days . 'days');
+ if($t1 < $t2) {
+ logger('feed content older than expiration. Ignoring.', LOGGER_DEBUG, LOG_INFO);
+ continue;
+ }
+ }
+
+
+
+ $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
+ dbesc($item_id),
+ intval($importer['channel_id'])
+ );
+
+ // Update content if 'updated' changes
+
+ if($r) {
+ if((x($datarray,'edited') !== false)
+ && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
+
+ // do not accept (ignore) an earlier edit than one we currently have.
+ if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
+ continue;
+
+ update_feed_item($importer['channel_id'],$datarray);
+ }
+
+ continue;
+ }
+
+ $datarray['parent_mid'] = $item_id;
+ $datarray['uid'] = $importer['channel_id'];
+ $datarray['aid'] = $importer['channel_account_id'];
+
+ if(! link_compare($author['owner_link'],$contact['xchan_url'])) {
+ logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
+ $author['owner_name'] = $contact['name'];
+ $author['owner_link'] = $contact['url'];
+ $author['owner_avatar'] = $contact['thumb'];
+ }
+
+ if(! post_is_importable($datarray,$contact))
+ continue;
+
+ logger('consume_feed: author ' . print_r($author,true),LOGGER_DEBUG);
+
+ logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA);
+
+ $xx = item_store($datarray);
+ $r = $xx['item_id'];
+ continue;
+ }
+ }
+ }
+}
+
+
+/**
+ * @brief Process atom feed and return the first post and structure
+ *
+ * @param array $xml
+ * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
+ * @param $importer
+ * The contact_record (joined to user_record) of the local user who owns this
+ * relationship. It is this person's stuff that is going to be updated.
+ */
+
+function process_salmon_feed($xml, $importer) {
+
+ $ret = array();
+
+ require_once('library/simplepie/simplepie.inc');
+
+ if(! strlen($xml)) {
+ logger('process_feed: empty input');
+ return;
+ }
+
+ $feed = new SimplePie();
+ $feed->set_raw_data($xml);
+ $feed->init();
+
+ if($feed->error())
+ logger('Error parsing XML: ' . $feed->error());
+
+ $permalink = $feed->get_permalink();
+
+ if($feed->get_item_quantity()) {
+
+ // this should be exactly one
+
+ logger('feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
+
+ $items = $feed->get_items();
+
+ foreach($items as $item) {
+
+ $item_id = base64url_encode($item->get_id());
+
+ logger('processing ' . $item_id, LOGGER_DEBUG);
+
+ $rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
+ if(isset($rawthread[0]['attribs']['']['ref'])) {
+ $is_reply = true;
+ $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
+ }
+
+ if($is_reply)
+ $ret['parent_mid'] = $parent_mid;
+
+ $ret['author'] = array();
+
+ $datarray = get_atom_elements($feed,$item,$ret['author']);
+
+ // reset policies which are restricted by default for RSS connections
+ // This item is likely coming from GNU-social via salmon and allows public interaction
+ $datarray['public_policy'] = '';
+ $datarray['comment_policy'] = '';
+
+ $ret['item'] = $datarray;
+ }
+ }
+
+ return $ret;
+}
+
+/*
+ * Given an xml (atom) feed, find author and hub links
+ */
+
+
+function feed_meta($xml) {
+ require_once('library/simplepie/simplepie.inc');
+
+ $ret = array();
+
+ if(! strlen($xml)) {
+ logger('empty input');
+ return $ret;
+ }
+
+ $feed = new SimplePie();
+ $feed->set_raw_data($xml);
+ $feed->init();
+
+ if($feed->error()) {
+ logger('Error parsing XML: ' . $feed->error());
+ return $ret;
+ }
+
+ $ret['hubs'] = $feed->get_links('hub');
+
+// logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA);
+
+ $author = array();
+
+ $found_author = $feed->get_author();
+ if($found_author) {
+ $author['author_name'] = unxmlify($found_author->get_name());
+ $author['author_link'] = unxmlify($found_author->get_link());
+
+ $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
+ logger('rawauthor: ' . print_r($rawauthor,true));
+
+ if($rawauthor) {
+ if($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
+ $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
+ foreach($base as $link) {
+ if(!x($author, 'author_photo') || ! $author['author_photo']) {
+ if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
+ $author['author_photo'] = unxmlify($link['attribs']['']['href']);
+ break;
+ }
+ }
+ }
+ }
+ if($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data'])
+ $author['full_name'] = unxmlify($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']);
+ if($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
+ $author['author_uri'] = unxmlify($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
+
+ }
+ }
+
+ if(substr($author['author_link'],-1,1) == '/')
+ $author['author_link'] = substr($author['author_link'],0,-1);
+
+ $ret['author'] = $author;
+
+ return $ret;
+}
+
+
+
+function update_feed_item($uid,$datarray) {
+ logger('update_feed_item: not implemented! ' . $uid . ' ' . print_r($datarray,true), LOGGER_DATA);
+}
+
+
+function handle_feed($uid,$abook_id,$url) {
+
+ $channel = channelx_by_n($uid);
+ if(! $channel)
+ return;
+
+ $x = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d limit 1",
+ dbesc($abook_id),
+ intval($uid)
+ );
+
+ $recurse = 0;
+ $z = z_fetch_url($url,false,$recurse,array('novalidate' => true));
+
+//logger('handle_feed:' . print_r($z,true));
+
+ if($z['success']) {
+ consume_feed($z['body'],$channel,$x[0],1);
+ consume_feed($z['body'],$channel,$x[0],2);
+ }
+}
+
+
+function atom_author($tag,$name,$uri,$h,$w,$type,$photo) {
+ $o = '';
+ if(! $tag)
+ return $o;
+
+ $name = xmlify($name);
+ $uri = xmlify($uri);
+ $h = intval($h);
+ $w = intval($w);
+ $photo = xmlify($photo);
+
+ $o .= "<$tag>\r\n";
+ $o .= "$name \r\n";
+ $o .= "$uri \r\n";
+ $o .= ' ' . "\r\n";
+ $o .= ' ' . "\r\n";
+
+ call_hooks('atom_author', $o);
+
+ $o .= "$tag>\r\n";
+
+ return $o;
+}
+
+function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
+
+ if(! $item['parent'])
+ return;
+
+ if($item['deleted'])
+ return ' ' . "\r\n";
+
+
+ create_export_photo_body($item);
+
+ if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
+ $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid);
+ else
+ $body = $item['body'];
+
+ $o = "\r\n\r\n\r\n";
+
+ if(is_array($author))
+ $o .= atom_author('author',$author['xchan_name'],$author['xchan_url'],80,80,$author['xchan_photo_mimetype'],$author['xchan_photo_m']);
+ else
+ $o .= atom_author('author',$item['author']['xchan_name'],$item['author']['xchan_url'],80,80,$item['author']['xchan_photo_mimetype'], $item['author']['xchan_photo_m']);
+
+ $o .= atom_author('zot:owner',$item['owner']['xchan_name'],$item['owner']['xchan_url'],80,80,$item['owner']['xchan_photo_mimetype'],$item['owner']['xchan_photo_m']);
+
+ if(($item['parent'] != $item['id']) || ($item['parent_mid'] !== $item['mid']) || (($item['thr_parent'] !== '') && ($item['thr_parent'] !== $item['mid']))) {
+ $parent_item = (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']);
+ $o .= ' ' . "\r\n";
+ }
+
+ if(activity_match($item['obj_type'],ACTIVITY_OBJ_EVENT) && activity_match($item['verb'],ACTIVITY_POST)) {
+ $obj = ((is_array($item['obj'])) ? $item['obj'] : json_decode($item['obj'],true));
+
+ $o .= '' . xmlify($item['title']) . ' ' . "\r\n";
+ $o .= '' . xmlify(bbcode($obj['title'])) . ' ' . "\r\n";
+ $o .= '' . datetime_convert('UTC','UTC', $obj['dtstart'],'Ymd\\THis' . (($obj['adjust']) ? '\\Z' : '')) . ' ' . "\r\n";
+ $o .= '' . datetime_convert('UTC','UTC', $obj['dtend'],'Ymd\\THis' . (($obj['adjust']) ? '\\Z' : '')) . ' ' . "\r\n";
+ $o .= '' . xmlify(bbcode($obj['location'])) . ' ' . "\r\n";
+ $o .= '' . xmlify(bbcode($obj['description'])) . ' ' . "\r\n";
+ }
+ else {
+ $o .= '' . xmlify($item['title']) . ' ' . "\r\n";
+ $o .= '' . xmlify(prepare_text($body,$item['mimetype'])) . ' ' . "\r\n";
+ }
+
+ $o .= '' . z_root() . '/display/' . xmlify($item['mid']) . ' ' . "\r\n";
+ $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . ' ' . "\r\n";
+ $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . ' ' . "\r\n";
+
+ $o .= ' ' . "\r\n";
+
+ if($item['location']) {
+ $o .= '' . xmlify($item['location']) . ' ' . "\r\n";
+ $o .= '' . xmlify($item['location']) . ' ' . "\r\n";
+ }
+
+ if($item['coord'])
+ $o .= '' . xmlify($item['coord']) . ' ' . "\r\n";
+
+ if(($item['item_private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']))
+ $o .= '' . (($item['item_private']) ? $item['item_private'] : 1) . ' ' . "\r\n";
+
+ if($item['app'])
+ $o .= ' ' . "\r\n";
+
+ $verb = construct_verb($item);
+ $o .= '' . xmlify($verb) . ' ' . "\r\n";
+ $actobj = construct_activity_object($item);
+ if(strlen($actobj))
+ $o .= $actobj;
+ $actarg = construct_activity_target($item);
+ if(strlen($actarg))
+ $o .= $actarg;
+
+ // FIXME
+// $tags = item_getfeedtags($item);
+// if(count($tags)) {
+// foreach($tags as $t) {
+// $o .= ' ' . "\r\n";
+// }
+// }
+
+// FIXME
+// $o .= item_getfeedattach($item);
+
+// $mentioned = get_mentions($item,$tags);
+// if($mentioned)
+// $o .= $mentioned;
+
+ call_hooks('atom_entry', $o);
+
+ $o .= ' ' . "\r\n";
+
+ return $o;
+}
+
+
+function gen_asld($items) {
+ $ret = array();
+ if(! $items)
+ return $ret;
+ foreach($items as $item) {
+ $ret[] = i2asld($item);
+ }
+ return $ret;
+}
+
+
+function i2asld($i) {
+
+ if(! $i)
+ return array();
+
+ $ret = array();
+
+ $ret['@context'] = array( 'http://www.w3.org/ns/activitystreams', 'zot' => 'http://purl.org/zot/protocol');
+
+ if($i['verb']) {
+ if(strpos(dirname($i['verb'],'activitystrea.ms/schema/1.0'))) {
+ $ret['@type'] = ucfirst(basename($i['verb']));
+ }
+ elseif(strpos(dirname($i['verb'],'purl.org/zot'))) {
+ $ret['@type'] = 'zot:' . ucfirst(basename($i['verb']));
+ }
+ }
+ $ret['@id'] = $i['plink'];
+
+ $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME);
+
+ // we need to pass the parent into this
+// if($i['id'] != $i['parent'] && $i['obj_type'] === ACTIVITY_OBJ_NOTE) {
+// $ret['inReplyTo'] = asencode_note
+// }
+
+ if($i['obj_type'] === ACTIVITY_OBJ_NOTE)
+ $ret['object'] = asencode_note($i);
+
+
+ $ret['actor'] = asencode_person($i['author']);
+
+
+ return $ret;
+
+}
+
+function asencode_note($i) {
+
+ $ret = array();
+
+ $ret['@type'] = 'Note';
+ $ret['@id'] = $i['plink'];
+ if($i['title'])
+ $ret['title'] = bbcode($i['title']);
+ $ret['content'] = bbcode($i['body']);
+ $ret['zot:owner'] = asencode_person($i['owner']);
+ $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME);
+ if($i['created'] !== $i['edited'])
+ $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME);
+
+ return $ret;
+}
+
+
+function asencode_person($p) {
+ $ret = array();
+ $ret['@type'] = 'Person';
+ $ret['@id'] = 'acct:' . $p['xchan_addr'];
+ $ret['displayName'] = $p['xchan_name'];
+ $ret['icon'] = array(
+ '@type' => 'Link',
+ 'mediaType' => $p['xchan_photo_mimetype'],
+ 'href' => $p['xchan_photo_m']
+ );
+ $ret['url'] = array(
+ '@type' => 'Link',
+ 'mediaType' => 'text/html',
+ 'href' => $p['xchan_url']
+ );
+
+ return $ret;
+}
diff --git a/include/follow.php b/include/follow.php
index 70e717cfc..e5a74f85e 100644
--- a/include/follow.php
+++ b/include/follow.php
@@ -17,7 +17,6 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
$result = array('success' => false,'message' => '');
- $a = get_app();
$is_red = false;
$is_http = ((strpos($url,'://') !== false) ? true : false);
@@ -56,11 +55,11 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
if($arr['channel']['success'])
$ret = $arr['channel'];
elseif(! $is_http)
- $ret = zot_finger($url,$channel);
+ $ret = Zotlabs\Zot\Finger::run($url,$channel);
- if($ret && $ret['success']) {
+ if($ret && is_array($ret) && $ret['success']) {
$is_red = true;
- $j = json_decode($ret['body'],true);
+ $j = $ret;
}
$my_perms = get_channel_default_perms($uid);
@@ -269,14 +268,14 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
if($r) {
$result['abook'] = $r[0];
- proc_run('php', 'include/notifier.php', 'permission_create', $result['abook']['abook_id']);
+ Zotlabs\Daemon\Master::Summon(array('Notifier', 'permission_create', $result['abook']['abook_id']));
}
$arr = array('channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook']);
call_hooks('follow', $arr);
- /** If there is a default group for this channel, add this member to it */
+ /** If there is a default group for this channel, add this connection to it */
if($default_group) {
require_once('include/group.php');
diff --git a/include/gprobe.php b/include/gprobe.php
deleted file mode 100644
index d8d893d9e..000000000
--- a/include/gprobe.php
+++ /dev/null
@@ -1,38 +0,0 @@
- '', 'hash' => '0', 'selected' => '');
if(count($r)) {
foreach($r as $rr) {
- $grps[] = array('name' => $rr['name'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : ''));
+ $grps[] = array('name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : ''));
}
}
@@ -271,7 +271,7 @@ function group_side($every="connections",$each="group",$edit = false, $group_id
);
- $r = q("SELECT * FROM `groups` WHERE `deleted` = 0 AND `uid` = %d ORDER BY `name` ASC",
+ $r = q("SELECT * FROM `groups` WHERE `deleted` = 0 AND `uid` = %d ORDER BY `gname` ASC",
intval($_SESSION['uid'])
);
$member_of = array();
@@ -296,7 +296,7 @@ function group_side($every="connections",$each="group",$edit = false, $group_id
'id' => $rr['id'],
'enc_cid' => base64url_encode($cid),
'cid' => $cid,
- 'text' => $rr['name'],
+ 'text' => $rr['gname'],
'selected' => $selected,
'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''),
'edit' => $groupedit,
@@ -340,7 +340,7 @@ function expand_groups($a) {
function member_of($c) {
- $r = q("SELECT `groups`.`name`, `groups`.`id` FROM `groups` LEFT JOIN `group_member` ON `group_member`.`gid` = `groups`.`id` WHERE `group_member`.`xchan` = '%s' AND `groups`.`deleted` = 0 ORDER BY `groups`.`name` ASC ",
+ $r = q("SELECT `groups`.`gname`, `groups`.`id` FROM `groups` LEFT JOIN `group_member` ON `group_member`.`gid` = `groups`.`id` WHERE `group_member`.`xchan` = '%s' AND `groups`.`deleted` = 0 ORDER BY `groups`.`gname` ASC ",
dbesc($c)
);
diff --git a/include/help.php b/include/help.php
index 13473164d..5518eeb70 100644
--- a/include/help.php
+++ b/include/help.php
@@ -24,8 +24,6 @@ function find_doc_file($s) {
function search_doc_files($s) {
- $a = get_app();
-
$itemspage = get_pconfig(local_channel(),'system','itemspage');
\App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20));
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']), intval(\App::$pager['start']));
diff --git a/include/hubloc.php b/include/hubloc.php
index 695cada3c..397646449 100644
--- a/include/hubloc.php
+++ b/include/hubloc.php
@@ -106,7 +106,7 @@ function remove_obsolete_hublocs() {
dbesc($rr['hubloc_hash'])
);
if($x) {
- proc_run('php','include/notifier.php','location',$x[0]['channel_id']);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','location',$x[0]['channel_id']));
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
}
diff --git a/include/import.php b/include/import.php
index 00058047e..be456bfa9 100644
--- a/include/import.php
+++ b/include/import.php
@@ -20,6 +20,8 @@ function import_channel($channel, $account_id, $seize) {
dbesc($channel['channel_hash']),
dbesc($channel['channel_address'])
);
+ if($r && $r[0]['channel_guid'] == $channel['channel_guid'] && $r[0]['channel_pubkey'] === $channel['channel_pubkey'] && $r[0]['channel_hash'] === $channel['channel_hash'])
+ return $r[0];
if(($r) || (check_webbie(array($channel['channel_address'])) !== $channel['channel_address'])) {
if($r[0]['channel_guid'] === $channel['channel_guid'] || $r[0]['channel_hash'] === $channel['channel_hash']) {
@@ -120,6 +122,11 @@ function import_profiles($channel,$profiles) {
$profile['aid'] = get_account_id();
$profile['uid'] = $channel['channel_id'];
+ convert_oldfields($profile,'name','fullname');
+ convert_oldfields($profile,'with','partner');
+ convert_oldfields($profile,'work','employment');
+
+
// we are going to reset all profile photos to the original
// somebody will have to fix this later and put all the applicable photos into the export
@@ -330,7 +337,9 @@ function import_apps($channel,$apps) {
);
if($x) {
foreach($term as $t) {
- store_item_tag($channel['channel_id'],$x[0]['id'],TERM_OBJ_APP,$t['type'],escape_tags($t['term']),escape_tags($t['url']));
+ if(array_key_exists('type',$t))
+ $t['ttype'] = $t['type'];
+ store_item_tag($channel['channel_id'],$x[0]['id'],TERM_OBJ_APP,$t['ttype'],escape_tags($t['term']),escape_tags($t['url']));
}
}
}
@@ -398,7 +407,9 @@ function sync_apps($channel,$apps) {
if($exists && $term) {
foreach($term as $t) {
- store_item_tag($channel['channel_id'],$exists['id'],TERM_OBJ_APP,$t['type'],escape_tags($t['term']),escape_tags($t['url']));
+ if(array_key_exists('type',$t))
+ $t['ttype'] = $t['type'];
+ store_item_tag($channel['channel_id'],$exists['id'],TERM_OBJ_APP,$t['ttype'],escape_tags($t['term']),escape_tags($t['url']));
}
}
@@ -434,7 +445,9 @@ function sync_apps($channel,$apps) {
);
if($x) {
foreach($term as $t) {
- store_item_tag($channel['channel_id'],$x[0]['id'],TERM_OBJ_APP,$t['type'],escape_tags($t['term']),escape_tags($t['url']));
+ if(array_key_exists('type',$t))
+ $t['ttype'] = $t['type'];
+ store_item_tag($channel['channel_id'],$x[0]['id'],TERM_OBJ_APP,$t['ttype'],escape_tags($t['term']),escape_tags($t['url']));
}
}
}
@@ -574,7 +587,7 @@ function import_items($channel,$items,$sync = false) {
if($sync && $item['item_wall']) {
// deliver singletons if we have any
if($item_result && $item_result['success']) {
- proc_run('php','include/notifier.php','single_activity',$item_result['item_id']);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','single_activity',$item_result['item_id']));
}
}
continue;
@@ -588,7 +601,7 @@ function import_items($channel,$items,$sync = false) {
if($sync && $item['item_wall']) {
// deliver singletons if we have any
if($item_result && $item_result['success']) {
- proc_run('php','include/notifier.php','single_activity',$item_result['item_id']);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','single_activity',$item_result['item_id']));
}
}
}
@@ -636,6 +649,10 @@ function import_events($channel,$events) {
unset($event['id']);
$event['aid'] = $channel['channel_account_id'];
$event['uid'] = $channel['channel_id'];
+ convert_oldfields($event,'start','dtstart');
+ convert_oldfields($event,'finish','dtend');
+ convert_oldfields($event,'type','etype');
+ convert_oldfields($event,'ignore','dismissed');
dbesc_array($event);
$r = dbq("INSERT INTO event (`"
@@ -669,6 +686,12 @@ function sync_events($channel,$events) {
$event['aid'] = $channel['channel_account_id'];
$event['uid'] = $channel['channel_id'];
+ convert_oldfields($event,'start','dtstart');
+ convert_oldfields($event,'finish','dtend');
+ convert_oldfields($event,'type','etype');
+ convert_oldfields($event,'ignore','dismissed');
+
+
$exists = false;
$x = q("select * from event where event_hash = '%s' and uid = %d limit 1",
@@ -936,7 +959,7 @@ function import_mail($channel,$mails,$sync = false) {
$m['uid'] = $channel['channel_id'];
$mail_id = mail_store($m);
if($sync && $mail_id) {
- proc_run('php','include/notifier.php','single_mail',$mail_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','single_mail',$mail_id));
}
}
}
@@ -966,6 +989,8 @@ function sync_files($channel,$files) {
$attachment_stored = false;
foreach($f['attach'] as $att) {
+ convert_oldfields($att,'data','content');
+
if($att['deleted']) {
attach_delete($channel,$att['hash']);
continue;
@@ -973,8 +998,11 @@ function sync_files($channel,$files) {
$attach_exists = false;
$x = attach_by_hash($att['hash']);
+ logger('sync_files duplicate check: attach_exists=' . $attach_exists, LOGGER_DEBUG);
+ logger('sync_files duplicate check: att=' . print_r($att,true), LOGGER_DEBUG);
+ logger('sync_files duplicate check: attach_by_hash() returned ' . print_r($x,true), LOGGER_DEBUG);
- if($x) {
+ if($x['success']) {
$attach_exists = true;
$attach_id = $x[0]['id'];
}
@@ -1032,7 +1060,7 @@ function sync_files($channel,$files) {
// @fixme - update attachment structures if they are modified rather than created
- $att['data'] = $newfname;
+ $att['content'] = $newfname;
// Note: we use $att['hash'] below after it has been escaped to
// fetch the file contents.
@@ -1043,15 +1071,17 @@ function sync_files($channel,$files) {
if($attach_exists) {
- $str = '';
- foreach($att as $k => $v) {
- if($str)
- $str .= ",";
- $str .= " `" . $k . "` = '" . $v . "' ";
- }
- $r = dbq("update `attach` set " . $str . " where id = " . intval($attach_id) );
+ logger('sync_files attach exists: ' . print_r($att,true), LOGGER_DEBUG);
+ $str = '';
+ foreach($att as $k => $v) {
+ if($str)
+ $str .= ",";
+ $str .= " `" . $k . "` = '" . $v . "' ";
+ }
+ $r = dbq("update `attach` set " . $str . " where id = " . intval($attach_id) );
}
else {
+ logger('sync_files attach does not exists: ' . print_r($att,true), LOGGER_DEBUG);
$r = dbq("INSERT INTO attach (`"
. implode("`, `", array_keys($att))
. "`) VALUES ('"
@@ -1064,6 +1094,7 @@ function sync_files($channel,$files) {
if($att['filetype'] === 'multipart/mixed' && $att['is_dir']) {
os_mkdir($newfname, STORAGE_DEFAULT_PERMISSIONS,true);
+ $attachment_stored = true;
continue;
}
else {
@@ -1111,6 +1142,11 @@ function sync_files($channel,$files) {
$p['aid'] = $channel['channel_account_id'];
$p['uid'] = $channel['channel_id'];
+ convert_oldfields($p,'data','content');
+ convert_oldfields($p,'scale','imgscale');
+ convert_oldfields($p,'size','filesize');
+ convert_oldfields($p,'type','mimetype');
+
// if this is a profile photo, undo the profile photo bit
// for any other photo which previously held it.
@@ -1136,15 +1172,15 @@ function sync_files($channel,$files) {
);
}
- if($p['scale'] === 0 && $p['os_storage'])
- $p['data'] = $store_path;
+ if($p['imgscale'] === 0 && $p['os_storage'])
+ $p['content'] = $store_path;
else
- $p['data'] = base64_decode($p['data']);
+ $p['content'] = base64_decode($p['content']);
- $exists = q("select * from photo where resource_id = '%s' and scale = %d and uid = %d limit 1",
+ $exists = q("select * from photo where resource_id = '%s' and imgscale = %d and uid = %d limit 1",
dbesc($p['resource_id']),
- intval($p['scale']),
+ intval($p['imgscale']),
intval($channel['channel_id'])
);
@@ -1200,3 +1236,9 @@ function sync_files($channel,$files) {
}
+function convert_oldfields(&$arr,$old,$new) {
+ if(array_key_exists($old,$arr)) {
+ $arr[$new] = $arr[$old];
+ unset($arr[$old]);
+ }
+}
diff --git a/include/importdoc.php b/include/importdoc.php
deleted file mode 100755
index 90dfb2fc4..000000000
--- a/include/importdoc.php
+++ /dev/null
@@ -1,41 +0,0 @@
- '1',
- 'datequery' => $params['end'],
- 'datequery2' => $params['begin'],
- 'start' => $params['start'], // FIXME
- 'records' => $params['records'], // FIXME
- 'direction' => $params['direction'], // FIXME
- 'pages' => $params['pages'],
- 'order' => 'post',
- 'top' => $params['top'],
- 'cat' => $params['cat']
- ), $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module);
-
-
- $feed_template = get_markup_template('atom_feed.tpl');
-
- $atom = '';
-
- $atom .= replace_macros($feed_template, array(
- '$version' => xmlify(Zotlabs\Project\System::get_project_version()),
- '$red' => xmlify(Zotlabs\Project\System::get_platform_name()),
- '$feed_id' => xmlify($channel['xchan_url']),
- '$feed_title' => xmlify($channel['channel_name']),
- '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now' , ATOM_TIME)) ,
- '$hub' => '', // feed_hublinks(),
- '$salmon' => '', // feed_salmonlinks($channel['channel_address']),
- '$name' => xmlify($channel['channel_name']),
- '$profile_page' => xmlify($channel['xchan_url']),
- '$mimephoto' => xmlify($channel['xchan_photo_mimetype']),
- '$photo' => xmlify($channel['xchan_photo_l']),
- '$thumb' => xmlify($channel['xchan_photo_m']),
- '$picdate' => '',
- '$uridate' => '',
- '$namdate' => '',
- '$birthday' => '',
- '$community' => '',
- ));
-
-
- call_hooks('atom_feed', $atom);
-
- if($items) {
- $type = 'html';
- foreach($items as $item) {
- if($item['item_private'])
- continue;
-
- /** @BUG $owner is undefined in this call */
- $atom .= atom_entry($item, $type, null, $owner, true);
- }
- }
-
- call_hooks('atom_feed_end', $atom);
-
- $atom .= '' . "\r\n";
-
- return $atom;
-}
-
-/**
- * @brief
- *
- * @param array $item an associative array with
- * * \b string \b verb
- * @return string item's verb if set, default ACTIVITY_POST see boot.php
- */
-function construct_verb($item) {
- if ($item['verb'])
- return $item['verb'];
-
- return ACTIVITY_POST;
-}
-
-function construct_activity_object($item) {
-
- if($item['object']) {
- $o = '' . "\r\n";
- $r = json_decode($item['object'],false);
-
- if(! $r)
- return '';
- if($r->type)
- $o .= '' . xmlify($r->type) . ' ' . "\r\n";
- if($r->id)
- $o .= '' . xmlify($r->id) . ' ' . "\r\n";
- if($r->title)
- $o .= '' . xmlify($r->title) . ' ' . "\r\n";
- if($r->links) {
- /** @FIXME!! */
- if(substr($r->link,0,1) === '<') {
- $r->link = preg_replace('/\ /',' ',$r->link);
- $o .= $r->link;
- }
- else
- $o .= ' ' . "\r\n";
- }
- if($r->content)
- $o .= '' . xmlify(bbcode($r->content)) . ' ' . "\r\n";
- $o .= ' ' . "\r\n";
- return $o;
- }
-
- return '';
-}
-
-function construct_activity_target($item) {
-
- if($item['target']) {
- $o = '' . "\r\n";
- $r = json_decode($item['target'],false);
- if(! $r)
- return '';
- if($r->type)
- $o .= '' . xmlify($r->type) . ' ' . "\r\n";
- if($r->id)
- $o .= '' . xmlify($r->id) . ' ' . "\r\n";
- if($r->title)
- $o .= '' . xmlify($r->title) . ' ' . "\r\n";
- if($r->links) {
- /** @FIXME !!! */
- if(substr($r->link,0,1) === '<') {
- if(strstr($r->link,'&') && (! strstr($r->link,'&')))
- $r->link = str_replace('&','&', $r->link);
- $r->link = preg_replace('/\ /',' ',$r->link);
- $o .= $r->link;
- }
- else
- $o .= ' ' . "\r\n";
- }
- if($r->content)
- $o .= '' . xmlify(bbcode($r->content)) . ' ' . "\r\n";
-
- $o .= ' ' . "\r\n";
-
- return $o;
- }
-
- return '';
-}
-
/**
* @brief Limit lenght on imported system messages.
*
@@ -912,7 +666,7 @@ function get_item_elements($x,$allow_code = false) {
$arr['diaspora_meta'] = (($x['diaspora_signature']) ? $x['diaspora_signature'] : '');
- $arr['object'] = activity_sanitise($x['object']);
+ $arr['obj'] = activity_sanitise($x['object']);
$arr['target'] = activity_sanitise($x['target']);
$arr['attach'] = activity_sanitise($x['attach']);
@@ -1301,8 +1055,8 @@ function encode_item($item,$mirror = false) {
$x['owner'] = encode_item_xchan($item['owner']);
$x['author'] = encode_item_xchan($item['author']);
- if($item['object'])
- $x['object'] = json_decode_plus($item['object']);
+ if($item['obj'])
+ $x['object'] = json_decode_plus($item['obj']);
if($item['target'])
$x['target'] = json_decode_plus($item['target']);
if($item['attach'])
@@ -1428,8 +1182,8 @@ function encode_item_terms($terms,$mirror = false) {
if($terms) {
foreach($terms as $term) {
- if(in_array($term['type'],$allowed_export_terms))
- $ret[] = array('tag' => $term['term'], 'url' => $term['url'], 'type' => termtype($term['type']));
+ if(in_array($term['ttype'],$allowed_export_terms))
+ $ret[] = array('tag' => $term['term'], 'url' => $term['url'], 'type' => termtype($term['ttype']));
}
}
@@ -1490,35 +1244,35 @@ function decode_tags($t) {
$tag['url'] = htmlspecialchars($x['url'], ENT_COMPAT, 'UTF-8', false);
switch($x['type']) {
case 'hashtag':
- $tag['type'] = TERM_HASHTAG;
+ $tag['ttype'] = TERM_HASHTAG;
break;
case 'mention':
- $tag['type'] = TERM_MENTION;
+ $tag['ttype'] = TERM_MENTION;
break;
case 'category':
- $tag['type'] = TERM_CATEGORY;
+ $tag['ttype'] = TERM_CATEGORY;
break;
case 'private_category':
- $tag['type'] = TERM_PCATEGORY;
+ $tag['ttype'] = TERM_PCATEGORY;
break;
case 'file':
- $tag['type'] = TERM_FILE;
+ $tag['ttype'] = TERM_FILE;
break;
case 'search':
- $tag['type'] = TERM_SEARCH;
+ $tag['ttype'] = TERM_SEARCH;
break;
case 'thing':
- $tag['type'] = TERM_THING;
+ $tag['ttype'] = TERM_THING;
break;
case 'bookmark':
- $tag['type'] = TERM_BOOKMARK;
+ $tag['ttype'] = TERM_BOOKMARK;
break;
case 'communitytag':
- $tag['type'] = TERM_COMMUNITYTAG;
+ $tag['ttype'] = TERM_COMMUNITYTAG;
break;
default:
case 'unknown':
- $tag['type'] = TERM_UNKNOWN;
+ $tag['ttype'] = TERM_UNKNOWN;
break;
}
$ret[] = $tag;
@@ -1742,453 +1496,6 @@ function get_profile_elements($x) {
return $arr;
}
-/**
- * @param object $feed
- * @param array $item
- * @param[out] array $author
- * @return multitype:multitype: string NULL number Ambigous Ambigous Ambigous , multitype:multitype:string unknown > multitype:NULL unknown
- */
-function get_atom_elements($feed, $item, &$author) {
-
- //$best_photo = array();
-
- $res = array();
-
- $found_author = $item->get_author();
- if($found_author) {
- $author['author_name'] = unxmlify($found_author->get_name());
- $author['author_link'] = unxmlify($found_author->get_link());
- $author['author_is_feed'] = false;
- }
- else {
- $author['author_name'] = unxmlify($feed->get_title());
- $author['author_link'] = unxmlify($feed->get_permalink());
- $author['author_is_feed'] = true;
- }
-
- if(substr($author['author_link'],-1,1) == '/')
- $author['author_link'] = substr($author['author_link'],0,-1);
-
- $res['mid'] = base64url_encode(unxmlify($item->get_id()));
- $res['title'] = unxmlify($item->get_title());
- $res['body'] = unxmlify($item->get_content());
- $res['plink'] = unxmlify($item->get_link(0));
- $res['item_rss'] = 1;
-
-
- // removing the content of the title if its identically to the body
- // This helps with auto generated titles e.g. from tumblr
-
- if (title_is_body($res["title"], $res["body"]))
- $res['title'] = "";
-
- if($res['plink'])
- $base_url = implode('/', array_slice(explode('/',$res['plink']),0,3));
- else
- $base_url = '';
-
- // look for a photo. We should check media size and find the best one,
- // but for now let's just find any author photo
-
- $rawauthor = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
-
- if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
- $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
- foreach($base as $link) {
- if(!x($author, 'author_photo') || ! $author['author_photo']) {
- if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
- $author['author_photo'] = unxmlify($link['attribs']['']['href']);
- }
- }
- }
-
- $rawactor = $item->get_item_tags(NAMESPACE_ACTIVITY, 'actor');
-
- if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
- $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
- if($base && count($base)) {
- foreach($base as $link) {
- if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
- $author['author_link'] = unxmlify($link['attribs']['']['href']);
- if(!x($author, 'author_photo') || ! $author['author_photo']) {
- if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
- $author['author_photo'] = unxmlify($link['attribs']['']['href']);
- }
- }
- }
- }
-
- // check for a yahoo media element (github etc.)
-
- if(! $author['author_photo']) {
- $rawmedia = $item->get_item_tags(NAMESPACE_YMEDIA,'thumbnail');
- if($rawmedia && $rawmedia[0]['attribs']['']['url']) {
- $author['author_photo'] = strip_tags(unxmlify($rawmedia[0]['attribs']['']['url']));
- }
- }
-
-
- // No photo/profile-link on the item - look at the feed level
-
- if((! (x($author,'author_link'))) || (! (x($author,'author_photo')))) {
- $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
- if($rawauthor && $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
- $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
- foreach($base as $link) {
- if($link['attribs']['']['rel'] === 'alternate' && (! $author['author_link'])) {
- $author['author_link'] = unxmlify($link['attribs']['']['href']);
- $author['author_is_feed'] = true;
- }
- if(! $author['author_photo']) {
- if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
- $author['author_photo'] = unxmlify($link['attribs']['']['href']);
- }
- }
- }
-
- $rawactor = $feed->get_feed_tags(NAMESPACE_ACTIVITY, 'subject');
-
- if($rawactor && activity_match($rawactor[0]['child'][NAMESPACE_ACTIVITY]['obj_type'][0]['data'],ACTIVITY_OBJ_PERSON)) {
- $base = $rawactor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
-
- if($base && count($base)) {
- foreach($base as $link) {
- if($link['attribs']['']['rel'] === 'alternate' && (! $res['author_link']))
- $author['author_link'] = unxmlify($link['attribs']['']['href']);
- if(! (x($author,'author_photo'))) {
- if($link['attribs']['']['rel'] === 'avatar' || $link['attribs']['']['rel'] === 'photo')
- $author['author_photo'] = unxmlify($link['attribs']['']['href']);
- }
- }
- }
- }
- }
-
- $apps = $item->get_item_tags(NAMESPACE_STATUSNET,'notice_info');
- if($apps && $apps[0]['attribs']['']['source']) {
- $res['app'] = strip_tags(unxmlify($apps[0]['attribs']['']['source']));
- }
-
- /*
- * If there's a copy of the body content which is guaranteed to have survived mangling in transit, use it.
- */
-
- $have_real_body = false;
-
- $rawenv = $item->get_item_tags(NAMESPACE_DFRN, 'env');
- if($rawenv) {
- $have_real_body = true;
- $res['body'] = $rawenv[0]['data'];
- $res['body'] = str_replace(array(' ',"\t","\r","\n"), array('','','',''),$res['body']);
- // make sure nobody is trying to sneak some html tags by us
- $res['body'] = notags(base64url_decode($res['body']));
-
- // We could probably turn these old Friendica bbcode bookmarks into bookmark tags but we'd have to
- // create a term table item for them. For now just make sure they stay as links.
-
- $res['body'] = preg_replace('/\[bookmark(.*?)\](.*?)\[\/bookmark\]/','[url$1]$2[/url]',$res['body']);
- }
-
- $res['body'] = limit_body_size($res['body']);
-
- // It isn't certain at this point whether our content is plaintext or html and we'd be foolish to trust
- // the content type. Our own network only emits text normally, though it might have been converted to
- // html if we used a pubsubhubbub transport. But if we see even one html tag in our text, we will
- // have to assume it is all html and needs to be purified.
-
- // It doesn't matter all that much security wise - because before this content is used anywhere, we are
- // going to escape any tags we find regardless, but this lets us import a limited subset of html from
- // the wild, by sanitising it and converting supported tags to bbcode before we rip out any remaining
- // html.
-
- if((strpos($res['body'],'<') !== false) && (strpos($res['body'],'>') !== false)) {
-
- $res['body'] = reltoabs($res['body'],$base_url);
-
- $res['body'] = html2bb_video($res['body']);
-
- $res['body'] = oembed_html2bbcode($res['body']);
-
- $res['body'] = purify_html($res['body']);
-
- $res['body'] = @html2bbcode($res['body']);
- }
- elseif(! $have_real_body) {
-
- // it's not one of our messages and it has no tags
- // so it's probably just text. We'll escape it just to be safe.
-
- $res['body'] = escape_tags($res['body']);
- }
-
- if($res['plink'] && $res['title']) {
- $res['body'] = '#^[url=' . $res['plink'] . ']' . $res['title'] . '[/url]' . "\n\n" . $res['body'];
- $terms = array();
- $terms[] = array(
- 'otype' => TERM_OBJ_POST,
- 'type' => TERM_BOOKMARK,
- 'url' => $res['plink'],
- 'term' => $res['title'],
- );
- }
- elseif($res['plink']) {
- $res['body'] = '#^[url]' . $res['plink'] . '[/url]' . "\n\n" . $res['body'];
- $terms = array();
- $terms[] = array(
- 'otype' => TERM_OBJ_POST,
- 'type' => TERM_BOOKMARK,
- 'url' => $res['plink'],
- 'term' => $res['plink'],
- );
- }
-
- $private = $item->get_item_tags(NAMESPACE_DFRN,'private');
- if($private && intval($private[0]['data']) > 0)
- $res['item_private'] = ((intval($private[0]['data'])) ? 1 : 0);
- else
- $res['item_private'] = 0;
-
- $rawlocation = $item->get_item_tags(NAMESPACE_DFRN, 'location');
- if($rawlocation)
- $res['location'] = unxmlify($rawlocation[0]['data']);
-
- $rawcreated = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'published');
- if($rawcreated)
- $res['created'] = unxmlify($rawcreated[0]['data']);
-
- $rawedited = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'updated');
- if($rawedited)
- $res['edited'] = unxmlify($rawedited[0]['data']);
-
- if((x($res,'edited')) && (! (x($res,'created'))))
- $res['created'] = $res['edited'];
-
- if(! $res['created'])
- $res['created'] = $item->get_date('c');
-
- if(! $res['edited'])
- $res['edited'] = $item->get_date('c');
-
-
- // Disallow time travelling posts
-
- $d1 = strtotime($res['created']);
- $d2 = strtotime($res['edited']);
- $d3 = strtotime('now');
-
- if($d1 > $d3)
- $res['created'] = datetime_convert();
- if($d2 > $d3)
- $res['edited'] = datetime_convert();
-
- $res['created'] = datetime_convert('UTC','UTC',$res['created']);
- $res['edited'] = datetime_convert('UTC','UTC',$res['edited']);
-
- $rawowner = $item->get_item_tags(NAMESPACE_DFRN, 'owner');
- if(! $rawowner)
- $rawowner = $item->get_item_tags(NAMESPACE_ZOT,'owner');
-
- if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'])
- $author['owner_name'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']);
- elseif($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data'])
- $author['owner_name'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['name'][0]['data']);
- if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
- $author['owner_link'] = unxmlify($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
- elseif($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])
- $author['owner_link'] = unxmlify($rawowner[0]['child'][NAMESPACE_DFRN]['uri'][0]['data']);
-
- if($rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
- $base = $rawowner[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
-
- foreach($base as $link) {
- if(!x($author, 'owner_photo') || ! $author['owner_photo']) {
- if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar')
- $author['owner_photo'] = unxmlify($link['attribs']['']['href']);
- }
- }
- }
-
- $rawgeo = $item->get_item_tags(NAMESPACE_GEORSS,'point');
- if($rawgeo)
- $res['coord'] = unxmlify($rawgeo[0]['data']);
-
-
- $rawverb = $item->get_item_tags(NAMESPACE_ACTIVITY, 'verb');
-
- // select between supported verbs
-
- if($rawverb) {
- $res['verb'] = unxmlify($rawverb[0]['data']);
- }
-
- // translate OStatus unfollow to activity streams if it happened to get selected
-
- if((x($res,'verb')) && ($res['verb'] === 'http://ostatus.org/schema/1.0/unfollow'))
- $res['verb'] = ACTIVITY_UNFOLLOW;
-
- $cats = $item->get_categories();
- if($cats) {
- if(is_null($terms))
- $terms = array();
- foreach($cats as $cat) {
- $term = $cat->get_term();
- if(! $term)
- $term = $cat->get_label();
- $scheme = $cat->get_scheme();
- $termurl = '';
- if($scheme && $term && stristr($scheme,'X-DFRN:')) {
- $termtype = ((substr($scheme,7,1) === '#') ? TERM_HASHTAG : TERM_MENTION);
- $termurl = unxmlify(substr($scheme,9));
- }
- else {
- $termtype = TERM_CATEGORY;
- }
- $termterm = notags(trim(unxmlify($term)));
-
- if($termterm) {
- $terms[] = array(
- 'otype' => TERM_OBJ_POST,
- 'type' => $termtype,
- 'url' => $termurl,
- 'term' => $termterm,
- );
- }
- }
- }
-
- if(! is_null($terms))
- $res['term'] = $terms;
-
- $attach = $item->get_enclosures();
- if($attach) {
- $res['attach'] = array();
- foreach($attach as $att) {
- $len = intval($att->get_length());
- $link = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_link()))));
- $title = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_title()))));
- $type = str_replace(array(',','"'),array('%2D','%22'),notags(trim(unxmlify($att->get_type()))));
- if(strpos($type,';'))
- $type = substr($type,0,strpos($type,';'));
- if((! $link) || (strpos($link,'http') !== 0))
- continue;
-
- if(! $title)
- $title = ' ';
- if(! $type)
- $type = 'application/octet-stream';
-
- $res['attach'][] = array('href' => $link, 'length' => $len, 'type' => $type, 'title' => $title );
- }
- }
-
- $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'object');
-
- if($rawobj) {
- $obj = array();
-
- $child = $rawobj[0]['child'];
- if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
- $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
- $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
- }
- if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
- $res['obj_type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
- $obj['type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
- }
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'])
- $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link'])
- $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'])
- $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
- $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
- if(! $body)
- $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
- // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
- $obj['orig'] = xmlify($body);
- if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
- $body = purify_html($body);
- $body = html2bbcode($body);
- }
-
- $obj['content'] = $body;
- }
-
- $res['object'] = $obj;
- }
-
- $rawobj = $item->get_item_tags(NAMESPACE_ACTIVITY, 'target');
-
- if($rawobj) {
- $obj = array();
-
- $child = $rawobj[0]['child'];
- if($child[NAMESPACE_ACTIVITY]['obj_type'][0]['data']) {
- $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
- $obj['type'] = $child[NAMESPACE_ACTIVITY]['obj_type'][0]['data'];
- }
- if($child[NAMESPACE_ACTIVITY]['object-type'][0]['data']) {
- $res['tgt_type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
- $obj['type'] = $child[NAMESPACE_ACTIVITY]['object-type'][0]['data'];
- }
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'id') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'])
- $obj['id'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['id'][0]['data'];
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'link') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['link'])
- $obj['link'] = encode_rel_links($child[SIMPLEPIE_NAMESPACE_ATOM_10]['link']);
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'title') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'])
- $obj['title'] = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['title'][0]['data'];
- if(x($child[SIMPLEPIE_NAMESPACE_ATOM_10], 'content') && $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data']) {
- $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['content'][0]['data'];
- if(! $body)
- $body = $child[SIMPLEPIE_NAMESPACE_ATOM_10]['summary'][0]['data'];
-
- // preserve a copy of the original body content in case we later need to parse out any microformat information, e.g. events
- $obj['orig'] = xmlify($body);
- if((strpos($body,'<') !== false) || (strpos($body,'>') !== false)) {
- $body = purify_html($body);
- $body = html2bbcode($body);
- }
-
- $obj['content'] = $body;
- }
-
- $res['target'] = $obj;
- }
-
- $arr = array('feed' => $feed, 'item' => $item, 'result' => $res);
-
- call_hooks('parse_atom', $arr);
- logger('get_atom_elements: author: ' . print_r($author,true),LOGGER_DATA);
-
- logger('get_atom_elements: ' . print_r($res,true),LOGGER_DATA);
-
- return $res;
-}
-
-function encode_rel_links($links) {
- $o = array();
- if(! ((is_array($links)) && (count($links))))
- return $o;
-
- foreach($links as $link) {
- $l = array();
- if($link['attribs']['']['rel'])
- $l['rel'] = $link['attribs']['']['rel'];
- if($link['attribs']['']['type'])
- $l['type'] = $link['attribs']['']['type'];
- if($link['attribs']['']['href'])
- $l['href'] = $link['attribs']['']['href'];
- if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['width'])
- $l['width'] = $link['attribs'][NAMESPACE_MEDIA]['width'];
- if( (x($link['attribs'],NAMESPACE_MEDIA)) && $link['attribs'][NAMESPACE_MEDIA]['height'])
- $l['height'] = $link['attribs'][NAMESPACE_MEDIA]['height'];
-
- if($l)
- $o[] = $l;
- }
- return $o;
-}
/**
* @brief
@@ -2286,9 +1593,9 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
}
}
- if((x($arr,'object')) && is_array($arr['object'])) {
- activity_sanitise($arr['object']);
- $arr['object'] = json_encode($arr['object']);
+ if((x($arr,'obj')) && is_array($arr['obj'])) {
+ activity_sanitise($arr['obj']);
+ $arr['obj'] = json_encode($arr['obj']);
}
if((x($arr,'target')) && is_array($arr['target'])) {
@@ -2319,7 +1626,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['thr_parent'] = ((x($arr,'thr_parent')) ? notags(trim($arr['thr_parent'])) : $arr['parent_mid']);
$arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : ACTIVITY_POST);
$arr['obj_type'] = ((x($arr,'obj_type')) ? notags(trim($arr['obj_type'])) : ACTIVITY_OBJ_NOTE);
- $arr['object'] = ((x($arr,'object')) ? trim($arr['object']) : '');
+ $arr['obj'] = ((x($arr,'obj')) ? trim($arr['obj']) : '');
$arr['tgt_type'] = ((x($arr,'tgt_type')) ? notags(trim($arr['tgt_type'])) : '');
$arr['target'] = ((x($arr,'target')) ? trim($arr['target']) : '');
$arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : '');
@@ -2388,7 +1695,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
return $ret;
}
- if(($arr['obj_type'] == ACTIVITY_OBJ_NOTE) && (! $arr['object']))
+ if(($arr['obj_type'] == ACTIVITY_OBJ_NOTE) && (! $arr['obj']))
$arr['obj_type'] = ACTIVITY_OBJ_COMMENT;
// is the new message multi-level threaded?
@@ -2548,12 +1855,12 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
if(($terms) && (is_array($terms))) {
foreach($terms as $t) {
- q("insert into term (uid,oid,otype,type,term,url)
+ q("insert into term (uid,oid,otype,ttype,term,url)
values(%d,%d,%d,%d,'%s','%s') ",
intval($arr['uid']),
intval($current_post),
intval(TERM_OBJ_POST),
- intval($t['type']),
+ intval($t['ttype']),
dbesc($t['term']),
dbesc($t['url'])
);
@@ -2682,9 +1989,9 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
}
}
- if((x($arr,'object')) && is_array($arr['object'])) {
- activity_sanitise($arr['object']);
- $arr['object'] = json_encode($arr['object']);
+ if((x($arr,'obj')) && is_array($arr['obj'])) {
+ activity_sanitise($arr['obj']);
+ $arr['obj'] = json_encode($arr['obj']);
}
if((x($arr,'target')) && is_array($arr['target'])) {
@@ -2726,7 +2033,7 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
$arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : $orig[0]['coord']);
$arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : $orig[0]['verb']);
$arr['obj_type'] = ((x($arr,'obj_type')) ? notags(trim($arr['obj_type'])) : $orig[0]['obj_type']);
- $arr['object'] = ((x($arr,'object')) ? trim($arr['object']) : $orig[0]['object']);
+ $arr['obj'] = ((x($arr,'obj')) ? trim($arr['obj']) : $orig[0]['obj']);
$arr['tgt_type'] = ((x($arr,'tgt_type')) ? notags(trim($arr['tgt_type'])) : $orig[0]['tgt_type']);
$arr['target'] = ((x($arr,'target')) ? trim($arr['target']) : $orig[0]['target']);
$arr['plink'] = ((x($arr,'plink')) ? notags(trim($arr['plink'])) : $orig[0]['plink']);
@@ -2827,12 +2134,12 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) {
if(is_array($terms)) {
foreach($terms as $t) {
- q("insert into term (uid,oid,otype,type,term,url)
+ q("insert into term (uid,oid,otype,ttype,term,url)
values(%d,%d,%d,%d,'%s','%s') ",
intval($uid),
intval($orig_post_id),
intval(TERM_OBJ_POST),
- intval($t['type']),
+ intval($t['ttype']),
dbesc($t['term']),
dbesc($t['url'])
);
@@ -2979,8 +2286,8 @@ function send_status_notifications($post_id,$item) {
if(! $notify)
return;
- require_once('include/enotify.php');
- notification(array(
+
+ Zlib\Enotify::submit(array(
'type' => NOTIFY_COMMENT,
'from_xchan' => $item['author_xchan'],
'to_xchan' => $r[0]['channel_hash'],
@@ -3060,10 +2367,10 @@ function tag_deliver($uid, $item_id) {
if (stristr($item['verb'],ACTIVITY_POKE)) {
$poke_notify = true;
- if(($item['obj_type'] == "") || ($item['obj_type'] !== ACTIVITY_OBJ_PERSON) || (! $item['object']))
+ if(($item['obj_type'] == "") || ($item['obj_type'] !== ACTIVITY_OBJ_PERSON) || (! $item['obj']))
$poke_notify = false;
- $obj = json_decode_plus($item['object']);
+ $obj = json_decode_plus($item['obj']);
if($obj) {
if($obj['id'] !== $u[0]['channel_hash'])
$poke_notify = false;
@@ -3073,8 +2380,7 @@ function tag_deliver($uid, $item_id) {
$verb = urldecode(substr($item['verb'],strpos($item['verb'],'#')+1));
if($poke_notify) {
- require_once('include/enotify.php');
- notification(array(
+ Zlib\Enotify::submit(array(
'to_xchan' => $u[0]['channel_hash'],
'from_xchan' => $item['author_xchan'],
'type' => NOTIFY_POKE,
@@ -3108,7 +2414,7 @@ function tag_deliver($uid, $item_id) {
intval($u[0]['channel_id'])
);
if($p) {
- $j_obj = json_decode_plus($item['object']);
+ $j_obj = json_decode_plus($item['obj']);
logger('tag_deliver: tag object: ' . print_r($j_obj,true), LOGGER_DATA);
if($j_obj && $j_obj['id'] && $j_obj['title']) {
if(is_array($j_obj['link']))
@@ -3122,7 +2428,7 @@ function tag_deliver($uid, $item_id) {
dbesc($j_tgt['id']),
intval($u[0]['channel_id'])
);
- proc_run('php','include/notifier.php','edit_post',$p[0]['id']);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','edit_post',$p[0]['id']));
}
}
}
@@ -3239,8 +2545,7 @@ function tag_deliver($uid, $item_id) {
* Kill two birds with one stone. As long as we're here, send a mention notification.
*/
- require_once('include/enotify.php');
- notification(array(
+ Zlib\Enotify::submit(array(
'to_xchan' => $u[0]['channel_hash'],
'from_xchan' => $item['author_xchan'],
'type' => NOTIFY_TAGSELF,
@@ -3415,7 +2720,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
foreach($tags as $tt) {
$tt = trim($tt);
if($tt) {
- q("insert into term (uid,oid,otype,type,term,url)
+ q("insert into term (uid,oid,otype,ttype,term,url)
values(%d,%d,%d,%d,'%s','%s') ",
intval($channel['channel_id']),
intval($item_id),
@@ -3494,7 +2799,7 @@ function start_delivery_chain($channel, $item, $item_id, $parent) {
if($r)
- proc_run('php','include/notifier.php','tgroup',$item_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','tgroup',$item_id));
else {
logger('start_delivery_chain: failed to update item');
// reset the source xchan to prevent loops
@@ -3558,7 +2863,7 @@ function check_item_source($uid, $item) {
foreach($words as $word) {
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
- if((($t['type'] == TERM_HASHTAG) || ($t['type'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
+ if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
@@ -3611,7 +2916,7 @@ function post_is_importable($item,$abook) {
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
- if((($t['type'] == TERM_HASHTAG) || ($t['type'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
+ if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return false;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
@@ -3632,7 +2937,7 @@ function post_is_importable($item,$abook) {
continue;
if(substr($word,0,1) === '#' && $tags) {
foreach($tags as $t)
- if((($t['type'] == TERM_HASHTAG) || ($t['type'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
+ if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*')))
return true;
}
elseif((strpos($word,'/') === 0) && preg_match($word,$text))
@@ -3741,7 +3046,6 @@ function mail_store($arr) {
);
}
else {
- require_once('include/enotify.php');
$notif_params = array(
'from_xchan' => $arr['from_xchan'],
@@ -3752,584 +3056,13 @@ function mail_store($arr) {
'otype' => 'mail'
);
- notification($notif_params);
+ Zlib\Enotify::submit($notif_params);
}
call_hooks('post_mail_end',$arr);
return $current_post;
}
-/**
- * @brief Process atom feed and update anything/everything we might need to update.
- *
- * @param array $xml
- * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
- * @param $importer
- * The contact_record (joined to user_record) of the local user who owns this
- * relationship. It is this person's stuff that is going to be updated.
- * @param $contact
- * The person who is sending us stuff. If not set, we MAY be processing a "follow" activity
- * from an external network and MAY create an appropriate contact record. Otherwise, we MUST
- * have a contact record.
- * @param int $pass by default ($pass = 0) we cannot guarantee that a parent item has been
- * imported prior to its children being seen in the stream unless we are certain
- * of how the feed is arranged/ordered.
- * * With $pass = 1, we only pull parent items out of the stream.
- * * With $pass = 2, we only pull children (comments/likes).
- *
- * So running this twice, first with pass 1 and then with pass 2 will do the right
- * thing regardless of feed ordering. This won't be adequate in a fully-threaded
- * model where comments can have sub-threads. That would require some massive sorting
- * to get all the feed items into a mostly linear ordering, and might still require
- * recursion.
- */
-function consume_feed($xml, $importer, &$contact, $pass = 0) {
-
- require_once('library/simplepie/simplepie.inc');
-
- if(! strlen($xml)) {
- logger('consume_feed: empty input');
- return;
- }
-
- $sys_expire = intval(get_config('system','default_expire_days'));
- $chn_expire = intval($importer['channel_expire_days']);
-
- $expire_days = $sys_expire;
-
- if(($chn_expire != 0) && ($chn_expire < $sys_expire))
- $expire_days = $chn_expire;
-
- // logger('expire_days: ' . $expire_days);
-
- $feed = new SimplePie();
- $feed->set_raw_data($xml);
- $feed->init();
-
- if($feed->error())
- logger('consume_feed: Error parsing XML: ' . $feed->error());
-
- $permalink = $feed->get_permalink();
-
- // Check at the feed level for updated contact name and/or photo
-
- // process any deleted entries
-
- $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry');
- if(is_array($del_entries) && count($del_entries) && $pass != 2) {
- foreach($del_entries as $dentry) {
- $deleted = false;
- if(isset($dentry['attribs']['']['ref'])) {
- $mid = $dentry['attribs']['']['ref'];
- $deleted = true;
- if(isset($dentry['attribs']['']['when'])) {
- $when = $dentry['attribs']['']['when'];
- $when = datetime_convert('UTC','UTC', $when, 'Y-m-d H:i:s');
- }
- else
- $when = datetime_convert('UTC','UTC','now','Y-m-d H:i:s');
- }
-
- if($deleted && is_array($contact)) {
- $r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1",
- dbesc(base64url_encode($mid)),
- dbesc($contact['xchan_hash']),
- intval($importer['channel_id'])
- );
-
- if($r) {
- $item = $r[0];
-
- if(! intval($item['item_deleted'])) {
- logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG);
- drop_item($item['id'],false);
- }
- }
- }
- }
- }
-
- // Now process the feed
-
- if($feed->get_item_quantity()) {
-
- logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
-
- $items = $feed->get_items();
-
- foreach($items as $item) {
-
- $is_reply = false;
- $item_id = base64url_encode($item->get_id());
-
- logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG);
-
- $rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
- if(isset($rawthread[0]['attribs']['']['ref'])) {
- $is_reply = true;
- $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
- }
-
- if($is_reply) {
-
- if($pass == 1)
- continue;
-
- // Have we seen it? If not, import it.
-
- $item_id = base64url_encode($item->get_id());
- $author = array();
- $datarray = get_atom_elements($feed,$item,$author);
-
- if($contact['xchan_network'] === 'rss') {
- $datarray['public_policy'] = 'specific';
- $datarray['comment_policy'] = 'none';
- }
-
- if((! x($author,'author_name')) || ($author['author_is_feed']))
- $author['author_name'] = $contact['xchan_name'];
- if((! x($author,'author_link')) || ($author['author_is_feed']))
- $author['author_link'] = $contact['xchan_url'];
- if((! x($author,'author_photo'))|| ($author['author_is_feed']))
- $author['author_photo'] = $contact['xchan_photo_m'];
-
- $datarray['author_xchan'] = '';
-
- if($author['author_link'] != $contact['xchan_url']) {
- $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
- if($x)
- $datarray['author_xchan'] = $x;
- }
- if(! $datarray['author_xchan'])
- $datarray['author_xchan'] = $contact['xchan_hash'];
-
- $datarray['owner_xchan'] = $contact['xchan_hash'];
-
- $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
- dbesc($item_id),
- intval($importer['channel_id'])
- );
-
-
- // Update content if 'updated' changes
-
- if($r) {
- if((x($datarray,'edited') !== false)
- && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
-
- // do not accept (ignore) an earlier edit than one we currently have.
- if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
- continue;
-
- update_feed_item($importer['channel_id'],$datarray);
- }
- continue;
- }
-
- $datarray['parent_mid'] = $parent_mid;
- $datarray['aid'] = $importer['channel_account_id'];
- $datarray['uid'] = $importer['channel_id'];
-
- logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA);
-
- $xx = item_store($datarray);
- $r = $xx['item_id'];
- continue;
- }
- else {
-
- // Head post of a conversation. Have we seen it? If not, import it.
-
- $item_id = base64url_encode($item->get_id());
- $author = array();
- $datarray = get_atom_elements($feed,$item,$author);
-
- if($contact['xchan_network'] === 'rss') {
- $datarray['public_policy'] = 'specific';
- $datarray['comment_policy'] = 'none';
- }
-
-
- if(is_array($contact)) {
- if((! x($author,'author_name')) || ($author['author_is_feed']))
- $author['author_name'] = $contact['xchan_name'];
- if((! x($author,'author_link')) || ($author['author_is_feed']))
- $author['author_link'] = $contact['xchan_url'];
- if((! x($author,'author_photo'))|| ($author['author_is_feed']))
- $author['author_photo'] = $contact['xchan_photo_m'];
- }
-
- if((! x($author,'author_name')) || (! x($author,'author_link'))) {
- logger('consume_feed: no author information! ' . print_r($author,true));
- continue;
- }
-
- $datarray['author_xchan'] = '';
-
- if(activity_match($datarray['verb'],ACTIVITY_FOLLOW) && $datarray['obj_type'] === ACTIVITY_OBJ_PERSON) {
- $cb = array('item' => $datarray,'channel' => $importer, 'xchan' => null, 'author' => $author, 'caught' => false);
- call_hooks('follow_from_feed',$cb);
- if($cb['caught']) {
- if($cb['return_code'])
- http_status_exit($cb['return_code']);
- continue;
- }
- }
-
- if($author['author_link'] != $contact['xchan_url']) {
- $x = import_author_unknown(array('name' => $author['author_name'],'url' => $author['author_link'],'photo' => array('src' => $author['author_photo'])));
- if($x)
- $datarray['author_xchan'] = $x;
- }
- if(! $datarray['author_xchan'])
- $datarray['author_xchan'] = $contact['xchan_hash'];
-
- $datarray['owner_xchan'] = $contact['xchan_hash'];
-
- if(array_key_exists('created',$datarray) && $datarray['created'] != NULL_DATE && $expire_days) {
- $t1 = $datarray['created'];
- $t2 = datetime_convert('UTC','UTC','now - ' . $expire_days . 'days');
- if($t1 < $t2) {
- logger('feed content older than expiration. Ignoring.', LOGGER_DEBUG, LOG_INFO);
- continue;
- }
- }
-
-
-
- $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1",
- dbesc($item_id),
- intval($importer['channel_id'])
- );
-
- // Update content if 'updated' changes
-
- if($r) {
- if((x($datarray,'edited') !== false)
- && (datetime_convert('UTC','UTC',$datarray['edited']) !== $r[0]['edited'])) {
-
- // do not accept (ignore) an earlier edit than one we currently have.
- if(datetime_convert('UTC','UTC',$datarray['edited']) < $r[0]['edited'])
- continue;
-
- update_feed_item($importer['channel_id'],$datarray);
- }
-
- continue;
- }
-
- $datarray['parent_mid'] = $item_id;
- $datarray['uid'] = $importer['channel_id'];
- $datarray['aid'] = $importer['channel_account_id'];
-
- if(! link_compare($author['owner_link'],$contact['xchan_url'])) {
- logger('consume_feed: Correcting item owner.', LOGGER_DEBUG);
- $author['owner_name'] = $contact['name'];
- $author['owner_link'] = $contact['url'];
- $author['owner_avatar'] = $contact['thumb'];
- }
-
- if(! post_is_importable($datarray,$contact))
- continue;
-
- logger('consume_feed: author ' . print_r($author,true),LOGGER_DEBUG);
-
- logger('consume_feed: ' . print_r($datarray,true),LOGGER_DATA);
-
- $xx = item_store($datarray);
- $r = $xx['item_id'];
- continue;
- }
- }
- }
-}
-
-
-/**
- * @brief Process atom feed and return the first post and structure
- *
- * @param array $xml
- * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds.
- * @param $importer
- * The contact_record (joined to user_record) of the local user who owns this
- * relationship. It is this person's stuff that is going to be updated.
- */
-
-function process_salmon_feed($xml, $importer) {
-
- $ret = array();
-
- require_once('library/simplepie/simplepie.inc');
-
- if(! strlen($xml)) {
- logger('process_feed: empty input');
- return;
- }
-
- $feed = new SimplePie();
- $feed->set_raw_data($xml);
- $feed->init();
-
- if($feed->error())
- logger('Error parsing XML: ' . $feed->error());
-
- $permalink = $feed->get_permalink();
-
- if($feed->get_item_quantity()) {
-
- // this should be exactly one
-
- logger('feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG);
-
- $items = $feed->get_items();
-
- foreach($items as $item) {
-
- $item_id = base64url_encode($item->get_id());
-
- logger('processing ' . $item_id, LOGGER_DEBUG);
-
- $rawthread = $item->get_item_tags( NAMESPACE_THREAD,'in-reply-to');
- if(isset($rawthread[0]['attribs']['']['ref'])) {
- $is_reply = true;
- $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']);
- }
-
- if($is_reply)
- $ret['parent_mid'] = $parent_mid;
-
- $ret['author'] = array();
-
- $datarray = get_atom_elements($feed,$item,$ret['author']);
-
- // reset policies which are restricted by default for RSS connections
- // This item is likely coming from GNU-social via salmon and allows public interaction
- $datarray['public_policy'] = '';
- $datarray['comment_policy'] = '';
-
- $ret['item'] = $datarray;
- }
- }
-
- return $ret;
-}
-
-/*
- * Given an xml (atom) feed, find author and hub links
- */
-
-
-function feed_meta($xml) {
- require_once('library/simplepie/simplepie.inc');
-
- $ret = array();
-
- if(! strlen($xml)) {
- logger('empty input');
- return $ret;
- }
-
- $feed = new SimplePie();
- $feed->set_raw_data($xml);
- $feed->init();
-
- if($feed->error()) {
- logger('Error parsing XML: ' . $feed->error());
- return $ret;
- }
-
- $ret['hubs'] = $feed->get_links('hub');
-
-// logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA);
-
- $author = array();
-
- $found_author = $feed->get_author();
- if($found_author) {
- $author['author_name'] = unxmlify($found_author->get_name());
- $author['author_link'] = unxmlify($found_author->get_link());
-
- $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10,'author');
- logger('rawauthor: ' . print_r($rawauthor,true));
-
- if($rawauthor) {
- if($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) {
- $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link'];
- foreach($base as $link) {
- if(!x($author, 'author_photo') || ! $author['author_photo']) {
- if($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') {
- $author['author_photo'] = unxmlify($link['attribs']['']['href']);
- break;
- }
- }
- }
- }
- if($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data'])
- $author['full_name'] = unxmlify($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']);
- if($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'])
- $author['author_uri'] = unxmlify($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']);
-
- }
- }
-
- if(substr($author['author_link'],-1,1) == '/')
- $author['author_link'] = substr($author['author_link'],0,-1);
-
- $ret['author'] = $author;
-
- return $ret;
-}
-
-
-
-function update_feed_item($uid,$datarray) {
- logger('update_feed_item: not implemented! ' . $uid . ' ' . print_r($datarray,true), LOGGER_DATA);
-}
-
-
-function handle_feed($uid,$abook_id,$url) {
-
- require_once('include/Contact.php');
- $channel = channelx_by_n($uid);
- if(! $channel)
- return;
-
- $x = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d limit 1",
- dbesc($abook_id),
- intval($uid)
- );
-
- $recurse = 0;
- $z = z_fetch_url($url,false,$recurse,array('novalidate' => true));
-
-//logger('handle_feed:' . print_r($z,true));
-
- if($z['success']) {
- consume_feed($z['body'],$channel,$x[0],1);
- consume_feed($z['body'],$channel,$x[0],2);
- }
-}
-
-
-function atom_author($tag,$name,$uri,$h,$w,$type,$photo) {
- $o = '';
- if(! $tag)
- return $o;
-
- $name = xmlify($name);
- $uri = xmlify($uri);
- $h = intval($h);
- $w = intval($w);
- $photo = xmlify($photo);
-
- $o .= "<$tag>\r\n";
- $o .= "$name \r\n";
- $o .= "$uri \r\n";
- $o .= ' ' . "\r\n";
- $o .= ' ' . "\r\n";
-
- call_hooks('atom_author', $o);
-
- $o .= "$tag>\r\n";
-
- return $o;
-}
-
-function atom_entry($item,$type,$author,$owner,$comment = false,$cid = 0) {
-
- if(! $item['parent'])
- return;
-
- if($item['deleted'])
- return ' ' . "\r\n";
-
-
- create_export_photo_body($item);
-
- if($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid'])
- $body = fix_private_photos($item['body'],$owner['uid'],$item,$cid);
- else
- $body = $item['body'];
-
- $o = "\r\n\r\n\r\n";
-
- if(is_array($author))
- $o .= atom_author('author',$author['xchan_name'],$author['xchan_url'],80,80,$author['xchan_photo_mimetype'],$author['xchan_photo_m']);
- else
- $o .= atom_author('author',$item['author']['xchan_name'],$item['author']['xchan_url'],80,80,$item['author']['xchan_photo_mimetype'], $item['author']['xchan_photo_m']);
-
- $o .= atom_author('zot:owner',$item['owner']['xchan_name'],$item['owner']['xchan_url'],80,80,$item['owner']['xchan_photo_mimetype'],$item['owner']['xchan_photo_m']);
-
- if(($item['parent'] != $item['id']) || ($item['parent_mid'] !== $item['mid']) || (($item['thr_parent'] !== '') && ($item['thr_parent'] !== $item['mid']))) {
- $parent_item = (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']);
- $o .= ' ' . "\r\n";
- }
-
- if(activity_match($item['obj_type'],ACTIVITY_OBJ_EVENT) && activity_match($item['verb'],ACTIVITY_POST)) {
- $obj = ((is_array($item['obj'])) ? $item['object'] : json_decode($item['object'],true));
-
- $o .= '' . xmlify($item['title']) . ' ' . "\r\n";
- $o .= '' . xmlify(bbcode($obj['title'])) . ' ' . "\r\n";
- $o .= '' . datetime_convert('UTC','UTC', $obj['start'],'Ymd\\THis' . (($obj['adjust']) ? '\\Z' : '')) . ' ' . "\r\n";
- $o .= '' . datetime_convert('UTC','UTC', $obj['finish'],'Ymd\\THis' . (($obj['adjust']) ? '\\Z' : '')) . ' ' . "\r\n";
- $o .= '' . xmlify(bbcode($obj['location'])) . ' ' . "\r\n";
- $o .= '' . xmlify(bbcode($obj['description'])) . ' ' . "\r\n";
- }
- else {
- $o .= '' . xmlify($item['title']) . ' ' . "\r\n";
- $o .= '' . xmlify(prepare_text($body,$item['mimetype'])) . ' ' . "\r\n";
- }
-
- $o .= '' . z_root() . '/display/' . xmlify($item['mid']) . ' ' . "\r\n";
- $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['created'] . '+00:00',ATOM_TIME)) . ' ' . "\r\n";
- $o .= '' . xmlify(datetime_convert('UTC','UTC',$item['edited'] . '+00:00',ATOM_TIME)) . ' ' . "\r\n";
-
- $o .= ' ' . "\r\n";
-
- if($item['location']) {
- $o .= '' . xmlify($item['location']) . ' ' . "\r\n";
- $o .= '' . xmlify($item['location']) . ' ' . "\r\n";
- }
-
- if($item['coord'])
- $o .= '' . xmlify($item['coord']) . ' ' . "\r\n";
-
- if(($item['item_private']) || strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid']))
- $o .= '' . (($item['item_private']) ? $item['item_private'] : 1) . ' ' . "\r\n";
-
- if($item['app'])
- $o .= ' ' . "\r\n";
-
- $verb = construct_verb($item);
- $o .= '' . xmlify($verb) . ' ' . "\r\n";
- $actobj = construct_activity_object($item);
- if(strlen($actobj))
- $o .= $actobj;
- $actarg = construct_activity_target($item);
- if(strlen($actarg))
- $o .= $actarg;
-
- // FIXME
-// $tags = item_getfeedtags($item);
-// if(count($tags)) {
-// foreach($tags as $t) {
-// $o .= ' ' . "\r\n";
-// }
-// }
-
-// FIXME
-// $o .= item_getfeedattach($item);
-
-// $mentioned = get_mentions($item,$tags);
-// if($mentioned)
-// $o .= $mentioned;
-
- call_hooks('atom_entry', $o);
-
- $o .= ' ' . "\r\n";
-
- return $o;
-}
function fix_private_photos($s, $uid, $item = null, $cid = 0) {
@@ -4358,7 +3091,7 @@ function fix_private_photos($s, $uid, $item = null, $cid = 0) {
if($x) {
$res = substr($i,$x+1);
$i = substr($i,0,$x);
- $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `scale` = %d AND `uid` = %d",
+ $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `imgscale` = %d AND `uid` = %d",
dbesc($i),
intval($res),
intval($uid)
@@ -4481,7 +3214,7 @@ function item_getfeedtags($item) {
if(count($terms)) {
foreach($terms as $term) {
- if(($term['type'] == TERM_HASHTAG) || ($term['type'] == TERM_COMMUNITYTAG))
+ if(($term['ttype'] == TERM_HASHTAG) || ($term['ttype'] == TERM_COMMUNITYTAG))
$ret[] = array('#',$term['url'],$term['term']);
else
$ret[] = array('@',$term['url'],$term['term']);
@@ -4573,7 +3306,7 @@ function item_expire($uid,$days) {
drop_item($item['id'],false);
}
-// proc_run('php',"include/notifier.php","expire","$uid");
+// Zotlabs\Daemon\Master::Summon(array('Notifier','expire',$uid));
}
function retain_item($id) {
@@ -4599,7 +3332,7 @@ function drop_items($items) {
// multiple threads may have been deleted, send an expire notification
if($uid)
- proc_run('php',"include/notifier.php","expire","$uid");
+ Zotlabs\Daemon\Master::Summon(array('Notifier','expire',$uid));
}
@@ -4695,7 +3428,7 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal
// set if we know we're going to send delete notifications out to others.
if((intval($item['item_wall']) && ($stage != DROPITEM_PHASE2)) || ($stage == DROPITEM_PHASE1))
- proc_run('php','include/notifier.php','drop',$notify_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','drop',$notify_id));
goaway(z_root() . '/' . $_SESSION['return_url']);
}
@@ -4952,7 +3685,7 @@ function fetch_post_tags($items,$link = false) {
for($x = 0; $x < count($items); $x ++) {
if($tags) {
foreach($tags as $t) {
- if(($link) && ($t['type'] == TERM_MENTION))
+ if(($link) && ($t['ttype'] == TERM_MENTION))
$t['url'] = chanlink_url($t['url']);
if(array_key_exists('item_id',$items[$x])) {
if($t['oid'] == $items[$x]['item_id']) {
@@ -5162,8 +3895,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
}
$contact_str = '';
- /** @FIXME $group is undefined */
- $contacts = group_get_members($group);
+
+ $contacts = group_get_members($r[0]['id']);
if ($contacts) {
foreach($contacts as $c) {
if($contact_str)
@@ -5180,7 +3913,7 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
$sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str)) or allow_gid like '" . protect_sprintf('%<' . dbesc($r[0]['hash']) . '>%') . "' ) and id = parent $item_normal ) ";
$x = group_rec_byhash($uid,$r[0]['hash']);
- $result['headline'] = sprintf( t('Privacy group: %s'),$x['name']);
+ $result['headline'] = sprintf( t('Privacy group: %s'),$x['gname']);
}
elseif($arr['cid'] && $uid) {
@@ -5512,90 +4245,6 @@ function comment_local_origin($item) {
}
-function gen_asld($items) {
- $ret = array();
- if(! $items)
- return $ret;
- foreach($items as $item) {
- $ret[] = i2asld($item);
- }
- return $ret;
-}
-
-
-function i2asld($i) {
-
- if(! $i)
- return array();
-
- $ret = array();
-
- $ret['@context'] = array( 'http://www.w3.org/ns/activitystreams', 'zot' => 'http://purl.org/zot/protocol');
-
- if($i['verb']) {
- if(strpos(dirname($i['verb'],'activitystrea.ms/schema/1.0'))) {
- $ret['@type'] = ucfirst(basename($i['verb']));
- }
- elseif(strpos(dirname($i['verb'],'purl.org/zot'))) {
- $ret['@type'] = 'zot:' . ucfirst(basename($i['verb']));
- }
- }
- $ret['@id'] = $i['plink'];
-
- $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME);
-
- // we need to pass the parent into this
-// if($i['id'] != $i['parent'] && $i['obj_type'] === ACTIVITY_OBJ_NOTE) {
-// $ret['inReplyTo'] = asencode_note
-// }
-
- if($i['obj_type'] === ACTIVITY_OBJ_NOTE)
- $ret['object'] = asencode_note($i);
-
-
- $ret['actor'] = asencode_person($i['author']);
-
-
- return $ret;
-
-}
-
-function asencode_note($i) {
-
- $ret = array();
-
- $ret['@type'] = 'Note';
- $ret['@id'] = $i['plink'];
- if($i['title'])
- $ret['title'] = bbcode($i['title']);
- $ret['content'] = bbcode($i['body']);
- $ret['zot:owner'] = asencode_person($i['owner']);
- $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME);
- if($i['created'] !== $i['edited'])
- $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME);
-
- return $ret;
-}
-
-
-function asencode_person($p) {
- $ret = array();
- $ret['@type'] = 'Person';
- $ret['@id'] = 'acct:' . $p['xchan_addr'];
- $ret['displayName'] = $p['xchan_name'];
- $ret['icon'] = array(
- '@type' => 'Link',
- 'mediaType' => $p['xchan_photo_mimetype'],
- 'href' => $p['xchan_photo_m']
- );
- $ret['url'] = array(
- '@type' => 'Link',
- 'mediaType' => 'text/html',
- 'href' => $p['xchan_url']
- );
-
- return $ret;
-}
function send_profile_photo_activity($channel,$photo,$profile) {
@@ -5612,7 +4261,7 @@ function send_profile_photo_activity($channel,$photo,$profile) {
$arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
$arr['verb'] = ACTIVITY_UPDATE;
- $arr['object'] = json_encode(array(
+ $arr['obj'] = json_encode(array(
'type' => $arr['obj_type'],
'id' => z_root() . '/photo/profile/l/' . $channel['channel_id'],
'link' => array('rel' => 'photo', 'type' => $photo['type'], 'href' => z_root() . '/photo/profile/l/' . $channel['channel_id'])
diff --git a/include/language.php b/include/language.php
index d6b7606ca..96d3e48a9 100644
--- a/include/language.php
+++ b/include/language.php
@@ -82,13 +82,11 @@ function get_best_language() {
if($arr['preferred'] !== 'unset')
return $arr['preferred'];
- $a = get_app();
return ((isset(App::$config['system']['language'])) ? App::$config['system']['language'] : 'en');
}
function push_lang($language) {
- global $a;
App::$langsave = App::$language;
@@ -104,7 +102,6 @@ function push_lang($language) {
}
function pop_lang() {
- global $a;
if(App::$language === App::$langsave)
return;
@@ -124,7 +121,6 @@ function pop_lang() {
* @param boolean $install (optional) default false
*/
function load_translation_table($lang, $install = false) {
- global $a;
App::$strings = array();
@@ -136,10 +132,10 @@ function load_translation_table($lang, $install = false) {
}
if(! $install) {
- $plugins = q("SELECT name FROM addon WHERE installed=1;");
+ $plugins = q("SELECT aname FROM addon WHERE installed=1;");
if ($plugins !== false) {
foreach($plugins as $p) {
- $name = $p['name'];
+ $name = $p['aname'];
if(file_exists("addon/$name/lang/$lang/hstrings.php")) {
include("addon/$name/lang/$lang/hstrings.php");
}
@@ -170,7 +166,6 @@ function load_translation_table($lang, $install = false) {
*
*/
function t($s, $ctx = '') {
- global $a;
$cs = $ctx ? '__ctx:' . $ctx . '__ ' . $s : $s;
if (x(App::$strings, $cs)) {
@@ -189,7 +184,7 @@ function t($s, $ctx = '') {
function translate_projectname($s) {
- return str_replace(array('$projectname','$Projectname'),array(Zotlabs\Project\System::get_platform_name(),ucfirst(Zotlabs\Project\System::get_platform_name())),$s);
+ return str_replace(array('$projectname','$Projectname'),array(Zotlabs\Lib\System::get_platform_name(),ucfirst(Zotlabs\Lib\System::get_platform_name())),$s);
}
@@ -205,7 +200,6 @@ function translate_projectname($s) {
* @return string
*/
function tt($singular, $plural, $count, $ctx = ''){
- $a = get_app();
$cs = $ctx ? "__ctx:" . $ctx . "__ " . $singular : $singular;
if (x(App::$strings,$cs)) {
diff --git a/include/message.php b/include/message.php
index a7883d50e..d3d8181ae 100644
--- a/include/message.php
+++ b/include/message.php
@@ -257,7 +257,7 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
}
}
- proc_run('php','include/notifier.php','mail',$post_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier','mail',$post_id));
$ret['success'] = true;
$ret['message_item'] = intval($post_id);
diff --git a/include/network.php b/include/network.php
index 9f68d3df3..0dd10e29b 100644
--- a/include/network.php
+++ b/include/network.php
@@ -595,8 +595,6 @@ function parse_xml_string($s,$strict = true) {
function scale_external_images($s, $include_link = true, $scale_replace = false) {
- $a = get_app();
-
// Picture addresses can contain special characters
$s = htmlspecialchars_decode($s, ENT_COMPAT);
@@ -1168,6 +1166,10 @@ function discover_by_webbie($webbie) {
if(! $x)
$probe_old = true;
+
+ if((! $dfrn) && (! $has_salmon))
+ $probe_old = true;
+
if($probe_old) {
$y = old_webfinger($webbie);
if($y) {
@@ -1614,8 +1616,6 @@ function fetch_xrd_links($url) {
function scrape_vcard($url) {
- $a = get_app();
-
$ret = array();
logger('scrape_vcard: url=' . $url);
@@ -1695,8 +1695,6 @@ function scrape_vcard($url) {
function scrape_feed($url) {
- $a = get_app();
-
$ret = array();
$level = 0;
$x = z_fetch_url($url,false,$level,array('novalidate' => true));
@@ -1815,8 +1813,6 @@ function service_plink($contact, $guid) {
function format_and_send_email($sender,$xchan,$item) {
- require_once('include/enotify.php');
-
$title = $item['title'];
$body = $item['body'];
@@ -1835,7 +1831,7 @@ function format_and_send_email($sender,$xchan,$item) {
$tpl = get_markup_template('email_notify_html.tpl');
$email_html_body = replace_macros($tpl,array(
'$banner' => $banner,
- '$notify_icon' => Zotlabs\Project\System::get_notify_icon(),
+ '$notify_icon' => Zotlabs\Lib\System::get_notify_icon(),
'$product' => $product,
'$preamble' => '',
'$sitename' => $sitename,
@@ -1881,7 +1877,7 @@ function format_and_send_email($sender,$xchan,$item) {
// use the EmailNotification library to send the message
- enotify::send(array(
+ Zotlabs\Lib\Enotify::send(array(
'fromName' => $product,
'fromEmail' => $sender_email,
'replyTo' => $sender_email,
@@ -1912,10 +1908,13 @@ function do_delivery($deliveries) {
$deliver = array();
foreach($deliveries as $d) {
+ if(! $d)
+ continue;
+
$deliver[] = $d;
if(count($deliver) >= $deliveries_per_process) {
- proc_run('php','include/deliver.php',$deliver);
+ Zotlabs\Daemon\Master::Summon(array('Deliver',$deliver));
$deliver = array();
if($interval)
@time_sleep_until(microtime(true) + (float) $interval);
@@ -1925,7 +1924,7 @@ function do_delivery($deliveries) {
// catch any stragglers
if($deliver)
- proc_run('php','include/deliver.php',$deliver);
+ Zotlabs\Daemon\Master::Summon(array('Deliver',$deliver));
}
@@ -1933,9 +1932,6 @@ function do_delivery($deliveries) {
function get_site_info() {
- global $db;
- global $a;
-
$register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN');
$directory_mode = Array('DIRECTORY_MODE_NORMAL', 'DIRECTORY_MODE_PRIMARY', 'DIRECTORY_MODE_SECONDARY', 256 => 'DIRECTORY_MODE_STANDALONE');
@@ -1971,7 +1967,7 @@ function get_site_info() {
$r = q("select * from addon where hidden = 0");
if(count($r))
foreach($r as $rr)
- $visible_plugins[] = $rr['name'];
+ $visible_plugins[] = $rr['aname'];
}
sort($visible_plugins);
@@ -1983,8 +1979,8 @@ function get_site_info() {
$site_info = get_config('system','info');
$site_name = get_config('system','sitename');
if(! get_config('system','hidden_version_siteinfo')) {
- $version = Zotlabs\Project\System::get_project_version();
- $tag = Zotlabs\Project\System::get_std_version();
+ $version = Zotlabs\Lib\System::get_project_version();
+ $tag = Zotlabs\Lib\System::get_std_version();
if(@is_dir('.git') && function_exists('shell_exec')) {
$commit = trim( @shell_exec('git log -1 --format="%h"'));
@@ -2020,7 +2016,7 @@ function get_site_info() {
$data = Array(
'version' => $version,
'version_tag' => $tag,
- 'server_role' => Zotlabs\Project\System::get_server_role(),
+ 'server_role' => Zotlabs\Lib\System::get_server_role(),
'commit' => $commit,
'url' => z_root(),
'plugins' => $visible_plugins,
@@ -2034,8 +2030,8 @@ function get_site_info() {
'locked_features' => $locked_features,
'admin' => $admin,
'site_name' => (($site_name) ? $site_name : ''),
- 'platform' => Zotlabs\Project\System::get_platform_name(),
- 'dbdriver' => $db->getdriver(),
+ 'platform' => Zotlabs\Lib\System::get_platform_name(),
+ 'dbdriver' => DBA::$dba->getdriver(),
'lastpoll' => get_config('system','lastpoll'),
'info' => (($site_info) ? $site_info : ''),
'channels_total' => $channels_total_stat,
@@ -2143,3 +2139,29 @@ function get_repository_version($branch = 'master') {
return '?.?';
}
+
+function network_to_name($s) {
+
+ $nets = array(
+ NETWORK_DFRN => t('Friendica'),
+ NETWORK_FRND => t('Friendica'),
+ NETWORK_OSTATUS => t('OStatus'),
+ NETWORK_GNUSOCIAL => t('GNU-Social'),
+ NETWORK_FEED => t('RSS/Atom'),
+ NETWORK_MAIL => t('Email'),
+ NETWORK_DIASPORA => t('Diaspora'),
+ NETWORK_FACEBOOK => t('Facebook'),
+ NETWORK_ZOT => t('Zot'),
+ NETWORK_LINKEDIN => t('LinkedIn'),
+ NETWORK_XMPP => t('XMPP/IM'),
+ NETWORK_MYSPACE => t('MySpace'),
+ );
+
+ call_hooks('network_to_name', $nets);
+
+ $search = array_keys($nets);
+ $replace = array_values($nets);
+
+ return str_replace($search,$replace,$s);
+
+}
diff --git a/include/notifier.php b/include/notifier.php
deleted file mode 100644
index 708d42bd0..000000000
--- a/include/notifier.php
+++ /dev/null
@@ -1,664 +0,0 @@
- 3) ? $argv[3] : null);
-
- if(! $item_id)
- return;
-
- $sys = get_sys_channel();
-
- $deliveries = array();
-
- $dead_hubs = array();
-
- $dh = q("select site_url from site where site_dead = 1");
- if($dh) {
- foreach($dh as $dead) {
- $dead_hubs[] = $dead['site_url'];
- }
- }
-
-
- $request = false;
- $mail = false;
- $top_level = false;
- $location = false;
- $recipients = array();
- $url_recipients = array();
- $normal_mode = true;
- $packet_type = 'undefined';
-
- if($cmd === 'mail' || $cmd === 'single_mail') {
- $normal_mode = false;
- $mail = true;
- $private = true;
- $message = q("SELECT * FROM `mail` WHERE `id` = %d LIMIT 1",
- intval($item_id)
- );
- if(! $message) {
- return;
- }
- xchan_mail_query($message[0]);
- $uid = $message[0]['channel_id'];
- $recipients[] = $message[0]['from_xchan']; // include clones
- $recipients[] = $message[0]['to_xchan'];
- $item = $message[0];
-
- $encoded_item = encode_mail($item);
-
- $s = q("select * from channel where channel_id = %d limit 1",
- intval($item['channel_id'])
- );
- if($s)
- $channel = $s[0];
-
- }
- elseif($cmd === 'request') {
- $channel_id = $item_id;
- $xchan = $argv[3];
- $request_message_id = $argv[4];
-
- $s = q("select * from channel where channel_id = %d limit 1",
- intval($channel_id)
- );
- if($s)
- $channel = $s[0];
-
- $private = true;
- $recipients[] = $xchan;
- $packet_type = 'request';
- $normal_mode = false;
- }
- elseif($cmd == 'permission_update' || $cmd == 'permission_create') {
- // Get the (single) recipient
- $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0",
- intval($item_id)
- );
- if($r) {
- $uid = $r[0]['abook_channel'];
- // Get the sender
- $channel = channelx_by_n($uid);
- if($channel) {
- $perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
-
- if($cmd == 'permission_create')
- call_hooks('permissions_create',$perm_update);
- else
- call_hooks('permissions_update',$perm_update);
-
- if($perm_update['success']) {
- if($perm_update['deliveries']) {
- $deliveries[] = $perm_update['deliveries'];
- do_delivery($deliveries);
- }
- return;
- }
- else {
- $recipients[] = $r[0]['abook_xchan'];
- $private = false;
- $packet_type = 'refresh';
- $packet_recips = array(array('guid' => $r[0]['xchan_guid'],'guid_sig' => $r[0]['xchan_guid_sig'],'hash' => $r[0]['xchan_hash']));
- }
- }
- }
- }
- elseif($cmd === 'refresh_all') {
- logger('notifier: refresh_all: ' . $item_id);
- $uid = $item_id;
- $channel = channelx_by_n($item_id);
- $r = q("select abook_xchan from abook where abook_channel = %d",
- intval($item_id)
- );
- if($r) {
- foreach($r as $rr) {
- $recipients[] = $rr['abook_xchan'];
- }
- }
- $private = false;
- $packet_type = 'refresh';
- }
- elseif($cmd === 'location') {
- logger('notifier: location: ' . $item_id);
- $s = q("select * from channel where channel_id = %d limit 1",
- intval($item_id)
- );
- if($s)
- $channel = $s[0];
- $uid = $item_id;
- $recipients = array();
- $r = q("select abook_xchan from abook where abook_channel = %d",
- intval($item_id)
- );
- if($r) {
- foreach($r as $rr) {
- $recipients[] = $rr['abook_xchan'];
- }
- }
-
- $encoded_item = array('locations' => zot_encode_locations($channel),'type' => 'location', 'encoding' => 'zot');
- $target_item = array('aid' => $channel['channel_account_id'],'uid' => $channel['channel_id']);
- $private = false;
- $packet_type = 'location';
- $location = true;
- }
- elseif($cmd === 'purge_all') {
- logger('notifier: purge_all: ' . $item_id);
- $s = q("select * from channel where channel_id = %d limit 1",
- intval($item_id)
- );
- if($s)
- $channel = $s[0];
- $uid = $item_id;
- $recipients = array();
- $r = q("select abook_xchan from abook where abook_channel = %d",
- intval($item_id)
- );
- if($r) {
- foreach($r as $rr) {
- $recipients[] = $rr['abook_xchan'];
- }
- }
- $private = false;
- $packet_type = 'purge';
- }
- else {
-
- // Normal items
-
- // Fetch the target item
-
- $r = q("SELECT * FROM item WHERE id = %d and parent != 0 LIMIT 1",
- intval($item_id)
- );
-
- if(! $r)
- return;
-
- xchan_query($r);
-
- $r = fetch_post_tags($r);
-
- $target_item = $r[0];
- $deleted_item = false;
-
- if(intval($target_item['item_deleted'])) {
- logger('notifier: target item ITEM_DELETED', LOGGER_DEBUG);
- $deleted_item = true;
- }
-
- if(intval($target_item['item_type']) != ITEM_TYPE_POST) {
- logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
- return;
- }
- if(intval($target_item['item_unpublished']) || intval($target_item['item_delayed']) || intval($target_item['item_hidden'])) {
- logger('notifier: target item not published, so not forwardable', LOGGER_DEBUG);
- return;
- }
-
- if(strpos($target_item['postopts'],'nodeliver') !== false) {
- logger('notifier: target item is undeliverable', LOGGER_DEBUG);
- return;
- }
-
- $s = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
- intval($target_item['uid'])
- );
- if($s)
- $channel = $s[0];
-
- if($channel['channel_hash'] !== $target_item['author_xchan'] && $channel['channel_hash'] !== $target_item['owner_xchan']) {
- logger("notifier: Sending channel {$channel['channel_hash']} is not owner {$target_item['owner_xchan']} or author {$target_item['author_xchan']}", LOGGER_NORMAL, LOG_WARNING);
- return;
- }
-
-
- if($target_item['id'] == $target_item['parent']) {
- $parent_item = $target_item;
- $top_level_post = true;
- }
- else {
- // fetch the parent item
- $r = q("SELECT * from item where id = %d order by id asc",
- intval($target_item['parent'])
- );
-
- if(! $r)
- return;
-
- if(strpos($r[0]['postopts'],'nodeliver') !== false) {
- logger('notifier: target item is undeliverable', LOGGER_DEBUG, LOG_NOTICE);
- return;
- }
-
- xchan_query($r);
- $r = fetch_post_tags($r);
-
- $parent_item = $r[0];
- $top_level_post = false;
- }
-
- // avoid looping of discover items 12/4/2014
-
- if($sys && $parent_item['uid'] == $sys['channel_id'])
- return;
-
- $encoded_item = encode_item($target_item);
-
- // Send comments to the owner to re-deliver to everybody in the conversation
- // We only do this if the item in question originated on this site. This prevents looping.
- // To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
- // Relaying should never be initiated on a post that arrived from elsewhere.
-
- // We should normally be able to rely on ITEM_ORIGIN, but start_delivery_chain() incorrectly set this
- // flag on comments for an extended period. So we'll also call comment_local_origin() which looks at
- // the hostname in the message_id and provides a second (fallback) opinion.
-
- $relay_to_owner = (((! $top_level_post) && (intval($target_item['item_origin'])) && comment_local_origin($target_item)) ? true : false);
-
-
-
- $uplink = false;
-
- // $cmd === 'relay' indicates the owner is sending it to the original recipients
- // don't allow the item in the relay command to relay to owner under any circumstances, it will loop
-
- logger('notifier: relay_to_owner: ' . (($relay_to_owner) ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
- logger('notifier: top_level_post: ' . (($top_level_post) ? 'true' : 'false'), LOGGER_DATA, LOG_DEBUG);
-
- // tag_deliver'd post which needs to be sent back to the original author
-
- if(($cmd === 'uplink') && intval($parent_item['item_uplink']) && (! $top_level_post)) {
- logger('notifier: uplink');
- $uplink = true;
- }
-
- if(($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
- logger('notifier: followup relay', LOGGER_DEBUG);
- $recipients = array(($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan']);
- $private = true;
- if(! $encoded_item['flags'])
- $encoded_item['flags'] = array();
- $encoded_item['flags'][] = 'relay';
- }
- else {
- logger('notifier: normal distribution', LOGGER_DEBUG);
- if($cmd === 'relay')
- logger('notifier: owner relay');
-
- // if our parent is a tag_delivery recipient, uplink to the original author causing
- // a delivery fork.
-
- if(($parent_item) && intval($parent_item['item_uplink']) && (! $top_level_post) && ($cmd !== 'uplink')) {
- // don't uplink a relayed post to the relay owner
- if($parent_item['source_xchan'] !== $parent_item['owner_xchan']) {
- logger('notifier: uplinking this item');
- proc_run('php','include/notifier.php','uplink',$item_id);
- }
- }
-
- $private = false;
- $recipients = collect_recipients($parent_item,$private);
-
- // FIXME add any additional recipients such as mentions, etc.
-
- // don't send deletions onward for other people's stuff
- // TODO verify this is needed - copied logic from same place in old code
-
- if(intval($target_item['item_deleted']) && (! intval($target_item['item_wall']))) {
- logger('notifier: ignoring delete notification for non-wall item', LOGGER_NORMAL, LOG_NOTICE);
- return;
- }
- }
-
- }
-
- $walltowall = (($top_level_post && $channel['xchan_hash'] === $target_item['author_xchan']) ? true : false);
-
- // Generic delivery section, we have an encoded item and recipients
- // Now start the delivery process
-
- $x = $encoded_item;
- $x['title'] = 'private';
- $x['body'] = 'private';
- logger('notifier: encoded item: ' . print_r($x,true), LOGGER_DATA, LOG_DEBUG);
-
- stringify_array_elms($recipients);
- if(! $recipients)
- return;
-
-// logger('notifier: recipients: ' . print_r($recipients,true), LOGGER_NORMAL, LOG_DEBUG);
-
- $env_recips = (($private) ? array() : null);
-
- $details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . implode(',',$recipients) . ")");
-
-
- $recip_list = array();
-
- if($details) {
- foreach($details as $d) {
-
- $recip_list[] = $d['xchan_addr'] . ' (' . $d['xchan_hash'] . ')';
- if($private)
- $env_recips[] = array('guid' => $d['xchan_guid'],'guid_sig' => $d['xchan_guid_sig'],'hash' => $d['xchan_hash']);
-
- if($d['xchan_network'] === 'mail' && $normal_mode) {
- $delivery_options = get_xconfig($d['xchan_hash'],'system','delivery_mode');
- if(! $delivery_options)
- format_and_send_email($channel,$d,$target_item);
- }
- }
- }
-
-
- $narr = array(
- 'channel' => $channel,
- 'env_recips' => $env_recips,
- 'packet_recips' => $packet_recips,
- 'recipients' => $recipients,
- 'item' => $item,
- 'target_item' => $target_item,
- 'top_level_post' => $top_level_post,
- 'private' => $private,
- 'relay_to_owner' => $relay_to_owner,
- 'uplink' => $uplink,
- 'cmd' => $cmd,
- 'mail' => $mail,
- 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
- 'location' => $location,
- 'request' => $request,
- 'normal_mode' => $normal_mode,
- 'packet_type' => $packet_type,
- 'walltowall' => $walltowall,
- 'queued' => array()
- );
-
- call_hooks('notifier_process', $narr);
- if($narr['queued']) {
- foreach($narr['queued'] as $pq)
- $deliveries[] = $pq;
- }
-
- // notifier_process can alter the recipient list
-
- $recipients = $narr['recipients'];
- $env_recips = $narr['env_recips'];
- $packet_recips = $narr['packet_recips'];
-
- if(($private) && (! $env_recips)) {
- // shouldn't happen
- logger('notifier: private message with no envelope recipients.' . print_r($argv,true), LOGGER_NORMAL, LOG_NOTICE);
- }
-
- logger('notifier: recipients (may be delivered to more if public): ' . print_r($recip_list,true), LOGGER_DEBUG);
-
-
- // Now we have collected recipients (except for external mentions, FIXME)
- // Let's reduce this to a set of hubs.
-
- $r = q("select * from hubloc where hubloc_hash in (" . implode(',',$recipients) . ")
- and hubloc_error = 0 and hubloc_deleted = 0"
- );
-
-
- if(! $r) {
- logger('notifier: no hubs', LOGGER_NORMAL, LOG_NOTICE);
- return;
- }
-
- $hubs = $r;
-
-
-
- /**
- * Reduce the hubs to those that are unique. For zot hubs, we need to verify uniqueness by the sitekey, since it may have been
- * a re-install which has not yet been detected and pruned.
- * For other networks which don't have or require sitekeys, we'll have to use the URL
- */
-
-
- $hublist = array(); // this provides an easily printable list for the logs
- $dhubs = array(); // delivery hubs where we store our resulting unique array
- $keys = array(); // array of keys to check uniquness for zot hubs
- $urls = array(); // array of urls to check uniqueness of hubs from other networks
-
-
- foreach($hubs as $hub) {
- if(in_array($hub['hubloc_url'],$dead_hubs)) {
- logger('skipping dead hub: ' . $hub['hubloc_url'], LOGGER_DEBUG, LOG_INFO);
- continue;
- }
-
- if($hub['hubloc_network'] == 'zot') {
- if(! in_array($hub['hubloc_sitekey'],$keys)) {
- $hublist[] = $hub['hubloc_host'];
- $dhubs[] = $hub;
- $keys[] = $hub['hubloc_sitekey'];
- }
- }
- else {
- if(! in_array($hub['hubloc_url'],$urls)) {
- $hublist[] = $hub['hubloc_host'];
- $dhubs[] = $hub;
- $urls[] = $hub['hubloc_url'];
- }
- }
- }
-
- logger('notifier: will notify/deliver to these hubs: ' . print_r($hublist,true), LOGGER_DEBUG, LOG_DEBUG);
-
-
- foreach($dhubs as $hub) {
-
- if($hub['hubloc_network'] !== 'zot') {
-
- $narr = array(
- 'channel' => $channel,
- 'env_recips' => $env_recips,
- 'packet_recips' => $packet_recips,
- 'recipients' => $recipients,
- 'item' => $item,
- 'target_item' => $target_item,
- 'hub' => $hub,
- 'top_level_post' => $top_level_post,
- 'private' => $private,
- 'relay_to_owner' => $relay_to_owner,
- 'uplink' => $uplink,
- 'cmd' => $cmd,
- 'mail' => $mail,
- 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
- 'location' => $location,
- 'request' => $request,
- 'normal_mode' => $normal_mode,
- 'packet_type' => $packet_type,
- 'walltowall' => $walltowall,
- 'queued' => array()
- );
-
-
- call_hooks('notifier_hub',$narr);
- if($narr['queued']) {
- foreach($narr['queued'] as $pq)
- $deliveries[] = $pq;
- }
- continue;
-
- }
-
- // singleton deliveries by definition 'not got zot'.
- // Single deliveries are other federated networks (plugins) and we're essentially
- // delivering only to those that have this site url in their abook_instance
- // and only from within a sync operation. This means if you post from a clone,
- // and a connection is connected to one of your other clones; assuming that hub
- // is running it will receive a sync packet. On receipt of this sync packet it
- // will invoke a delivery to those connections which are connected to just that
- // hub instance.
-
- if($cmd === 'single_mail' || $cmd === 'single_activity') {
- continue;
- }
-
- // default: zot protocol
-
- $hash = random_string();
- $packet = null;
-
- if($packet_type === 'refresh' || $packet_type === 'purge') {
- $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
- }
- elseif($packet_type === 'request') {
- $packet = zot_build_packet($channel,$packet_type,$env_recips,$hub['hubloc_sitekey'],$hash,
- array('message_id' => $request_message_id)
- );
- }
-
- if($packet) {
- queue_insert(array(
- 'hash' => $hash,
- 'account_id' => $channel['channel_account_id'],
- 'channel_id' => $channel['channel_id'],
- 'posturl' => $hub['hubloc_callback'],
- 'notify' => $packet
- ));
- }
- else {
- $packet = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash);
- queue_insert(array(
- 'hash' => $hash,
- 'account_id' => $target_item['aid'],
- 'channel_id' => $target_item['uid'],
- 'posturl' => $hub['hubloc_callback'],
- 'notify' => $packet,
- 'msg' => json_encode($encoded_item)
- ));
-
- // only create delivery reports for normal undeleted items
- if(is_array($target_item) && array_key_exists('postopts',$target_item) && (! $target_item['item_deleted']) && (! get_config('system','disable_dreport'))) {
- q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue ) values ( '%s','%s','%s','%s','%s','%s','%s' ) ",
- dbesc($target_item['mid']),
- dbesc($hub['hubloc_host']),
- dbesc($hub['hubloc_host']),
- dbesc('queued'),
- dbesc(datetime_convert()),
- dbesc($channel['channel_hash']),
- dbesc($hash)
- );
- }
- }
-
- $deliveries[] = $hash;
- }
-
- if($normal_mode) {
- $x = q("select * from hook where hook = 'notifier_normal'");
- if($x)
- proc_run('php','include/deliver_hooks.php', $target_item['id']);
- }
-
- if($deliveries)
- do_delivery($deliveries);
-
- logger('notifier: basic loop complete.', LOGGER_DEBUG);
-
- call_hooks('notifier_end',$target_item);
-
- logger('notifer: complete.');
- return;
-
-}
-
-
-if (array_search(__file__,get_included_files())===0){
- notifier_run($argv,$argc);
- killme();
-}
diff --git a/include/notify.php b/include/notify.php
deleted file mode 100644
index 2b032b56b..000000000
--- a/include/notify.php
+++ /dev/null
@@ -1,37 +0,0 @@
- $item['llink'],
- 'name' => $item['author']['xchan_name'],
- 'url' => $item['author']['xchan_url'],
- 'photo' => $item['author']['xchan_photo_s'],
- 'when' => relative_date($item['created']),
- 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'),
- 'message' => strip_tags(bbcode($itemem_text))
- );
-
-}
-
diff --git a/include/oauth.php b/include/oauth.php
index ec41a5dd2..984e0e6c6 100644
--- a/include/oauth.php
+++ b/include/oauth.php
@@ -37,7 +37,7 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
logger(__function__.":".$consumer.", ". $token_type.", ".$token, LOGGER_DEBUG);
- $r = q("SELECT id, secret, scope, expires, uid FROM tokens WHERE client_id = '%s' AND scope = '%s' AND id = '%s'",
+ $r = q("SELECT id, secret, auth_scope, expires, uid FROM tokens WHERE client_id = '%s' AND auth_scope = '%s' AND id = '%s'",
dbesc($consumer->key),
dbesc($token_type),
dbesc($token)
@@ -45,7 +45,7 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
if (count($r)){
$ot=new OAuth1Token($r[0]['id'],$r[0]['secret']);
- $ot->scope=$r[0]['scope'];
+ $ot->scope=$r[0]['auth_scope'];
$ot->expires = $r[0]['expires'];
$ot->uid = $r[0]['uid'];
return $ot;
@@ -79,7 +79,7 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
$k = $consumer;
}
- $r = q("INSERT INTO tokens (id, secret, client_id, scope, expires) VALUES ('%s','%s','%s','%s', %d)",
+ $r = q("INSERT INTO tokens (id, secret, client_id, auth_scope, expires) VALUES ('%s','%s','%s','%s', %d)",
dbesc($key),
dbesc($sec),
dbesc($k),
@@ -110,7 +110,7 @@ class ZotOAuth1DataStore extends OAuth1DataStore {
$key = $this->gen_token();
$sec = $this->gen_token();
- $r = q("INSERT INTO tokens (id, secret, client_id, scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, %d)",
+ $r = q("INSERT INTO tokens (id, secret, client_id, auth_scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, %d)",
dbesc($key),
dbesc($sec),
dbesc($consumer->key),
@@ -249,7 +249,7 @@ class FKOAuth2 extends OAuth2 {
protected function getAuthCode($code) {
- $r = q("SELECT id, client_id, redirect_uri, expires, scope FROM auth_codes WHERE id = '%s'",
+ $r = q("SELECT id, client_id, redirect_uri, expires, auth_scope FROM auth_codes WHERE id = '%s'",
dbesc($code));
if (count($r))
@@ -259,7 +259,7 @@ class FKOAuth2 extends OAuth2 {
protected function setAuthCode($code, $client_id, $redirect_uri, $expires, $scope = NULL) {
$r = q("INSERT INTO auth_codes
- (id, client_id, redirect_uri, expires, scope) VALUES
+ (id, client_id, redirect_uri, expires, auth_scope) VALUES
('%s', '%s', '%s', %d, '%s')",
dbesc($code),
dbesc($client_id),
diff --git a/include/oembed.php b/include/oembed.php
index 1e5c51172..08363e488 100755
--- a/include/oembed.php
+++ b/include/oembed.php
@@ -227,7 +227,7 @@ function oembed_fetch_url($embedurl){
}
function oembed_format_object($j){
- $a = get_app();
+
$embedurl = $j->embedurl;
// logger('format: ' . print_r($j,true));
diff --git a/include/onedirsync.php b/include/onedirsync.php
deleted file mode 100644
index ce516da9d..000000000
--- a/include/onedirsync.php
+++ /dev/null
@@ -1,82 +0,0 @@
- 1) && (intval($argv[1])))
- $update_id = intval($argv[1]);
-
- if(! $update_id) {
- logger('onedirsync: no update');
- return;
- }
-
- $r = q("select * from updates where ud_id = %d limit 1",
- intval($update_id)
- );
-
- if(! $r)
- return;
- if(($r[0]['ud_flags'] & UPDATE_FLAGS_UPDATED) || (! $r[0]['ud_addr']))
- return;
-
- // Have we probed this channel more recently than the other directory server
- // (where we received this update from) ?
- // If we have, we don't need to do anything except mark any older entries updated
-
- $x = q("select * from updates where ud_addr = '%s' and ud_date > '%s' and ( ud_flags & %d )>0 order by ud_date desc limit 1",
- dbesc($r[0]['ud_addr']),
- dbesc($r[0]['ud_date']),
- intval(UPDATE_FLAGS_UPDATED)
- );
- if($x) {
- $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 and ud_date != '%s'",
- intval(UPDATE_FLAGS_UPDATED),
- dbesc($r[0]['ud_addr']),
- intval(UPDATE_FLAGS_UPDATED),
- dbesc($x[0]['ud_date'])
- );
- return;
- }
-
- // ignore doing an update if this ud_addr refers to a known dead hubloc
-
- $h = q("select * from hubloc where hubloc_addr = '%s' limit 1",
- dbesc($r[0]['ud_addr'])
- );
- if(($h) && ($h[0]['hubloc_status'] & HUBLOC_OFFLINE)) {
- $y = q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and ( ud_flags & %d ) = 0 ",
- intval(UPDATE_FLAGS_UPDATED),
- dbesc($r[0]['ud_addr']),
- intval(UPDATE_FLAGS_UPDATED)
- );
-
- return;
- }
-
- // we might have to pull this out some day, but for now update_directory_entry()
- // runs zot_finger() and is kind of zot specific
-
- if($h && $h[0]['hubloc_network'] !== 'zot')
- return;
-
- update_directory_entry($r[0]);
-
- return;
-}
-
-if (array_search(__file__,get_included_files())===0){
- onedirsync_run($argv,$argc);
- killme();
-}
diff --git a/include/onepoll.php b/include/onepoll.php
deleted file mode 100644
index fedeb1e95..000000000
--- a/include/onepoll.php
+++ /dev/null
@@ -1,159 +0,0 @@
- 1) && (intval($argv[1])))
- $contact_id = intval($argv[1]);
-
- if(! $contact_id) {
- logger('onepoll: no contact');
- return;
- }
-
- $d = datetime_convert();
-
- $contacts = q("SELECT abook.*, xchan.*, account.*
- FROM abook LEFT JOIN account on abook_account = account_id left join xchan on xchan_hash = abook_xchan
- where abook_id = %d
- and abook_pending = 0 and abook_archived = 0 and abook_blocked = 0 and abook_ignored = 0
- AND (( account_flags = %d ) OR ( account_flags = %d )) limit 1",
- intval($contact_id),
- intval(ACCOUNT_OK),
- intval(ACCOUNT_UNVERIFIED)
- );
-
- if(! $contacts) {
- logger('onepoll: abook_id not found: ' . $contact_id);
- return;
- }
-
- $contact = $contacts[0];
-
- $t = $contact['abook_updated'];
-
- $importer_uid = $contact['abook_channel'];
-
- $r = q("SELECT * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1",
- intval($importer_uid)
- );
-
- if(! $r)
- return;
-
- $importer = $r[0];
-
- logger("onepoll: poll: ({$contact['id']}) IMPORTER: {$importer['xchan_name']}, CONTACT: {$contact['xchan_name']}");
-
- $last_update = ((($contact['abook_updated'] === $contact['abook_created']) || ($contact['abook_updated'] === NULL_DATE))
- ? datetime_convert('UTC','UTC','now - 7 days')
- : datetime_convert('UTC','UTC',$contact['abook_updated'] . ' - 2 days')
- );
-
- if($contact['xchan_network'] === 'rss') {
- logger('onepoll: processing feed ' . $contact['xchan_name'], LOGGER_DEBUG);
- handle_feed($importer['channel_id'],$contact_id,$contact['xchan_hash']);
- q("update abook set abook_connected = '%s' where abook_id = %d",
- dbesc(datetime_convert()),
- intval($contact['abook_id'])
- );
- return;
- }
-
- if($contact['xchan_network'] !== 'zot')
- return;
-
- // update permissions
-
- $x = zot_refresh($contact,$importer);
-
- $responded = false;
- $updated = datetime_convert();
- $connected = datetime_convert();
- if(! $x) {
- // mark for death by not updating abook_connected, this is caught in include/poller.php
- q("update abook set abook_updated = '%s' where abook_id = %d",
- dbesc($updated),
- intval($contact['abook_id'])
- );
- }
- else {
- q("update abook set abook_updated = '%s', abook_connected = '%s' where abook_id = %d",
- dbesc($updated),
- dbesc($connected),
- intval($contact['abook_id'])
- );
- $responded = true;
- }
-
- if(! $responded)
- return;
-
- if($contact['xchan_connurl']) {
- $fetch_feed = true;
- $x = null;
-
- if(! ($contact['abook_their_perms'] & PERMS_R_STREAM ))
- $fetch_feed = false;
-
- if($fetch_feed) {
-
- $feedurl = str_replace('/poco/','/zotfeed/',$contact['xchan_connurl']);
- $feedurl .= '?f=&mindate=' . urlencode($last_update);
-
- $x = z_fetch_url($feedurl);
-
- logger('feed_update: ' . print_r($x,true), LOGGER_DATA);
-
- }
-
- if(($x) && ($x['success'])) {
- $total = 0;
- logger('onepoll: feed update ' . $contact['xchan_name'] . ' ' . $feedurl);
-
- $j = json_decode($x['body'],true);
- if($j['success'] && $j['messages']) {
- foreach($j['messages'] as $message) {
- $results = process_delivery(array('hash' => $contact['xchan_hash']), get_item_elements($message),
- array(array('hash' => $importer['xchan_hash'])), false);
- logger('onepoll: feed_update: process_delivery: ' . print_r($results,true), LOGGER_DATA);
- $total ++;
- }
- logger("onepoll: $total messages processed");
- }
- }
- }
-
-
- // update the poco details for this connection
-
- if($contact['xchan_connurl']) {
- $r = q("SELECT xlink_id from xlink
- where xlink_xchan = '%s' and xlink_updated > %s - INTERVAL %s and xlink_static = 0 limit 1",
- intval($contact['xchan_hash']),
- db_utcnow(), db_quoteinterval('1 DAY')
- );
- if(! $r) {
- poco_load($contact['xchan_hash'],$contact['xchan_connurl']);
- }
- }
-
- return;
-}
-
-if (array_search(__file__,get_included_files())===0){
- onepoll_run($argv,$argc);
- killme();
-}
diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php
index 3bea54fd4..6de75d497 100644
--- a/include/photo/photo_driver.php
+++ b/include/photo/photo_driver.php
@@ -316,7 +316,7 @@ abstract class photo_driver {
$p['resource_id'] = (($arr['resource_id']) ? $arr['resource_id'] : '');
$p['filename'] = (($arr['filename']) ? $arr['filename'] : '');
$p['album'] = (($arr['album']) ? $arr['album'] : '');
- $p['scale'] = ((intval($arr['scale'])) ? intval($arr['scale']) : 0);
+ $p['imgscale'] = ((intval($arr['imgscale'])) ? intval($arr['imgscale']) : 0);
$p['allow_cid'] = (($arr['allow_cid']) ? $arr['allow_cid'] : '');
$p['allow_gid'] = (($arr['allow_gid']) ? $arr['allow_gid'] : '');
$p['deny_cid'] = (($arr['deny_cid']) ? $arr['deny_cid'] : '');
@@ -329,14 +329,14 @@ abstract class photo_driver {
$p['os_storage'] = intval($arr['os_storage']);
$p['os_path'] = $arr['os_path'];
- if(! intval($p['scale']))
- logger('save: ' . print_r($arr,true));
+ if(! intval($p['imgscale']))
+ logger('save: ' . print_r($arr,true), LOGGER_DATA);
- $x = q("select id from photo where resource_id = '%s' and uid = %d and xchan = '%s' and `scale` = %d limit 1",
+ $x = q("select id from photo where resource_id = '%s' and uid = %d and xchan = '%s' and imgscale = %d limit 1",
dbesc($p['resource_id']),
intval($p['uid']),
dbesc($p['xchan']),
- intval($p['scale'])
+ intval($p['imgscale'])
);
if($x) {
$r = q("UPDATE `photo` set
@@ -347,14 +347,14 @@ abstract class photo_driver {
`created` = '%s',
`edited` = '%s',
`filename` = '%s',
- `type` = '%s',
+ `mimetype` = '%s',
`album` = '%s',
`height` = %d,
`width` = %d,
- `data` = '%s',
+ `content` = '%s',
`os_storage` = %d,
- `size` = %d,
- `scale` = %d,
+ `filesize` = %d,
+ `imgscale` = %d,
`photo_usage` = %d,
`title` = '%s',
`description` = '%s',
@@ -378,7 +378,7 @@ abstract class photo_driver {
(intval($p['os_storage']) ? dbesc($p['os_path']) : dbescbin($this->imageString())),
intval($p['os_storage']),
intval(strlen($this->imageString())),
- intval($p['scale']),
+ intval($p['imgscale']),
intval($p['photo_usage']),
dbesc($p['title']),
dbesc($p['description']),
@@ -391,7 +391,7 @@ abstract class photo_driver {
}
else {
$r = q("INSERT INTO `photo`
- ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `os_storage`, `size`, `scale`, `photo_usage`, `title`, `description`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
+ ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, mimetype, `album`, `height`, `width`, `content`, `os_storage`, `filesize`, `imgscale`, `photo_usage`, `title`, `description`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s' )",
intval($p['aid']),
intval($p['uid']),
@@ -407,7 +407,7 @@ abstract class photo_driver {
(intval($p['os_storage']) ? dbesc($p['os_path']) : dbescbin($this->imageString())),
intval($p['os_storage']),
intval(strlen($this->imageString())),
- intval($p['scale']),
+ intval($p['imgscale']),
intval($p['photo_usage']),
dbesc($p['title']),
dbesc($p['description']),
@@ -422,7 +422,7 @@ abstract class photo_driver {
public function store($aid, $uid, $xchan, $rid, $filename, $album, $scale, $usage = PHOTO_NORMAL, $allow_cid = '', $allow_gid = '', $deny_cid = '', $deny_gid = '') {
- $x = q("select id from photo where `resource_id` = '%s' and uid = %d and `xchan` = '%s' and `scale` = %d limit 1",
+ $x = q("select id from photo where `resource_id` = '%s' and uid = %d and `xchan` = '%s' and `imgscale` = %d limit 1",
dbesc($rid),
intval($uid),
dbesc($xchan),
@@ -437,13 +437,13 @@ abstract class photo_driver {
`created` = '%s',
`edited` = '%s',
`filename` = '%s',
- `type` = '%s',
+ `mimetype` = '%s',
`album` = '%s',
`height` = %d,
`width` = %d,
- `data` = '%s',
- `size` = %d,
- `scale` = %d,
+ `content` = '%s',
+ `filesize` = %d,
+ `imgscale` = %d,
`photo_usage` = %d,
`allow_cid` = '%s',
`allow_gid` = '%s',
@@ -475,7 +475,7 @@ abstract class photo_driver {
}
else {
$r = q("INSERT INTO `photo`
- ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, type, `album`, `height`, `width`, `data`, `size`, `scale`, `photo_usage`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
+ ( `aid`, `uid`, `xchan`, `resource_id`, `created`, `edited`, `filename`, mimetype, `album`, `height`, `width`, `content`, `filesize`, `imgscale`, `photo_usage`, `allow_cid`, `allow_gid`, `deny_cid`, `deny_gid` )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s' )",
intval($aid),
intval($uid),
@@ -521,7 +521,7 @@ function guess_image_type($filename, $headers = '') {
logger('Photo: guess_image_type: '.$filename . ($headers?' from curl headers':''), LOGGER_DEBUG);
$type = null;
if ($headers) {
- $a = get_app();
+
$hdrs=array();
$h = explode("\n",$headers);
foreach ($h as $l) {
@@ -580,8 +580,6 @@ function guess_image_type($filename, $headers = '') {
function import_xchan_photo($photo,$xchan,$thing = false) {
- $a = get_app();
-
$flags = (($thing) ? PHOTO_THING : PHOTO_XCHAN);
$album = (($thing) ? 'Things' : 'Contact Photos');
@@ -590,7 +588,7 @@ function import_xchan_photo($photo,$xchan,$thing = false) {
if($thing)
$hash = photo_new_resource();
else {
- $r = q("select resource_id from photo where xchan = '%s' and photo_usage = %d and scale = 4 limit 1",
+ $r = q("select resource_id from photo where xchan = '%s' and photo_usage = %d and imgscale = 4 limit 1",
dbesc($xchan),
intval(PHOTO_XCHAN)
);
@@ -656,7 +654,7 @@ function import_xchan_photo($photo,$xchan,$thing = false) {
else
$photo_failure = true;
- $p = array('xchan' => $xchan,'resource_id' => $hash, 'filename' => basename($photo), 'album' => $album, 'photo_usage' => $flags, 'scale' => 4);
+ $p = array('xchan' => $xchan,'resource_id' => $hash, 'filename' => basename($photo), 'album' => $album, 'photo_usage' => $flags, 'imgscale' => 4);
$r = $img->save($p);
@@ -664,7 +662,7 @@ function import_xchan_photo($photo,$xchan,$thing = false) {
$photo_failure = true;
$img->scaleImage(80);
- $p['scale'] = 5;
+ $p['imgscale'] = 5;
$r = $img->save($p);
@@ -672,7 +670,7 @@ function import_xchan_photo($photo,$xchan,$thing = false) {
$photo_failure = true;
$img->scaleImage(48);
- $p['scale'] = 6;
+ $p['imgscale'] = 6;
$r = $img->save($p);
@@ -703,8 +701,6 @@ function import_xchan_photo($photo,$xchan,$thing = false) {
function import_channel_photo($photo,$type,$aid,$uid) {
- $a = get_app();
-
logger('import_channel_photo: importing channel photo for ' . $uid, LOGGER_DEBUG);
$hash = photo_new_resource();
@@ -719,7 +715,7 @@ function import_channel_photo($photo,$type,$aid,$uid) {
$img->scaleImageSquare(300);
- $p = array('aid' => $aid, 'uid' => $uid, 'resource_id' => $hash, 'filename' => $filename, 'album' => t('Profile Photos'), 'photo_usage' => PHOTO_PROFILE, 'scale' => 4);
+ $p = array('aid' => $aid, 'uid' => $uid, 'resource_id' => $hash, 'filename' => $filename, 'album' => t('Profile Photos'), 'photo_usage' => PHOTO_PROFILE, 'imgscale' => 4);
$r = $img->save($p);
@@ -727,7 +723,7 @@ function import_channel_photo($photo,$type,$aid,$uid) {
$photo_failure = true;
$img->scaleImage(80);
- $p['scale'] = 5;
+ $p['imgscale'] = 5;
$r = $img->save($p);
@@ -735,7 +731,7 @@ function import_channel_photo($photo,$type,$aid,$uid) {
$photo_failure = true;
$img->scaleImage(48);
- $p['scale'] = 6;
+ $p['imgscale'] = 6;
$r = $img->save($p);
diff --git a/include/photos.php b/include/photos.php
index 73a29d8eb..c64d662ea 100644
--- a/include/photos.php
+++ b/include/photos.php
@@ -19,8 +19,6 @@ require_once('include/text.php');
*/
function photo_upload($channel, $observer, $args) {
- $a = get_app();
-
$ret = array('success' => false);
$channel_id = $channel['channel_id'];
$account_id = $channel['channel_account_id'];
@@ -73,17 +71,17 @@ function photo_upload($channel, $observer, $args) {
$type = $args['getimagesize']['mime'];
$os_storage = 1;
}
- elseif ($args['data']) {
+ elseif ($args['data'] || $args['content']) {
// allow an import from a binary string representing the image.
// This bypasses the upload step and max size limit checking
- $imagedata = $args['data'];
+ $imagedata = (($args['content']) ? $args['content'] : $args['data']);
$filename = $args['filename'];
$filesize = strlen($imagedata);
// this is going to be deleted if it exists
$src = '/tmp/deletemenow';
- $type = $args['type'];
+ $type = (($args['mimetype']) ? $args['mimetype'] : $args['type']);
} else {
$f = array('src' => '', 'filename' => '', 'filesize' => 0, 'type' => '');
@@ -127,7 +125,7 @@ function photo_upload($channel, $observer, $args) {
$imagedata = @file_get_contents($src);
}
- $r = q("select sum(size) as total from photo where aid = %d and scale = 0 ",
+ $r = q("select sum(filesize) as total from photo where aid = %d and imgscale = 0 ",
intval($account_id)
);
@@ -174,7 +172,7 @@ function photo_upload($channel, $observer, $args) {
$errors = false;
$p = array('aid' => $account_id, 'uid' => $channel_id, 'xchan' => $visitor, 'resource_id' => $photo_hash,
- 'filename' => $filename, 'album' => $album, 'scale' => 0, 'photo_usage' => PHOTO_NORMAL,
+ 'filename' => $filename, 'album' => $album, 'imgscale' => 0, 'photo_usage' => PHOTO_NORMAL,
'allow_cid' => $ac['allow_cid'], 'allow_gid' => $ac['allow_gid'],
'deny_cid' => $ac['deny_cid'], 'deny_gid' => $ac['deny_gid'],
'os_storage' => $os_storage, 'os_path' => $args['os_path']
@@ -207,7 +205,7 @@ function photo_upload($channel, $observer, $args) {
if(($width > 1024 || $height > 1024) && (! $errors))
$ph->scaleImage(1024);
- $p['scale'] = 1;
+ $p['imgscale'] = 1;
$r1 = $ph->save($p);
$link[1] = array(
'rel' => 'alternate',
@@ -222,7 +220,7 @@ function photo_upload($channel, $observer, $args) {
if(($width > 640 || $height > 640) && (! $errors))
$ph->scaleImage(640);
- $p['scale'] = 2;
+ $p['imgscale'] = 2;
$r2 = $ph->save($p);
$link[2] = array(
'rel' => 'alternate',
@@ -237,7 +235,7 @@ function photo_upload($channel, $observer, $args) {
if(($width > 320 || $height > 320) && (! $errors))
$ph->scaleImage(320);
- $p['scale'] = 3;
+ $p['imgscale'] = 3;
$r3 = $ph->save($p);
$link[3] = array(
'rel' => 'alternate',
@@ -334,7 +332,7 @@ function photo_upload($channel, $observer, $args) {
$item['body'] = $args['body'];
$item['obj_type'] = ACTIVITY_OBJ_PHOTO;
- $item['object'] = json_encode($object);
+ $item['obj'] = json_encode($object);
$item['tgt_type'] = ACTIVITY_OBJ_ALBUM;
$item['target'] = json_encode($target);
@@ -391,8 +389,8 @@ function photo_upload($channel, $observer, $args) {
$arr['deny_cid'] = $ac['deny_cid'];
$arr['deny_gid'] = $ac['deny_gid'];
$arr['verb'] = ACTIVITY_POST;
- $arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
- $arr['object'] = json_encode($object);
+ $arr['obj_type'] = ACTIVITY_OBJ_PHOTO;
+ $arr['obj'] = json_encode($object);
$arr['tgt_type'] = ACTIVITY_OBJ_ALBUM;
$arr['target'] = json_encode($target);
$arr['item_wall'] = 1;
@@ -420,7 +418,7 @@ function photo_upload($channel, $observer, $args) {
$item_id = $result['item_id'];
if($visible)
- proc_run('php', "include/notifier.php", 'wall-new', $item_id);
+ Zotlabs\Daemon\Master::Summon(array('Notifier', 'wall-new', $item_id));
}
$ret['success'] = true;
@@ -445,7 +443,7 @@ function photo_upload($channel, $observer, $args) {
* * success (bool)
* * albums (array)
*/
-function photos_albums_list($channel, $observer) {
+function photos_albums_list($channel, $observer, $sort_key = 'album', $direction = 'asc') {
$channel_id = $channel['channel_id'];
$observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
@@ -453,11 +451,15 @@ function photos_albums_list($channel, $observer) {
if(! perm_is_allowed($channel_id, $observer_xchan, 'view_storage'))
return false;
- /** @FIXME create a permissions SQL which works on arbitrary observers and channels, regardless of login or web status */
- $sql_extra = permissions_sql($channel_id);
+ $sql_extra = permissions_sql($channel_id,$observer_xchan);
- $albums = q("SELECT count( distinct resource_id ) as total, album from photo where uid = %d and photo_usage IN ( %d, %d ) $sql_extra group by album order by max(created) desc",
+ $sort_key = dbesc($sort_key);
+ $direction = dbesc($direction);
+
+
+
+ $albums = q("SELECT count( distinct resource_id ) as total, album from photo where uid = %d and photo_usage IN ( %d, %d ) $sql_extra group by album order by $sort_key $direction",
intval($channel_id),
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE)
@@ -485,20 +487,14 @@ function photos_albums_list($channel, $observer) {
return $ret;
}
-function photos_album_widget($channelx,$observer,$albums = null) {
+function photos_album_widget($channelx,$observer,$sortkey = 'album',$direction = 'asc') {
$o = '';
- // If we weren't passed an album list, see if the photos module
- // dropped one for us to find in App::$data['albums'].
- // If all else fails, load it.
-
- if(! $albums) {
- if(array_key_exists('albums', App::$data))
- $albums = App::$data['albums'];
- else
- $albums = photos_albums_list($channelx,$observer);
- }
+ if(array_key_exists('albums', App::$data))
+ $albums = App::$data['albums'];
+ else
+ $albums = photos_albums_list($channelx,$observer,$sortkey,$direction);
if($albums['success']) {
$o = replace_macros(get_markup_template('photo_albums.tpl'),array(
@@ -537,7 +533,7 @@ function photos_list_photos($channel, $observer, $album = '') {
$ret = array('success' => false);
- $r = q("select resource_id, created, edited, title, description, album, filename, type, height, width, size, scale, photo_usage, allow_cid, allow_gid, deny_cid, deny_gid from photo where uid = %d and photo_usage in ( %d, %d ) $sql_extra ",
+ $r = q("select resource_id, created, edited, title, description, album, filename, mimetype, height, width, filesize, imgscale, photo_usage, allow_cid, allow_gid, deny_cid, deny_gid from photo where uid = %d and photo_usage in ( %d, %d ) $sql_extra ",
intval($channel_id),
intval(PHOTO_NORMAL),
intval(PHOTO_PROFILE)
@@ -545,7 +541,7 @@ function photos_list_photos($channel, $observer, $album = '') {
if($r) {
for($x = 0; $x < count($r); $x ++) {
- $r[$x]['src'] = z_root() . '/photo/' . $r[$x]['resource_id'] . '-' . $r[$x]['scale'];
+ $r[$x]['src'] = z_root() . '/photo/' . $r[$x]['resource_id'] . '-' . $r[$x]['imgscale'];
}
$ret['success'] = true;
$ret['photos'] = $r;
@@ -663,7 +659,7 @@ function photos_create_item($channel, $creator_hash, $photo, $visible = false) {
$arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
$arr['body'] = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']'
- . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['scale'] . '[/zmg]'
+ . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-' . $photo['imgscale'] . '[/zmg]'
. '[/zrl]';
$result = item_store($arr);
diff --git a/include/plugin.php b/include/plugin.php
index 8dd67bb0c..be4e92f03 100755
--- a/include/plugin.php
+++ b/include/plugin.php
@@ -5,8 +5,6 @@
* @brief Some functions to handle addons and themes.
*/
-require_once("include/smarty.php");
-
/**
* @brief unloads an addon.
@@ -43,7 +41,7 @@ function uninstall_plugin($plugin) {
$func();
}
- q("DELETE FROM `addon` WHERE `name` = '%s' ",
+ q("DELETE FROM `addon` WHERE `aname` = '%s' ",
dbesc($plugin)
);
}
@@ -68,7 +66,7 @@ function install_plugin($plugin) {
$plugin_admin = (function_exists($plugin . '_plugin_admin') ? 1 : 0);
- q("INSERT INTO `addon` (`name`, `installed`, `timestamp`, `plugin_admin`) VALUES ( '%s', 1, %d , %d ) ",
+ q("INSERT INTO `addon` (`aname`, `installed`, `tstamp`, `plugin_admin`) VALUES ( '%s', 1, %d , %d ) ",
dbesc($plugin),
intval($t),
$plugin_admin
@@ -113,7 +111,7 @@ function load_plugin($plugin) {
}
function plugin_is_installed($name) {
- $r = q("select name from addon where name = '%s' and installed = 1 limit 1",
+ $r = q("select aname from addon where aname = '%s' and installed = 1 limit 1",
dbesc($name)
);
if($r)
@@ -145,8 +143,8 @@ function reload_plugins() {
if(file_exists($fname)) {
$t = @filemtime($fname);
foreach($installed as $i) {
- if(($i['name'] == $pl) && ($i['timestamp'] != $t)) {
- logger('Reloading plugin: ' . $i['name']);
+ if(($i['aname'] == $pl) && ($i['tstamp'] != $t)) {
+ logger('Reloading plugin: ' . $i['aname']);
@include_once($fname);
if(function_exists($pl . '_unload')) {
@@ -157,7 +155,7 @@ function reload_plugins() {
$func = $pl . '_load';
$func();
}
- q("UPDATE `addon` SET `timestamp` = %d WHERE `id` = %d",
+ q("UPDATE `addon` SET `tstamp` = %d WHERE `id` = %d",
intval($t),
intval($i['id'])
);
@@ -180,7 +178,7 @@ function reload_plugins() {
* @return mixed|bool
*/
function register_hook($hook, $file, $function, $priority = 0) {
- $r = q("SELECT * FROM `hook` WHERE `hook` = '%s' AND `file` = '%s' AND `function` = '%s' LIMIT 1",
+ $r = q("SELECT * FROM `hook` WHERE `hook` = '%s' AND `file` = '%s' AND `fn` = '%s' LIMIT 1",
dbesc($hook),
dbesc($file),
dbesc($function)
@@ -188,7 +186,7 @@ function register_hook($hook, $file, $function, $priority = 0) {
if($r)
return true;
- $r = q("INSERT INTO `hook` (`hook`, `file`, `function`, `priority`) VALUES ( '%s', '%s', '%s', '%s' )",
+ $r = q("INSERT INTO `hook` (`hook`, `file`, `fn`, `priority`) VALUES ( '%s', '%s', '%s', '%s' )",
dbesc($hook),
dbesc($file),
dbesc($function),
@@ -208,7 +206,7 @@ function register_hook($hook, $file, $function, $priority = 0) {
* @return array
*/
function unregister_hook($hook, $file, $function) {
- $r = q("DELETE FROM hook WHERE hook = '%s' AND `file` = '%s' AND `function` = '%s'",
+ $r = q("DELETE FROM hook WHERE hook = '%s' AND `file` = '%s' AND `fn` = '%s'",
dbesc($hook),
dbesc($file),
dbesc($function)
@@ -235,7 +233,7 @@ function load_hooks() {
if(! array_key_exists($rr['hook'],App::$hooks))
App::$hooks[$rr['hook']] = array();
- App::$hooks[$rr['hook']][] = array($rr['file'],$rr['function'],$rr['priority'],$rr['hook_version']);
+ App::$hooks[$rr['hook']][] = array($rr['file'],$rr['fn'],$rr['priority'],$rr['hook_version']);
}
}
//logger('hooks: ' . print_r(App::$hooks,true));
@@ -302,12 +300,18 @@ function call_hooks($name, &$data = null) {
$func($data);
else
$func($a, $data);
- } else {
- q("DELETE FROM hook WHERE hook = '%s' AND file = '%s' AND function = '%s'",
- dbesc($name),
- dbesc($hook[0]),
- dbesc($origfn)
- );
+ }
+ else {
+
+ // Don't do any DB write calls if we're currently logging a possibly failed DB call.
+ if(! DBA::$logging) {
+ // The hook should be removed so we don't process it.
+ q("DELETE FROM hook WHERE hook = '%s' AND file = '%s' AND fn = '%s'",
+ dbesc($name),
+ dbesc($hook[0]),
+ dbesc($origfn)
+ );
+ }
}
}
}
@@ -502,7 +506,7 @@ function get_theme_info($theme){
* @return string
*/
function get_theme_screenshot($theme) {
- $a = get_app();
+
$exts = array('.png', '.jpg');
foreach($exts as $ext) {
if(file_exists('view/theme/' . $theme . '/img/screenshot' . $ext))
@@ -523,7 +527,7 @@ function head_add_css($src, $media = 'screen') {
}
function head_remove_css($src, $media = 'screen') {
- $a = get_app();
+
$index = array_search(array($src, $media), App::$css_sources);
if ($index !== false)
unset(App::$css_sources[$index]);
@@ -594,7 +598,7 @@ function head_add_js($src) {
}
function head_remove_js($src) {
- $a = get_app();
+
$index = array_search($src, App::$js_sources);
if($index !== false)
unset(App::$js_sources[$index]);
@@ -635,7 +639,6 @@ function format_js_if_exists($source) {
function theme_include($file, $root = '') {
- $a = get_app();
// Make sure $root ends with a slash / if it's not blank
if($root !== '' && $root[strlen($root)-1] !== '/')
@@ -648,12 +651,13 @@ function theme_include($file, $root = '') {
else
$parent = 'NOPATH';
- $theme = current_theme();
+ $theme = Zotlabs\Render\Theme::current();
+ $thname = $theme[0];
$ext = substr($file,strrpos($file,'.')+1);
$paths = array(
- "{$root}view/theme/$theme/$ext/$file",
+ "{$root}view/theme/$thname/$ext/$file",
"{$root}view/theme/$parent/$ext/$file",
"{$root}view/site/$ext/$file",
"{$root}view/$ext/$file",
@@ -672,7 +676,7 @@ function theme_include($file, $root = '') {
function get_intltext_template($s, $root = '') {
- $a = get_app();
+
$t = App::template_engine();
$template = $t->get_intltext_template($s, $root);
@@ -681,7 +685,7 @@ function get_intltext_template($s, $root = '') {
function get_markup_template($s, $root = '') {
- $a = get_app();
+
$t = App::template_engine();
$template = $t->get_markup_template($s, $root);
return $template;
diff --git a/include/poller.php b/include/poller.php
index 808b54ee5..e72121a8a 100644
--- a/include/poller.php
+++ b/include/poller.php
@@ -1,445 +1,15 @@
$maxsysload) {
- logger('system: load ' . $load . ' too high. Poller deferred to next scheduled run.');
- return;
- }
- }
-
- $interval = intval(get_config('system','poll_interval'));
- if(! $interval)
- $interval = ((get_config('system','delivery_interval') === false) ? 3 : intval(get_config('system','delivery_interval')));
-
- // Check for a lockfile. If it exists, but is over an hour old, it's stale. Ignore it.
- $lockfile = 'store/[data]/poller';
- if((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 3600))
- && (! get_config('system','override_poll_lockfile'))) {
- logger("poller: Already running");
- return;
- }
-
- // Create a lockfile. Needs two vars, but $x doesn't need to contain anything.
- file_put_contents($lockfile, $x);
-
- logger('poller: start');
-
- // run queue delivery process in the background
-
- proc_run('php',"include/queue.php");
-
-
- // maintenance for mod sharedwithme - check for updated items and remove them
-
- require_once('include/sharedwithme.php');
- apply_updates();
-
-
- // expire any expired mail
-
- q("delete from mail where expires != '%s' and expires < %s ",
- dbesc(NULL_DATE),
- db_utcnow()
- );
-
- // expire any expired items
-
- $r = q("select id from item where expires != '%s' and expires < %s
- and item_deleted = 0 ",
- dbesc(NULL_DATE),
- db_utcnow()
- );
- if($r) {
- require_once('include/items.php');
- foreach($r as $rr)
- drop_item($rr['id'],false);
- }
-
-
- // Ensure that every channel pings a directory server once a month. This way we can discover
- // channels and sites that quietly vanished and prevent the directory from accumulating stale
- // or dead entries.
-
- $r = q("select channel_id from channel where channel_dirdate < %s - INTERVAL %s",
- db_utcnow(),
- db_quoteinterval('30 DAY')
- );
- if($r) {
- foreach($r as $rr) {
- proc_run('php','include/directory.php',$rr['channel_id'],'force');
- if($interval)
- @time_sleep_until(microtime(true) + (float) $interval);
- }
- }
-
- // publish any applicable items that were set to be published in the future
- // (time travel posts). Restrict to items that have come of age in the last
- // couple of days to limit the query to something reasonable.
-
- $r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
- db_utcnow(),
- dbesc(datetime_convert('UTC','UTC','now - 2 days'))
- );
- if($r) {
- foreach($r as $rr) {
- $x = q("update item set item_delayed = 0 where id = %d",
- intval($rr['id'])
- );
- if($x) {
- proc_run('php','include/notifier.php','wall-new',$rr['id']);
- }
- }
- }
-
- $abandon_days = intval(get_config('system','account_abandon_days'));
- if($abandon_days < 1)
- $abandon_days = 0;
-
-
- // once daily run birthday_updates and then expire in background
-
- // FIXME: add birthday updates, both locally and for xprof for use
- // by directory servers
-
- $d1 = intval(get_config('system','last_expire_day'));
- $d2 = intval(datetime_convert('UTC','UTC','now','d'));
-
- // Allow somebody to staggger daily activities if they have more than one site on their server,
- // or if it happens at an inconvenient (busy) hour.
-
- $h1 = intval(get_config('system','cron_hour'));
- $h2 = intval(datetime_convert('UTC','UTC','now','G'));
-
- $dirmode = get_config('system','directory_mode');
-
- /**
- * Cron Daily
- *
- * Actions in the following block are executed once per day, not on every poller run
- *
- */
-
- if(($d2 != $d1) && ($h1 == $h2)) {
-
- require_once('include/dir_fns.php');
- check_upstream_directory();
-
- call_hooks('cron_daily',datetime_convert());
-
-
- $d3 = intval(datetime_convert('UTC','UTC','now','N'));
- if($d3 == 7) {
-
- /**
- * Cron Weekly
- *
- * Actions in the following block are executed once per day only on Sunday (once per week).
- *
- */
-
-
- call_hooks('cron_weekly',datetime_convert());
-
-
- z_check_cert();
-
- require_once('include/hubloc.php');
- prune_hub_reinstalls();
-
- require_once('include/Contact.php');
- mark_orphan_hubsxchans();
-
-
- // get rid of really old poco records
-
- q("delete from xlink where xlink_updated < %s - INTERVAL %s and xlink_static = 0 ",
- db_utcnow(), db_quoteinterval('14 DAY')
- );
-
- $dirmode = intval(get_config('system','directory_mode'));
- if($dirmode === DIRECTORY_MODE_SECONDARY || $dirmode === DIRECTORY_MODE_PRIMARY) {
- logger('regdir: ' . print_r(z_fetch_url(get_directory_primary() . '/regdir?f=&url=' . urlencode(z_root()) . '&realm=' . urlencode(get_directory_realm())),true));
- }
-
- // Check for dead sites
- proc_run('php', 'include/checksites.php');
-
- // update searchable doc indexes
- proc_run('php', 'include/importdoc.php');
-
- /**
- * End Cron Weekly
- */
- }
-
- update_birthdays();
-
- //update statistics in config
- require_once('include/statistics_fns.php');
- update_channels_total_stat();
- update_channels_active_halfyear_stat();
- update_channels_active_monthly_stat();
- update_local_posts_stat();
-
- // expire any read notifications over a month old
-
- q("delete from notify where seen = 1 and date < %s - INTERVAL %s",
- db_utcnow(), db_quoteinterval('30 DAY')
- );
-
- // expire old delivery reports
-
- $keep_reports = intval(get_config('system','expire_delivery_reports'));
- if($keep_reports === 0)
- $keep_reports = 10;
-
- q("delete from dreport where dreport_time < %s - INTERVAL %s",
- db_utcnow(),
- db_quoteinterval($keep_reports . ' DAY')
- );
-
- // expire any expired accounts
- downgrade_accounts();
-
- // If this is a directory server, request a sync with an upstream
- // directory at least once a day, up to once every poll interval.
- // Pull remote changes and push local changes.
- // potential issue: how do we keep from creating an endless update loop?
-
- if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
- require_once('include/dir_fns.php');
- sync_directories($dirmode);
- }
-
- set_config('system','last_expire_day',$d2);
-
- proc_run('php','include/expire.php');
- proc_run('php','include/cli_suggest.php');
-
- require_once('include/hubloc.php');
- remove_obsolete_hublocs();
-
- /**
- * End Cron Daily
- */
- }
-
- // update any photos which didn't get imported properly
- // This should be rare
-
- $r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
- and xchan_photo_date < %s - INTERVAL %s",
- db_utcnow(),
- db_quoteinterval('1 DAY')
- );
- if($r) {
- require_once('include/photo/photo_driver.php');
- foreach($r as $rr) {
- $photos = import_xchan_photo($rr['xchan_photo_l'],$rr['xchan_hash']);
- $x = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s'
- where xchan_hash = '%s'",
- dbesc($photos[0]),
- dbesc($photos[1]),
- dbesc($photos[2]),
- dbesc($photos[3]),
- dbesc($rr['xchan_hash'])
- );
- }
- }
-
-
- // pull in some public posts
-
- if(! get_config('system','disable_discover_tab'))
- proc_run('php','include/externals.php');
-
-
- $manual_id = 0;
- $generation = 0;
-
- $force = false;
- $restart = false;
-
- if(($argc > 1) && ($argv[1] == 'force'))
- $force = true;
-
- if(($argc > 1) && ($argv[1] == 'restart')) {
- $restart = true;
- $generation = intval($argv[2]);
- if(! $generation)
- killme();
- }
-
- if(($argc > 1) && intval($argv[1])) {
- $manual_id = intval($argv[1]);
- $force = true;
- }
-
-
- $sql_extra = (($manual_id) ? " AND abook_id = " . intval($manual_id) . " " : "");
-
- reload_plugins();
-
- $d = datetime_convert();
-
- // TODO check to see if there are any cronhooks before wasting a process
-
- if(! $restart)
- proc_run('php','include/cronhooks.php');
-
- // Only poll from those with suitable relationships
-
- $abandon_sql = (($abandon_days)
- ? sprintf(" AND account_lastlog > %s - INTERVAL %s ", db_utcnow(), db_quoteinterval(intval($abandon_days).' DAY'))
- : ''
- );
-
- $randfunc = db_getfunc('RAND');
-
- $contacts = q("SELECT * FROM abook LEFT JOIN xchan on abook_xchan = xchan_hash
- LEFT JOIN account on abook_account = account_id
- where abook_self = 0
- $sql_extra
- AND (( account_flags = %d ) OR ( account_flags = %d )) $abandon_sql ORDER BY $randfunc",
- intval(ACCOUNT_OK),
- intval(ACCOUNT_UNVERIFIED) // FIXME
-
- );
-
- if($contacts) {
-
- foreach($contacts as $contact) {
-
- $update = false;
-
- $t = $contact['abook_updated'];
- $c = $contact['abook_connected'];
-
- if(intval($contact['abook_feed'])) {
- $min = service_class_fetch($contact['abook_channel'],'minimum_feedcheck_minutes');
- if(! $min)
- $min = intval(get_config('system','minimum_feedcheck_minutes'));
- if(! $min)
- $min = 60;
- $x = datetime_convert('UTC','UTC',"now - $min minutes");
- if($c < $x) {
- proc_run('php','include/onepoll.php',$contact['abook_id']);
- if($interval)
- @time_sleep_until(microtime(true) + (float) $interval);
- }
- continue;
- }
-
-
- if($contact['xchan_network'] !== 'zot')
- continue;
-
- if($c == $t) {
- if(datetime_convert('UTC','UTC', 'now') > datetime_convert('UTC','UTC', $t . " + 1 day"))
- $update = true;
- }
- else {
-
- // if we've never connected with them, start the mark for death countdown from now
-
- if($c == NULL_DATE) {
- $r = q("update abook set abook_connected = '%s' where abook_id = %d",
- dbesc(datetime_convert()),
- intval($contact['abook_id'])
- );
- $c = datetime_convert();
- $update = true;
- }
-
- // He's dead, Jim
-
- if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 30 day")) > 0) {
- $r = q("update abook set abook_archived = 1 where abook_id = %d",
- intval($contact['abook_id'])
- );
- $update = false;
- continue;
- }
-
- if(intval($contact['abook_archived'])) {
- $update = false;
- continue;
- }
-
- // might be dead, so maybe don't poll quite so often
-
- // recently deceased, so keep up the regular schedule for 3 days
-
- if((strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $c . " + 3 day")) > 0)
- && (strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 1 day")) > 0))
- $update = true;
-
- // After that back off and put them on a morphine drip
-
- if(strcmp(datetime_convert('UTC','UTC', 'now'),datetime_convert('UTC','UTC', $t . " + 2 day")) > 0) {
- $update = true;
- }
-
- }
-
- if(intval($contact['abook_pending']) || intval($contact['abook_archived']) || intval($contact['abook_ignored']) || intval($contact['abook_blocked']))
- continue;
-
- if((! $update) && (! $force))
- continue;
-
- proc_run('php','include/onepoll.php',$contact['abook_id']);
- if($interval)
- @time_sleep_until(microtime(true) + (float) $interval);
-
- }
- }
-
- if($dirmode == DIRECTORY_MODE_SECONDARY || $dirmode == DIRECTORY_MODE_PRIMARY) {
- $r = q("SELECT u.ud_addr, u.ud_id, u.ud_last FROM updates AS u INNER JOIN (SELECT ud_addr, max(ud_id) AS ud_id FROM updates WHERE ( ud_flags & %d ) = 0 AND ud_addr != '' AND ( ud_last = '%s' OR ud_last > %s - INTERVAL %s ) GROUP BY ud_addr) AS s ON s.ud_id = u.ud_id ",
- intval(UPDATE_FLAGS_UPDATED),
- dbesc(NULL_DATE),
- db_utcnow(), db_quoteinterval('7 DAY')
- );
- if($r) {
- foreach($r as $rr) {
-
- // If they didn't respond when we attempted before, back off to once a day
- // After 7 days we won't bother anymore
-
- if($rr['ud_last'] != NULL_DATE)
- if($rr['ud_last'] > datetime_convert('UTC','UTC', 'now - 1 day'))
- continue;
- proc_run('php','include/onedirsync.php',$rr['ud_id']);
- if($interval)
- @time_sleep_until(microtime(true) + (float) $interval);
- }
- }
- }
-
- set_config('system','lastpoll',datetime_convert());
-
- //All done - clear the lockfile
- @unlink($lockfile);
-
- return;
}
if (array_search(__file__,get_included_files())===0){
- poller_run($argv,$argc);
+ poller_run($argc,$argv);
killme();
}
diff --git a/include/queue.php b/include/queue.php
deleted file mode 100644
index 8a3b2aa58..000000000
--- a/include/queue.php
+++ /dev/null
@@ -1,95 +0,0 @@
- 1)
- $queue_id = argv(1);
- else
- $queue_id = 0;
-
- logger('queue: start');
-
- // delete all queue items more than 3 days old
- // but first mark these sites dead if we haven't heard from them in a month
-
- $r = q("select outq_posturl from outq where outq_created < %s - INTERVAL %s",
- db_utcnow(), db_quoteinterval('3 DAY')
- );
- if($r) {
- foreach($r as $rr) {
- $site_url = '';
- $h = parse_url($rr['outq_posturl']);
- $desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
- q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
- dbesc($desturl),
- db_utcnow(), db_quoteinterval('1 MONTH')
- );
- }
- }
-
- $r = q("DELETE FROM outq WHERE outq_created < %s - INTERVAL %s",
- db_utcnow(), db_quoteinterval('3 DAY')
- );
-
- if($queue_id) {
- $r = q("SELECT * FROM outq WHERE outq_hash = '%s' LIMIT 1",
- dbesc($queue_id)
- );
- }
- else {
-
- // For the first 12 hours we'll try to deliver every 15 minutes
- // After that, we'll only attempt delivery once per hour.
- // This currently only handles the default queue drivers ('zot' or '') which we will group by posturl
- // so that we don't start off a thousand deliveries for a couple of dead hubs.
- // The zot driver will deliver everything destined for a single hub once contact is made (*if* contact is made).
- // Other drivers will have to do something different here and may need their own query.
-
- // Note: this requires some tweaking as new posts to long dead hubs once a day will keep them in the
- // "every 15 minutes" category. We probably need to prioritise them when inserted into the queue
- // or just prior to this query based on recent and long-term delivery history. If we have good reason to believe
- // the site is permanently down, there's no reason to attempt delivery at all, or at most not more than once
- // or twice a day.
-
- // FIXME: can we sort postgres on outq_priority and maintain the 'distinct' ?
- // The order by max(outq_priority) might be a dodgy query because of the group by.
- // The desired result is to return a sequence in the order most likely to be delivered in this run.
- // If a hub has already been sitting in the queue for a few days, they should be delivered last;
- // hence every failure should drop them further down the priority list.
-
- if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
- $prefix = 'DISTINCT ON (outq_posturl)';
- $suffix = 'ORDER BY outq_posturl';
- } else {
- $prefix = '';
- $suffix = 'GROUP BY outq_posturl ORDER BY max(outq_priority)';
- }
- $r = q("SELECT $prefix * FROM outq WHERE outq_delivered = 0 and (( outq_created > %s - INTERVAL %s and outq_updated < %s - INTERVAL %s ) OR ( outq_updated < %s - INTERVAL %s )) $suffix",
- db_utcnow(), db_quoteinterval('12 HOUR'),
- db_utcnow(), db_quoteinterval('15 MINUTE'),
- db_utcnow(), db_quoteinterval('1 HOUR')
- );
- }
- if(! $r)
- return;
-
- foreach($r as $rr) {
- queue_deliver($rr);
- }
-}
-
-if (array_search(__file__,get_included_files())===0){
- queue_run($argv,$argc);
- killme();
-}
diff --git a/include/ratenotif.php b/include/ratenotif.php
deleted file mode 100644
index 2c636c710..000000000
--- a/include/ratenotif.php
+++ /dev/null
@@ -1,119 +0,0 @@
- 'rating',
- 'encoding' => 'zot',
- 'target' => $r[0]['xlink_link'],
- 'rating' => intval($r[0]['xlink_rating']),
- 'rating_text' => $r[0]['xlink_rating_text'],
- 'signature' => $r[0]['xlink_sig'],
- 'edited' => $r[0]['xlink_updated']
- );
- }
-
- $channel = channelx_by_hash($r[0]['xlink_xchan']);
- if(! $channel) {
- logger('no channel');
- return;
- }
-
-
- $primary = get_directory_primary();
-
- if(! $primary)
- return;
-
-
- $interval = ((get_config('system','delivery_interval') !== false)
- ? intval(get_config('system','delivery_interval')) : 2 );
-
- $deliveries_per_process = intval(get_config('system','delivery_batch_count'));
-
- if($deliveries_per_process <= 0)
- $deliveries_per_process = 1;
-
- $deliver = array();
-
- $x = z_fetch_url($primary . '/regdir');
- if($x['success']) {
- $j = json_decode($x['body'],true);
- if($j && $j['success'] && is_array($j['directories'])) {
-
- foreach($j['directories'] as $h) {
- if($h == z_root())
- continue;
-
- $hash = random_string();
- $n = zot_build_packet($channel,'notify',null,null,$hash);
-
- queue_insert(array(
- 'hash' => $hash,
- 'account_id' => $channel['channel_account_id'],
- 'channel_id' => $channel['channel_id'],
- 'posturl' => $h . '/post',
- 'notify' => $n,
- 'msg' => json_encode($encoded_item)
- ));
-
- $deliver[] = $hash;
-
- if(count($deliver) >= $deliveries_per_process) {
- proc_run('php','include/deliver.php',$deliver);
- $deliver = array();
- if($interval)
- @time_sleep_until(microtime(true) + (float) $interval);
- }
- }
-
- // catch any stragglers
-
- if(count($deliver)) {
- proc_run('php','include/deliver.php',$deliver);
- }
- }
- }
-
- logger('ratenotif: complete.');
- return;
-
-}
-
-if (array_search(__file__,get_included_files())===0){
- ratenotif_run($argv,$argc);
- killme();
-}
diff --git a/include/profile_selectors.php b/include/selectors.php
similarity index 79%
rename from include/profile_selectors.php
rename to include/selectors.php
index 9f993f803..d7d070d31 100644
--- a/include/profile_selectors.php
+++ b/include/selectors.php
@@ -1,6 +1,49 @@
\r\n";
+
+ $r = q("SELECT profile_guid, profile_name FROM `profile` WHERE `uid` = %d",
+ intval($_SESSION['uid']));
+
+ if($r) {
+ foreach($r as $rr) {
+ $selected = (($rr['profile_guid'] == $current) ? " selected=\"selected\" " : "");
+ $o .= "{$rr['profile_name']} \r\n";
+ }
+ }
+ $o .= "\r\n";
+ return $o;
+}
+
+function contact_poll_interval($current, $disabled = false) {
+
+ $dis = (($disabled) ? ' disabled="disabled" ' : '');
+ $o = '';
+ $o .= " " . "\r\n";
+
+ $rep = array(
+ 0 => t('Frequently'),
+ 1 => t('Hourly'),
+ 2 => t('Twice daily'),
+ 3 => t('Daily'),
+ 4 => t('Weekly'),
+ 5 => t('Monthly')
+ );
+
+ foreach($rep as $k => $v) {
+ $selected = (($k == $current) ? " selected=\"selected\" " : "");
+ $o .= "$v \r\n";
+ }
+ $o .= "\r\n";
+ return $o;
+}
+
+
function gender_selector($current="",$suffix="") {
$o = '';
$select = array('', t('Male'), t('Female'), t('Currently Male'), t('Currently Female'), t('Mostly Male'), t('Mostly Female'), t('Transgender'), t('Intersex'), t('Transsexual'), t('Hermaphrodite'), t('Neuter'), t('Non-specific'), t('Other'), t('Undecided'));
@@ -108,3 +151,4 @@ function marital_selector_min($current="",$suffix="") {
$o .= '';
return $o;
}
+
diff --git a/include/sharedwithme.php b/include/sharedwithme.php
index b01764ad3..b342f51d5 100644
--- a/include/sharedwithme.php
+++ b/include/sharedwithme.php
@@ -3,7 +3,7 @@
function apply_updates() {
//check for updated items and remove them
- $x = q("SELECT mid, max(object) AS object FROM item WHERE verb = '%s' AND obj_type = '%s' GROUP BY mid",
+ $x = q("SELECT mid, max(obj) AS obj FROM item WHERE verb = '%s' AND obj_type = '%s' GROUP BY mid",
dbesc(ACTIVITY_UPDATE),
dbesc(ACTIVITY_OBJ_FILE)
);
@@ -12,7 +12,7 @@ function apply_updates() {
foreach($x as $xx) {
- $object = json_decode($xx['object'],true);
+ $object = json_decode($xx['obj'],true);
$d_mid = $object['d_mid'];
$u_mid = $xx['mid'];
diff --git a/include/smarty.php b/include/smarty.php
deleted file mode 100755
index 3812c6021..000000000
--- a/include/smarty.php
+++ /dev/null
@@ -1,114 +0,0 @@
- "view/theme/$theme/tpl/");
- if( x(App::$theme_info,"extends") )
- $template_dirs = $template_dirs + array('extends' => "view/theme/".App::$theme_info["extends"]."/tpl/");
- $template_dirs = $template_dirs + array('base' => 'view/tpl/');
- $this->setTemplateDir($template_dirs);
-
- $basecompiledir = App::$config['system']['smarty3_folder'];
-
- $this->setCompileDir($basecompiledir.'/compiled/');
- $this->setConfigDir($basecompiledir.'/config/');
- $this->setCacheDir($basecompiledir.'/cache/');
-
- $this->left_delimiter = App::get_template_ldelim('smarty3');
- $this->right_delimiter = App::get_template_rdelim('smarty3');
-
- // Don't report errors so verbosely
- $this->error_reporting = E_ALL & ~E_NOTICE;
- }
-
- function parsed($template = '') {
- if($template) {
- return $this->fetch('string:' . $template);
- }
- return $this->fetch('file:' . $this->filename);
- }
-}
-
-
-
-class FriendicaSmartyEngine implements ITemplateEngine {
- static $name ="smarty3";
-
- public function __construct(){
- $a = get_app();
-
- // Cannot use get_config() here because it is called during installation when there is no DB.
- // FIXME: this may leak private information such as system pathnames.
-
- $basecompiledir = ((array_key_exists('smarty3_folder',App::$config['system'])) ? App::$config['system']['smarty3_folder'] : '');
- if (!$basecompiledir) $basecompiledir = dirname(__dir__) . "/" . TEMPLATE_BUILD_PATH;
- if (!is_dir($basecompiledir)) {
- echo "ERROR: folder $basecompiledir does not exist."; killme();
- }
- if(!is_writable($basecompiledir)){
- echo "ERROR: folder $basecompiledir must be writable by webserver."; killme();
- }
- App::$config['system']['smarty3_folder'] = $basecompiledir;
- }
-
- // ITemplateEngine interface
- public function replace_macros($s, $r) {
- $template = '';
- if(gettype($s) === 'string') {
- $template = $s;
- $s = new FriendicaSmarty();
- }
- foreach($r as $key=>$value) {
- if($key[0] === '$') {
- $key = substr($key, 1);
- }
- $s->assign($key, $value);
- }
- return $s->parsed($template);
- }
-
- public function get_markup_template($file, $root=''){
- $template_file = theme_include($file, $root);
- if($template_file) {
- $template = new FriendicaSmarty();
- $template->filename = $template_file;
-
- return $template;
- }
- return "";
- }
-
- public function get_intltext_template($file, $root='') {
- $a = get_app();
-
- if(file_exists("view/{App::$language}/$file"))
- $template_file = "view/{App::$language}/$file";
- elseif(file_exists("view/en/$file"))
- $template_file = "view/en/$file";
- else
- $template_file = theme_include($file,$root);
- if($template_file) {
- $template = new FriendicaSmarty();
- $template->filename = $template_file;
-
- return $template;
- }
- return "";
- }
-
-
-
-}
diff --git a/include/socgraph.php b/include/socgraph.php
index 1b1bccf20..4cb5600ec 100644
--- a/include/socgraph.php
+++ b/include/socgraph.php
@@ -152,11 +152,9 @@ function poco_load($xchan = '', $url = null) {
if(($x !== false) && (! count($x))) {
if($address) {
if($network === 'zot') {
- $z = zot_finger($address,null);
- if($z['success']) {
- $j = json_decode($z['body'],true);
- if($j)
- import_xchan($j);
+ $j = Zotlabs\Zot\Finger::run($address,null);
+ if($j['success']) {
+ import_xchan($j);
}
$x = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1",
dbesc($hash)
@@ -404,7 +402,7 @@ function poco($a,$extended = false) {
$system_mode = false;
- if(intval(get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) {
+ if(observer_prohibited()) {
logger('mod_poco: block_public');
http_status_exit(401);
}
diff --git a/include/taxonomy.php b/include/taxonomy.php
index e43f5e5d0..177215fe8 100644
--- a/include/taxonomy.php
+++ b/include/taxonomy.php
@@ -20,7 +20,7 @@ function file_tag_file_query($table,$s,$type = 'file') {
else
$termtype = TERM_CATEGORY;
- return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.type = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ",
+ return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.ttype = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ",
intval($termtype),
protect_sprintf(dbesc($s))
);
@@ -29,14 +29,14 @@ function file_tag_file_query($table,$s,$type = 'file') {
function term_query($table,$s,$type = TERM_UNKNOWN, $type2 = '') {
if($type2) {
- return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.type in (%d, %d) and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ",
+ return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.ttype in (%d, %d) and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ",
intval($type),
intval($type2),
protect_sprintf(dbesc($s))
);
}
else {
- return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.type = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ",
+ return sprintf(" AND " . (($table) ? dbesc($table) . '.' : '') . "id in (select term.oid from term where term.ttype = %d and term.term = '%s' and term.uid = " . (($table) ? dbesc($table) . '.' : '') . "uid ) ",
intval($type),
protect_sprintf(dbesc($s))
);
@@ -49,7 +49,7 @@ function store_item_tag($uid,$iid,$otype,$type,$term,$url = '') {
return false;
$r = q("select * from term
- where uid = %d and oid = %d and otype = %d and type = %d
+ where uid = %d and oid = %d and otype = %d and ttype = %d
and term = '%s' and url = '%s' ",
intval($uid),
intval($iid),
@@ -61,7 +61,7 @@ function store_item_tag($uid,$iid,$otype,$type,$term,$url = '') {
if($r)
return false;
- $r = q("insert into term (uid, oid, otype, type, term, url)
+ $r = q("insert into term (uid, oid, otype, ttype, term, url)
values( %d, %d, %d, %d, '%s', '%s') ",
intval($uid),
intval($iid),
@@ -85,7 +85,7 @@ function get_terms_oftype($arr,$type) {
foreach($type as $t)
foreach($arr as $x)
- if($x['type'] == $t)
+ if($x['ttype'] == $t)
$ret[] = $x;
return $ret;
@@ -93,9 +93,9 @@ function get_terms_oftype($arr,$type) {
function format_term_for_display($term) {
$s = '';
- if(($term['type'] == TERM_HASHTAG) || ($term['type'] == TERM_COMMUNITYTAG))
+ if(($term['ttype'] == TERM_HASHTAG) || ($term['ttype'] == TERM_COMMUNITYTAG))
$s .= '#';
- elseif($term['type'] == TERM_MENTION)
+ elseif($term['ttype'] == TERM_MENTION)
$s .= '@';
else
return $s;
@@ -142,7 +142,7 @@ function tagadelic($uid, $count = 0, $authors = '', $owner = '', $flags = 0, $re
// Fetch tags
$r = q("select term, count(term) as total from term left join item on term.oid = item.id
- where term.uid = %d and term.type = %d
+ where term.uid = %d and term.ttype = %d
and otype = %d and item_type = %d and item_private = 0
$sql_options $item_normal
group by term order by total desc %s",
diff --git a/include/text.php b/include/text.php
index 3f2e85fc8..1bc19da34 100644
--- a/include/text.php
+++ b/include/text.php
@@ -3,8 +3,6 @@
* @file include/text.php
*/
-require_once("include/template_processor.php");
-require_once("include/smarty.php");
require_once("include/bbcode.php");
// random string, there are 86 characters max in text mode, 128 for hex
@@ -16,13 +14,12 @@ define('RANDOM_STRING_TEXT', 0x01 );
/**
* @brief This is our template processor.
*
- * @param string|FriendicaSmarty $s the string requiring macro substitution,
- * or an instance of FriendicaSmarty
+ * @param string|SmartyEngine $s the string requiring macro substitution,
+ * or an instance of SmartyEngine
* @param array $r key value pairs (search => replace)
* @return string substituted string
*/
function replace_macros($s, $r) {
- $a = get_app();
$arr = array('template' => $s, 'params' => $r);
call_hooks('replace_macros', $arr);
@@ -98,7 +95,6 @@ function z_input_filter($channel_id,$s,$type = 'text/bbcode') {
if($type == 'application/x-pdl')
return escape_tags($s);
- $a = get_app();
if(App::$is_sys) {
return $s;
}
@@ -326,6 +322,15 @@ function autoname($len) {
function xmlify($str) {
$buffer = '';
+ if(is_array($str)) {
+
+ // allow to fall through so we ge a PHP error, as the log statement will
+ // probably get lost in the noise unless we're specifically looking for it.
+
+ btlogger('xmlify called with array: ' . print_r($str,true), LOGGER_NORMAL, LOG_WARNING);
+ }
+
+
$len = mb_strlen($str);
for($x = 0; $x < $len; $x ++) {
$char = mb_substr($str,$x,1);
@@ -569,21 +574,25 @@ function attribute_contains($attr, $s) {
*/
function logger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) {
- // turn off logger in install mode
- global $a;
- global $db;
- if((App::$module == 'install') || (! ($db && $db->connected)))
- return;
-
- $debugging = get_config('system', 'debugging');
- $loglevel = intval(get_config('system', 'loglevel'));
- $logfile = get_config('system', 'logfile');
+ if(App::$module == 'setup' && is_writable('install.log')) {
+ $debugging = true;
+ $logfile = 'install.log';
+ $loglevel = LOGGER_ALL;
+ }
+ else {
+ $debugging = get_config('system', 'debugging');
+ $loglevel = intval(get_config('system', 'loglevel'));
+ $logfile = get_config('system', 'logfile');
+ }
if((! $debugging) || (! $logfile) || ($level > $loglevel))
return;
$where = '';
+
+ // We require > 5.4 but leave the version check so that install issues (including version) can be logged
+
if(version_compare(PHP_VERSION, '5.4.0') >= 0) {
$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
$where = basename($stack[0]['file']) . ':' . $stack[0]['line'] . ':' . $stack[1]['function'] . ': ';
@@ -592,7 +601,8 @@ function logger($msg, $level = LOGGER_NORMAL, $priority = LOG_INFO) {
$s = datetime_convert() . ':' . log_priority_str($priority) . ':' . session_id() . ':' . $where . $msg . PHP_EOL;
$pluginfo = array('filename' => $logfile, 'loglevel' => $level, 'message' => $s,'priority' => $priority, 'logged' => false);
- call_hooks('logger',$pluginfo);
+ if(! (App::$module == 'setup'))
+ call_hooks('logger',$pluginfo);
if(! $pluginfo['logged'])
@file_put_contents($pluginfo['filename'], $pluginfo['message'], FILE_APPEND);
@@ -650,11 +660,10 @@ function log_priority_str($priority) {
* @param int $level A log level.
*/
function dlogger($msg, $level = 0) {
- // turn off logger in install mode
- global $a;
- global $db;
- if((App::$module == 'install') || (! ($db && $db->connected)))
+ // turn off logger in install mode
+
+ if(App::$module == 'setup')
return;
$debugging = get_config('system','debugging');
@@ -725,6 +734,10 @@ function get_tags($s) {
// '=' needs to be avoided because when the replacement is made (in handle_tag()) it has to be ignored there
// Feel free to allow '=' if the issue with '=' is solved in handle_tag()
// added / ? and [ to avoid issues with hashchars in url paths
+
+ // added ; to single word tags to allow emojis and other unicode character constructs in bbcode
+ // (this would actually be nnnnn; but the ampersand will have been escaped to & by the time we see it.)
+
if(preg_match_all('/(?' . "\r\n";
$o .= "\t\t" . ' ' . "\r\n";
}
@@ -812,7 +825,6 @@ function get_mentions($item,$tags) {
function contact_block() {
$o = '';
- $a = get_app();
if(! App::$profile['uid'])
return;
@@ -925,7 +937,7 @@ function micropro($contact, $redirect = false, $class = '', $textmode = false) {
function search($s,$id='search-box',$url='/search',$save = false) {
- $a = get_app();
+
return replace_macros(get_markup_template('searchbox.tpl'),array(
'$s' => $s,
'$id' => $id,
@@ -1070,7 +1082,7 @@ function get_mood_verbs() {
// Function to list all smilies, both internal and from addons
// Returns array with keys 'texts' and 'icons'
function list_smilies() {
- $a = get_app();
+
$texts = array(
'<3',
'</3',
@@ -1104,9 +1116,7 @@ function list_smilies() {
':facepalm',
':like',
':dislike',
- 'red#matrix',
- 'red#',
- 'r#'
+ ':hubzilla'
);
$icons = array(
@@ -1142,12 +1152,24 @@ function list_smilies() {
' ',
' ',
' ',
- 'red matrix ',
- 'red matrix ',
- 'red matrix '
+ ' ',
);
+ $x = get_config('feature','emoji');
+ if($x === false)
+ $x = 1;
+ if($x) {
+ if(! App::$emojitab)
+ App::$emojitab = json_decode(file_get_contents('library/emoji.json'),true);
+ foreach(App::$emojitab as $e) {
+ if(strpos($e['shortname'],':tone') === 0)
+ continue;
+ $texts[] = $e['shortname'];
+ $icons[] = ' ';
+ }
+ }
+
$params = array('texts' => $texts, 'icons' => $icons);
call_hooks('smilie', $params);
@@ -1215,7 +1237,7 @@ function smile_unshield($m) {
* @param array $x
*/
function preg_heart($x) {
- $a = get_app();
+
if (strlen($x[1]) == 1)
return $x[0];
@@ -1321,7 +1343,7 @@ function theme_attachments(&$item) {
$title = t('Size') . ' ' . (($r['length']) ? userReadableSize($r['length']) : t('unknown'));
- require_once('include/identity.php');
+ require_once('include/channel.php');
if(is_foreigner($item['author_xchan']))
$url = $r['href'];
else
@@ -1455,40 +1477,8 @@ function generate_named_map($location) {
return (($arr['html']) ? $arr['html'] : $location);
}
-function format_event($jobject) {
- $event = array();
-
- $object = json_decode($jobject,true);
-
- //ensure compatibility with older items - this check can be removed at a later point
- if(array_key_exists('description', $object)) {
-
- $bd_format = t('l F d, Y \@ g:i A'); // Friday January 18, 2011 @ 8:01 AM
-
- $event['header'] = replace_macros(get_markup_template('event_item_header.tpl'),array(
- '$title' => bbcode($object['title']),
- '$dtstart_label' => t('Starts:'),
- '$dtstart_title' => datetime_convert('UTC', 'UTC', $object['start'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
- '$dtstart_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['start'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['start'] , $bd_format))),
- '$finish' => (($object['nofinish']) ? false : true),
- '$dtend_label' => t('Finishes:'),
- '$dtend_title' => datetime_convert('UTC','UTC',$object['finish'], (($object['adjust']) ? ATOM_TIME : 'Y-m-d\TH:i:s' )),
- '$dtend_dt' => (($object['adjust']) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['finish'] , $bd_format )) : day_translate(datetime_convert('UTC', 'UTC', $object['finish'] , $bd_format )))
- ));
-
- $event['content'] = replace_macros(get_markup_template('event_item_content.tpl'),array(
- '$description' => bbcode($object['description']),
- '$location_label' => t('Location:'),
- '$location' => bbcode($object['location'])
- ));
-
- }
-
- return $event;
-}
function prepare_body(&$item,$attach = false) {
- require_once('include/identity.php');
call_hooks('prepare_body_init', $item);
@@ -1498,7 +1488,7 @@ function prepare_body(&$item,$attach = false) {
if($is_photo) {
- $object = json_decode($item['object'],true);
+ $object = json_decode($item['obj'],true);
// if original photo width is <= 640px prepend it to item body
if($object['link'][0]['width'] && $object['link'][0]['width'] <= 640) {
@@ -1514,7 +1504,7 @@ function prepare_body(&$item,$attach = false) {
$s .= prepare_text($item['body'],$item['mimetype'], false);
- $event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event($item['object']) : false);
+ $event = (($item['obj_type'] === ACTIVITY_OBJ_EVENT) ? format_event_obj($item['obj']) : false);
$prep_arr = array(
'item' => $item,
@@ -1718,7 +1708,6 @@ function feed_hublinks() {
/* return atom link elements for salmon endpoints */
function feed_salmonlinks($nick) {
- $a = get_app();
$salmon = ' ' . "\n" ;
@@ -1786,7 +1775,7 @@ function mimetype_select($channel_id, $current = 'text/bbcode') {
'application/x-pdl'
);
- $a = get_app();
+
if(App::$is_sys) {
$x[] = 'application/x-php';
}
@@ -1819,7 +1808,6 @@ function mimetype_select($channel_id, $current = 'text/bbcode') {
function lang_selector() {
- global $a;
$langs = glob('view/*/hstrings.php');
@@ -2263,7 +2251,7 @@ function design_tools() {
$sys = false;
if(App::$is_sys && is_site_admin()) {
- require_once('include/identity.php');
+ require_once('include/channel.php');
$channel = get_sys_channel();
$sys = true;
}
@@ -2860,3 +2848,32 @@ function pdl_selector($uid, $current="") {
return $o;
}
+/*
+ * array flatten_array_recursive(array);
+ * returns a one-dimensional array from a multi-dimensional array
+ * empty values are discarded
+ * example: print_r(flatten_array_recursive(array('foo','bar',array('baz','blip',array('zob','glob')),'','grip')));
+ *
+ * Array ( [0] => foo [1] => bar [2] => baz [3] => blip [4] => zob [5] => glob [6] => grip )
+ *
+ */
+
+function flatten_array_recursive($arr) {
+ $ret = array();
+
+ if(! $arr)
+ return $ret;
+
+ foreach($arr as $a) {
+ if(is_array($a)) {
+ $tmp = flatten_array_recursive($a);
+ if($tmp) {
+ $ret = array_merge($ret,$tmp);
+ }
+ }
+ elseif($a) {
+ $ret[] = $a;
+ }
+ }
+ return($ret);
+}
diff --git a/include/widgets.php b/include/widgets.php
index 2641a718e..3ca189af0 100644
--- a/include/widgets.php
+++ b/include/widgets.php
@@ -8,17 +8,17 @@
require_once('include/dir_fns.php');
require_once('include/contact_widgets.php');
require_once('include/attach.php');
-require_once('include/Contact.php');
+
function widget_profile($args) {
- $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
+ $block = observer_prohibited();
return profile_sidebar(App::$profile, $block, true);
}
function widget_zcard($args) {
- $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
+ $block = observer_prohibited();
$channel = channelx_by_n(App::$profile_uid);
return get_zcard($channel,get_observer_hash(),array('width' => 875));
}
@@ -212,13 +212,13 @@ function widget_savedsearch($arr) {
$search = ((x($_GET,'search')) ? $_GET['search'] : '');
if(x($_GET,'searchsave') && $search) {
- $r = q("select * from `term` where `uid` = %d and `type` = %d and `term` = '%s' limit 1",
+ $r = q("select * from `term` where `uid` = %d and `ttype` = %d and `term` = '%s' limit 1",
intval(local_channel()),
intval(TERM_SAVEDSEARCH),
dbesc($search)
);
if(! $r) {
- q("insert into `term` ( `uid`,`type`,`term` ) values ( %d, %d, '%s') ",
+ q("insert into `term` ( `uid`,`ttype`,`term` ) values ( %d, %d, '%s') ",
intval(local_channel()),
intval(TERM_SAVEDSEARCH),
dbesc($search)
@@ -227,7 +227,7 @@ function widget_savedsearch($arr) {
}
if(x($_GET,'searchremove') && $search) {
- q("delete from `term` where `uid` = %d and `type` = %d and `term` = '%s'",
+ q("delete from `term` where `uid` = %d and `ttype` = %d and `term` = '%s'",
intval(local_channel()),
intval(TERM_SAVEDSEARCH),
dbesc($search)
@@ -254,7 +254,7 @@ function widget_savedsearch($arr) {
$o = '';
- $r = q("select `tid`,`term` from `term` WHERE `uid` = %d and `type` = %d ",
+ $r = q("select `tid`,`term` from `term` WHERE `uid` = %d and `ttype` = %d ",
intval(local_channel()),
intval(TERM_SAVEDSEARCH)
);
@@ -296,7 +296,7 @@ function widget_filer($arr) {
$selected = ((x($_REQUEST,'file')) ? $_REQUEST['file'] : '');
$terms = array();
- $r = q("select distinct(term) from term where uid = %d and type = %d order by term asc",
+ $r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
intval(local_channel()),
intval(TERM_FILE)
);
@@ -369,7 +369,7 @@ function widget_fullprofile($arr) {
if(! App::$profile['profile_uid'])
return;
- $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
+ $block = observer_prohibited();
return profile_sidebar(App::$profile, $block);
}
@@ -379,7 +379,7 @@ function widget_shortprofile($arr) {
if(! App::$profile['profile_uid'])
return;
- $block = (((get_config('system', 'block_public')) && (! local_channel()) && (! remote_channel())) ? true : false);
+ $block = observer_prohibited();
return profile_sidebar(App::$profile, $block, true, true);
}
@@ -771,7 +771,6 @@ function widget_eventstools($arr) {
}
function widget_design_tools($arr) {
- $a = get_app();
// mod menu doesn't load a profile. For any modules which load a profile, check it.
// otherwise local_channel() is sufficient for permissions.
@@ -800,13 +799,14 @@ function widget_photo_albums($arr) {
if((! $channelx) || (! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_storage')))
return '';
require_once('include/photos.php');
+ $sortkey = ((array_key_exists('sortkey',$arr)) ? $arr['sortkey'] : 'album');
+ $direction = ((array_key_exists('direction',$arr)) ? $arr['direction'] : 'asc');
- return photos_album_widget($channelx, App::get_observer());
+ return photos_album_widget($channelx, App::get_observer(),$sortkey,$direction);
}
function widget_vcard($arr) {
- require_once ('include/Contact.php');
return vcard_from_xchan('', App::get_observer());
}
@@ -835,8 +835,7 @@ function widget_menu_preview($arr) {
function widget_chatroom_list($arr) {
- require_once("include/chat.php");
- $r = chatroom_list(App::$profile['profile_uid']);
+ $r = Zotlabs\Lib\Chatroom::roomlist(App::$profile['profile_uid']);
if($r) {
return replace_macros(get_markup_template('chatroomlist.tpl'), array(
@@ -857,6 +856,78 @@ function widget_chatroom_members() {
return $o;
}
+function widget_wiki_list($arr) {
+
+ require_once("include/wiki.php");
+ $channel = null;
+ if (argc() < 2 && local_channel()) {
+ // This should not occur because /wiki should redirect to /wiki/channel ...
+ $channel = \App::get_channel();
+ } else {
+ $channel = get_channel_by_nick(argv(1)); // Channel being viewed by observer
+ }
+ if (!$channel) {
+ return '';
+ }
+ $wikis = wiki_list($channel, get_observer_hash());
+ if ($wikis) {
+ return replace_macros(get_markup_template('wikilist.tpl'), array(
+ '$header' => t('Wiki List'),
+ '$channel' => $channel['channel_address'],
+ '$wikis' => $wikis['wikis'],
+ // If the observer is the local channel owner, show the wiki controls
+ '$showControls' => ((local_channel() === intval($channel['channel_id'])) ? true : false)
+ ));
+ }
+ return '';
+}
+
+function widget_wiki_pages($arr) {
+
+ require_once("include/wiki.php");
+ $channelname = ((array_key_exists('channel',$arr)) ? $arr['channel'] : '');
+ $wikiname = '';
+ if (array_key_exists('refresh', $arr)) {
+ $not_refresh = (($arr['refresh']=== true) ? false : true);
+ } else {
+ $not_refresh = true;
+ }
+ $pages = array();
+ if (!array_key_exists('resource_id', $arr)) {
+ $hide = true;
+ } else {
+ $p = wiki_page_list($arr['resource_id']);
+ if ($p['pages']) {
+ $pages = $p['pages'];
+ $w = $p['wiki'];
+ // Wiki item record is $w['wiki']
+ $wikiname = $w['urlName'];
+ if (!$wikiname) {
+ $wikiname = '';
+ }
+ }
+ }
+ return replace_macros(get_markup_template('wiki_page_list.tpl'), array(
+ '$hide' => $hide,
+ '$not_refresh' => $not_refresh,
+ '$header' => t('Wiki Pages'),
+ '$channel' => $channelname,
+ '$wikiname' => $wikiname,
+ '$pages' => $pages
+ ));
+}
+
+function widget_wiki_page_history($arr) {
+ require_once("include/wiki.php");
+ $pageUrlName = ((array_key_exists('pageUrlName', $arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : '');
+ $pageHistory = wiki_page_history(array('resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
+
+ return replace_macros(get_markup_template('wiki_page_history.tpl'), array(
+ '$pageHistory' => $pageHistory['history']
+ ));
+}
+
function widget_bookmarkedchats($arr) {
if(! feature_enabled(App::$profile['profile_uid'],'ajaxchat'))
@@ -1052,7 +1123,7 @@ function widget_photo($arr) {
function widget_cover_photo($arr) {
- require_once('include/identity.php');
+ require_once('include/channel.php');
$o = '';
if(App::$module == 'channel' && $_REQUEST['mid'])
@@ -1129,7 +1200,7 @@ function widget_photo_rand($arr) {
$filtered = array();
if($ret['success'] && $ret['photos'])
foreach($ret['photos'] as $p)
- if($p['scale'] == $scale)
+ if($p['imgscale'] == $scale)
$filtered[] = $p['src'];
if($filtered) {
@@ -1381,7 +1452,7 @@ function widget_admin($arr) {
$aside = array(
'site' => array(z_root() . '/admin/site/', t('Site'), 'site'),
- 'users' => array(z_root() . '/admin/users/', t('Accounts'), 'users', 'pending-update', t('Member registrations waiting for confirmation')),
+ 'accounts' => array(z_root() . '/admin/accounts/', t('Accounts'), 'accounts', 'pending-update', t('Member registrations waiting for confirmation')),
'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'),
'security' => array(z_root() . '/admin/security/', t('Security'), 'security'),
'features' => array(z_root() . '/admin/features/', t('Features'), 'features'),
@@ -1400,7 +1471,7 @@ function widget_admin($arr) {
$plugins = array();
if($r) {
foreach ($r as $h){
- $plugin = $h['name'];
+ $plugin = $h['aname'];
$plugins[] = array(z_root() . '/admin/plugins/' . $plugin, $plugin, 'plugin');
// temp plugins with admin
App::$plugins_admin[] = $plugin;
@@ -1462,9 +1533,9 @@ function widget_album($args) {
$order = 'DESC';
- $r = q("SELECT p.resource_id, p.id, p.filename, p.type, p.scale, p.description, p.created FROM photo p INNER JOIN
- (SELECT resource_id, max(scale) scale FROM photo WHERE uid = %d AND album = '%s' AND scale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph
- ON (p.resource_id = ph.resource_id AND p.scale = ph.scale)
+ $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN
+ (SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph
+ ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale)
ORDER BY created $order ",
intval($owner_uid),
dbesc($album),
@@ -1485,7 +1556,7 @@ function widget_album($args) {
else
$twist = 'rotright';
- $ext = $phototypes[$rr['type']];
+ $ext = $phototypes[$rr['mimetype']];
$imgalt_e = $rr['filename'];
$desc_e = $rr['description'];
@@ -1498,7 +1569,7 @@ function widget_album($args) {
'twist' => ' ' . $twist . rand(2,4),
'link' => $imagelink,
'title' => t('View Photo'),
- 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['scale'] . '.' .$ext,
+ 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext,
'alt' => $imgalt_e,
'desc'=> $desc_e,
'ext' => $ext,
diff --git a/include/wiki.php b/include/wiki.php
new file mode 100644
index 000000000..4aa3fc1b4
--- /dev/null
+++ b/include/wiki.php
@@ -0,0 +1,399 @@
+ $wikis);
+}
+
+function wiki_page_list($resource_id) {
+ // TODO: Create item table records for pages so that metadata like title can be applied
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('pages' => null, 'wiki' => null);
+ }
+ $pages = array();
+ if (is_dir($w['path']) === true) {
+ $files = array_diff(scandir($w['path']), array('.', '..', '.git'));
+ // TODO: Check that the files are all text files
+
+ foreach($files as $file) {
+ // strip the .md file extension and unwrap URL encoding to leave HTML encoded name
+ $pages[] = array('title' => urldecode(substr($file, 0, -3)), 'url' => urlencode(substr($file, 0, -3)));
+ }
+ }
+
+ return array('pages' => $pages, 'wiki' => $w);
+}
+
+function wiki_init_wiki($channel, $wiki) {
+ // Store the path as a relative path, but pass absolute path to mkdir
+ $path = 'store/[data]/git/'.$channel['channel_address'].'/wiki/'.$wiki['urlName'];
+ if (!os_mkdir(__DIR__ . '/../' . $path, 0770, true)) {
+ logger('Error creating wiki path: ' . $path);
+ return null;
+ }
+ // Create GitRepo object
+ $git = new GitRepo($channel['channel_address'], null, false, $name, __DIR__ . '/../' . $path);
+ if(!$git->initRepo()) {
+ logger('Error creating new git repo in ' . $git->path);
+ return null;
+ }
+
+ return array('path' => $path);
+}
+
+function wiki_create_wiki($channel, $observer_hash, $wiki, $acl) {
+ $wikiinit = wiki_init_wiki($channel, $wiki);
+ if (!$wikiinit['path']) {
+ notice('Error creating wiki');
+ return array('item' => null, 'success' => false);
+ }
+ $path = $wikiinit['path'];
+ // Generate unique resource_id using the same method as item_message_id()
+ do {
+ $dups = false;
+ $resource_id = random_string();
+ $r = q("SELECT mid FROM item WHERE resource_id = '%s' AND resource_type = '%s' AND uid = %d LIMIT 1",
+ dbesc($resource_id),
+ dbesc(WIKI_ITEM_RESOURCE_TYPE),
+ intval($channel['channel_id'])
+ );
+ if (count($r))
+ $dups = true;
+ } while ($dups == true);
+ $ac = $acl->get();
+ $mid = item_message_id();
+ $arr = array(); // Initialize the array of parameters for the post
+ $item_hidden = 0; // TODO: Allow form creator to send post to ACL about new game automatically
+ $wiki_url = z_root() . '/wiki/' . $channel['channel_address'] . '/' . $wiki['urlName'];
+ $arr['aid'] = $channel['channel_account_id'];
+ $arr['uid'] = $channel['channel_id'];
+ $arr['mid'] = $mid;
+ $arr['parent_mid'] = $mid;
+ $arr['item_hidden'] = $item_hidden;
+ $arr['resource_type'] = WIKI_ITEM_RESOURCE_TYPE;
+ $arr['resource_id'] = $resource_id;
+ $arr['owner_xchan'] = $channel['channel_hash'];
+ $arr['author_xchan'] = $observer_hash;
+ $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid'];
+ $arr['llink'] = $arr['plink'];
+ $arr['title'] = $wiki['htmlName']; // name of new wiki;
+ $arr['allow_cid'] = $ac['allow_cid'];
+ $arr['allow_gid'] = $ac['allow_gid'];
+ $arr['deny_cid'] = $ac['deny_cid'];
+ $arr['deny_gid'] = $ac['deny_gid'];
+ $arr['item_wall'] = 1;
+ $arr['item_origin'] = 1;
+ $arr['item_thread_top'] = 1;
+ $arr['item_private'] = intval($acl->is_private());
+ $arr['verb'] = ACTIVITY_CREATE;
+ $arr['obj_type'] = ACTIVITY_OBJ_WIKI;
+ $arr['body'] = '[table][tr][td][h1]New Wiki[/h1][/td][/tr][tr][td][zrl=' . $wiki_url . ']' . $wiki['htmlName'] . '[/zrl][/td][/tr][/table]';
+ // Save the path using iconfig. The file path should not be shared with other hubs
+ if (!set_iconfig($arr, 'wiki', 'path', $path, false)) {
+ return array('item' => null, 'success' => false);
+ }
+ // Save the wiki name information using iconfig. This is shareable.
+ if (!set_iconfig($arr, 'wiki', 'rawName', $wiki['rawName'], true)) {
+ return array('item' => null, 'success' => false);
+ }
+ if (!set_iconfig($arr, 'wiki', 'htmlName', $wiki['htmlName'], true)) {
+ return array('item' => null, 'success' => false);
+ }
+ if (!set_iconfig($arr, 'wiki', 'urlName', $wiki['urlName'], true)) {
+ return array('item' => null, 'success' => false);
+ }
+ $post = item_store($arr);
+ $item_id = $post['item_id'];
+
+ if ($item_id) {
+ proc_run('php', "include/notifier.php", "activity", $item_id);
+ return array('item' => $arr, 'success' => true);
+ } else {
+ return array('item' => null, 'success' => false);
+ }
+}
+
+function wiki_delete_wiki($resource_id) {
+
+ $w = wiki_get_wiki($resource_id);
+ $item = $w['wiki'];
+ if (!$item || !$w['path']) {
+ return array('item' => null, 'success' => false);
+ } else {
+ $drop = drop_item($item['id'], false, DROPITEM_NORMAL, true);
+ $pathdel = rrmdir($w['path']);
+ if ($pathdel) {
+ info('Wiki files deleted successfully');
+ }
+ return array('item' => $item, 'success' => (($drop === 1 && $pathdel) ? true : false));
+ }
+}
+
+function wiki_get_wiki($resource_id) {
+ $item = q("SELECT * FROM item WHERE resource_type = '%s' AND resource_id = '%s' AND item_deleted = 0 limit 1",
+ dbesc(WIKI_ITEM_RESOURCE_TYPE),
+ dbesc($resource_id)
+ );
+ if (!$item) {
+ return array('wiki' => null, 'path' => null);
+ } else {
+ $w = $item[0]; // wiki item table record
+ // Get wiki metadata
+ $rawName = get_iconfig($w, 'wiki', 'rawName');
+ $htmlName = get_iconfig($w, 'wiki', 'htmlName');
+ $urlName = get_iconfig($w, 'wiki', 'urlName');
+ $path = get_iconfig($w, 'wiki', 'path');
+ if (!realpath(__DIR__ . '/../' . $path)) {
+ return array('wiki' => null, 'path' => null);
+ }
+ // Path to wiki exists
+ $abs_path = realpath(__DIR__ . '/../' . $path);
+ return array( 'wiki' => $w,
+ 'path' => $abs_path,
+ 'rawName' => $rawName,
+ 'htmlName' => $htmlName,
+ 'urlName' => $urlName
+ );
+ }
+}
+
+function wiki_exists_by_name($uid, $urlName) {
+ $item = q("SELECT id,resource_id FROM item WHERE resource_type = '%s' AND title = '%s' AND uid = '%s' AND item_deleted = 0 limit 1",
+ dbesc(WIKI_ITEM_RESOURCE_TYPE),
+ dbesc(escape_tags(urldecode($urlName))),
+ dbesc($uid)
+ );
+ if (!$item) {
+ return array('id' => null, 'resource_id' => null);
+ } else {
+ return array('id' => $item[0]['id'], 'resource_id' => $item[0]['resource_id']);
+ }
+}
+
+function wiki_get_permissions($resource_id, $owner_id, $observer_hash) {
+ // TODO: For now, only the owner can edit
+ $sql_extra = item_permissions_sql($owner_id, $observer_hash);
+ $r = q("SELECT * FROM item WHERE resource_type = '%s' AND resource_id = '%s' $sql_extra LIMIT 1",
+ dbesc(WIKI_ITEM_RESOURCE_TYPE),
+ dbesc($resource_id)
+ );
+
+ if (!$r) {
+ return array('read' => false, 'write' => false, 'success' => true);
+ } else {
+ $perms = get_all_perms($owner_id, $observer_hash);
+ // TODO: Create a new permission setting for wiki analogous to webpages. Until
+ // then, use webpage permissions
+ if (!$perms['write_pages']) {
+ $write = false;
+ } else {
+ $write = true;
+ }
+ return array('read' => true, 'write' => $write, 'success' => true);
+ }
+}
+
+function wiki_create_page($name, $resource_id) {
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('page' => null, 'wiki' => null, 'message' => 'Wiki not found.', 'success' => false);
+ }
+ $page = array('rawName' => $name, 'htmlName' => escape_tags($name), 'urlName' => urlencode(escape_tags($name)), 'fileName' => urlencode(escape_tags($name)).'.md');
+ $page_path = $w['path'] . '/' . $page['fileName'];
+ if (is_file($page_path)) {
+ return array('page' => null, 'wiki' => null, 'message' => 'Page already exists.', 'success' => false);
+ }
+ // Create the page file in the wiki repo
+ if(!touch($page_path)) {
+ return array('page' => null, 'wiki' => null, 'message' => 'Page file cannot be created.', 'success' => false);
+ } else {
+ return array('page' => $page, 'wiki' => $w, 'message' => '', 'success' => true);
+ }
+
+}
+
+function wiki_get_page_content($arr) {
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('content' => null, 'message' => 'Error reading wiki', 'success' => false);
+ }
+ $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ if (is_readable($page_path) === true) {
+ if(filesize($page_path) === 0) {
+ $content = '';
+ } else {
+ $content = file_get_contents($page_path);
+ if(!$content) {
+ return array('content' => null, 'message' => 'Error reading page content', 'success' => false);
+ }
+ }
+ // TODO: Check that the files are all text files
+ return array('content' => json_encode($content), 'message' => '', 'success' => true);
+ }
+}
+
+function wiki_page_history($arr) {
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('history' => null, 'message' => 'Error reading wiki', 'success' => false);
+ }
+ $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ if (!is_readable($page_path) === true) {
+ return array('history' => null, 'message' => 'Cannot read wiki page: ' . $page_path, 'success' => false);
+ }
+ $reponame = ((array_key_exists('title', $w['wiki'])) ? $w['wiki']['title'] : 'repo');
+ if($reponame === '') {
+ $reponame = 'repo';
+ }
+ $git = new GitRepo('', null, false, $w['wiki']['title'], $w['path']);
+ try {
+ $gitlog = $git->git->log('', $page_path , array('limit' => 500));
+ return array('history' => $gitlog, 'message' => '', 'success' => true);
+ } catch (\PHPGit\Exception\GitException $e) {
+ return array('history' => null, 'message' => 'GitRepo error thrown', 'success' => false);
+ }
+}
+
+function wiki_save_page($arr) {
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $content = ((array_key_exists('content',$arr)) ? purify_html($arr['content']) : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('message' => 'Error reading wiki', 'success' => false);
+ }
+ $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ if (is_writable($page_path) === true) {
+ if(!file_put_contents($page_path, $content)) {
+ return array('message' => 'Error writing to page file', 'success' => false);
+ }
+ return array('message' => '', 'success' => true);
+ } else {
+ return array('message' => 'Page file not writable', 'success' => false);
+ }
+}
+
+function wiki_delete_page($arr) {
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('message' => 'Error reading wiki', 'success' => false);
+ }
+ $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ if (is_writable($page_path) === true) {
+ if(!unlink($page_path)) {
+ return array('message' => 'Error deleting page file', 'success' => false);
+ }
+ return array('message' => '', 'success' => true);
+ } else {
+ return array('message' => 'Page file not writable', 'success' => false);
+ }
+}
+
+function wiki_revert_page($arr) {
+ $pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
+ $resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
+ $commitHash = ((array_key_exists('commitHash',$arr)) ? $arr['commitHash'] : null);
+ if (! $commitHash) {
+ return array('content' => $content, 'message' => 'No commit has provided', 'success' => false);
+ }
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('content' => $content, 'message' => 'Error reading wiki', 'success' => false);
+ }
+ $page_path = $w['path'].'/'.$pageUrlName.'.md';
+ if (is_writable($page_path) === true) {
+
+ $reponame = ((array_key_exists('title', $w['wiki'])) ? urlencode($w['wiki']['title']) : 'repo');
+ if($reponame === '') {
+ $reponame = 'repo';
+ }
+ $git = new GitRepo($observer['xchan_addr'], null, false, $w['wiki']['title'], $w['path']);
+ $content = null;
+ try {
+ $git->setIdentity($observer['xchan_name'], $observer['xchan_addr']);
+ foreach ($git->git->tree($commitHash) as $object) {
+ if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) {
+ $content = $git->git->cat->blob($object['hash']);
+ }
+ }
+ } catch (\PHPGit\Exception\GitException $e) {
+ json_return_and_die(array('content' => $content, 'message' => 'GitRepo error thrown', 'success' => false));
+ }
+ return array('content' => $content, 'message' => '', 'success' => true);
+ } else {
+ return array('content' => $content, 'message' => 'Page file not writable', 'success' => false);
+ }
+}
+
+function wiki_git_commit($arr) {
+ $files = ((array_key_exists('files', $arr)) ? $arr['files'] : null);
+ $commit_msg = ((array_key_exists('commit_msg', $arr)) ? $arr['commit_msg'] : 'Repo updated');
+ $resource_id = ((array_key_exists('resource_id', $arr)) ? $arr['resource_id'] : json_return_and_die(array('message' => 'Wiki resource_id required for git commit', 'success' => false)));
+ $observer = ((array_key_exists('observer', $arr)) ? $arr['observer'] : json_return_and_die(array('message' => 'Observer required for git commit', 'success' => false)));
+ $w = wiki_get_wiki($resource_id);
+ if (!$w['path']) {
+ return array('message' => 'Error reading wiki', 'success' => false);
+ }
+ $reponame = ((array_key_exists('title', $w['wiki'])) ? urlencode($w['wiki']['title']) : 'repo');
+ if($reponame === '') {
+ $reponame = 'repo';
+ }
+ $git = new GitRepo($observer['xchan_addr'], null, false, $w['wiki']['title'], $w['path']);
+ try {
+ $git->setIdentity($observer['xchan_name'], $observer['xchan_addr']);
+ if ($files === null) {
+ $options = array('all' => true); // git commit option to include all changes
+ } else {
+ $options = array(); // git commit options
+ foreach ($files as $file) {
+ if (!$git->git->add($file)) { // add specified files to the git repo stage
+ if (!$git->git->reset->hard()) {
+ json_return_and_die(array('message' => 'Error adding file to git stage: ' . $file . '. Error resetting git repo.', 'success' => false));
+ }
+ json_return_and_die(array('message' => 'Error adding file to git stage: ' . $file, 'success' => false));
+ }
+ }
+ }
+ if ($git->commit($commit_msg, $options)) {
+ json_return_and_die(array('message' => 'Wiki repo commit succeeded', 'success' => true));
+ } else {
+ json_return_and_die(array('message' => 'Wiki repo commit failed', 'success' => false));
+ }
+ } catch (\PHPGit\Exception\GitException $e) {
+ json_return_and_die(array('message' => 'GitRepo error thrown', 'success' => false));
+ }
+}
+
+function wiki_generate_page_filename($name) {
+ $file = urlencode(escape_tags($name));
+ if( $file === '') {
+ return null;
+ } else {
+ return $file . '.md';
+ }
+}
\ No newline at end of file
diff --git a/include/zot.php b/include/zot.php
index 8adc74ffa..043139e2f 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -329,8 +329,12 @@ function zot_refresh($them, $channel = null, $force = false) {
return false;
}
+ $token = random_string();
+
$postvars = array();
+ $postvars['token'] = $token;
+
if($channel) {
$postvars['target'] = $channel['channel_guid'];
$postvars['target_sig'] = $channel['channel_guid_sig'];
@@ -343,9 +347,9 @@ function zot_refresh($them, $channel = null, $force = false) {
$postvars['guid_hash'] = $them['xchan_hash'];
if (array_key_exists('xchan_guid',$them) && $them['xchan_guid']
&& array_key_exists('xchan_guid_sig',$them) && $them['xchan_guid_sig']) {
-
$postvars['guid'] = $them['xchan_guid'];
$postvars['guid_sig'] = $them['xchan_guid_sig'];
+
}
$rhs = '/.well-known/zot-info';
@@ -363,6 +367,22 @@ function zot_refresh($them, $channel = null, $force = false) {
return false;
}
+ $signed_token = ((is_array($j) && array_key_exists('signed_token',$j)) ? $j['signed_token'] : null);
+ if($signed_token) {
+ $valid = rsa_verify('token.' . $token,base64url_decode($signed_token),$j['key']);
+ if(! $valid) {
+ logger('invalid signed token: ' . $url . $rhs, LOGGER_NORMAL, LOG_ERR);
+ return false;
+ }
+ }
+ else {
+ logger('No signed token from ' . $url . $rhs, LOGGER_NORMAL, LOG_WARNING);
+ // after 2017-01-01 this will be a hard error unless you over-ride it.
+ if((time() > 1483228800) && (! get_config('system','allow_unsigned_zotfinger'))) {
+ return false;
+ }
+ }
+
$x = import_xchan($j, (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
if(! $x['success'])
@@ -453,7 +473,7 @@ function zot_refresh($them, $channel = null, $force = false) {
else {
// if we were just granted read stream permission and didn't have it before, try to pull in some posts
if((! ($r[0]['abook_their_perms'] & PERMS_R_STREAM)) && ($their_perms & PERMS_R_STREAM))
- proc_run('php','include/onepoll.php',$r[0]['abook_id']);
+ Zotlabs\Daemon\Master::Summon(array('Onepoll',$r[0]['abook_id']));
}
}
else {
@@ -504,9 +524,8 @@ function zot_refresh($them, $channel = null, $force = false) {
if($new_connection) {
if($new_perms != $previous_perms)
- proc_run('php','include/notifier.php','permission_create',$new_connection[0]['abook_id']);
- require_once('include/enotify.php');
- notification(array(
+ Zotlabs\Daemon\Master::Summon(array('Notifier','permission_create',$new_connection[0]['abook_id']));
+ Zotlabs\Lib\Enotify::submit(array(
'type' => NOTIFY_INTRO,
'from_xchan' => $x['hash'],
'to_xchan' => $channel['channel_hash'],
@@ -516,7 +535,17 @@ function zot_refresh($them, $channel = null, $force = false) {
if($their_perms & PERMS_R_STREAM) {
if(($channel['channel_w_stream'] & PERMS_PENDING)
|| (! intval($new_connection[0]['abook_pending'])) )
- proc_run('php','include/onepoll.php',$new_connection[0]['abook_id']);
+ Zotlabs\Daemon\Master::Summon(array('Onepoll',$new_connection[0]['abook_id']));
+ }
+
+
+ /** If there is a default group for this channel, add this connection to it */
+ $default_group = $channel['channel_default_group'];
+ if($default_group) {
+ require_once('include/group.php');
+ $g = group_rec_byhash($channel['channel_id'],$default_group);
+ if($g)
+ group_add_member($channel['channel_id'],'',$x['hash'],$g['id']);
}
unset($new_connection[0]['abook_id']);
@@ -1027,8 +1056,9 @@ function zot_process_response($hub, $arr, $outq) {
/**
* @brief
*
- * We received a notification packet (in mod/post.php) that a message is waiting for us, and we've verified the sender.
- * Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site private key.
+ * We received a notification packet (in mod_post) that a message is waiting for us, and we've verified the sender.
+ * Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site
+ * private key.
* The entire pickup message is encrypted with the remote site's public key.
* If everything checks out on the remote end, we will receive back a packet containing one or more messages,
* which will be processed and delivered before this function ultimately returns.
@@ -1102,6 +1132,7 @@ function zot_fetch($arr) {
* * [1] => \e string $delivery_status
* * [2] => \e string $address
*/
+
function zot_import($arr, $sender_url) {
$data = json_decode($arr['body'], true);
@@ -1332,7 +1363,7 @@ function zot_import($arr, $sender_url) {
*/
function public_recips($msg) {
- require_once('include/identity.php');
+ require_once('include/channel.php');
$check_mentions = false;
$include_sys = false;
@@ -1494,7 +1525,7 @@ function public_recips($msg) {
/**
* @brief
*
- * This is the second part of public_recipes().
+ * This is the second part of public_recips().
* We'll find all the channels willing to accept public posts from us, then
* match them against the sender privacy scope and see who in that list that
* the sender is allowing.
@@ -1703,7 +1734,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
if((! $relay) && (! $request) && (! $local_public)
&& perm_is_allowed($channel['channel_id'],$sender['hash'],'send_stream')) {
- proc_run('php', 'include/notifier.php', 'request', $channel['channel_id'], $sender['hash'], $arr['parent_mid']);
+ Zotlabs\Daemon\Master::Summon(array('Notifier', 'request', $channel['channel_id'], $sender['hash'], $arr['parent_mid']));
}
continue;
}
@@ -1775,7 +1806,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
if($relay && $item_id) {
logger('process_delivery: invoking relay');
- proc_run('php','include/notifier.php','relay',intval($item_id));
+ Zotlabs\Daemon\Master::Summon(array('Notifier','relay',intval($item_id)));
$DR->update('relayed');
$result[] = $DR->get();
}
@@ -1858,7 +1889,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
if($relay && $item_id) {
logger('process_delivery: invoking relay');
- proc_run('php','include/notifier.php','relay',intval($item_id));
+ Zotlabs\Daemon\Master::Summon(array('Notifier','relay',intval($item_id)));
$DR->addto_update('relayed');
$result[] = $DR->get();
}
@@ -1932,7 +1963,7 @@ function remove_community_tag($sender, $arr, $uid) {
return;
}
- q("delete from term where uid = %d and oid = %d and otype = %d and type in ( %d, %d ) and term = '%s' and url = '%s'",
+ q("delete from term where uid = %d and oid = %d and otype = %d and ttype in ( %d, %d ) and term = '%s' and url = '%s'",
intval($uid),
intval($r[0]['id']),
intval(TERM_OBJ_POST),
@@ -2381,11 +2412,14 @@ function sync_locations($sender, $arr, $absolute = false) {
$current_site = false;
+ $t = datetime_convert('UTC','UTC','now - 15 minutes');
+
if(array_key_exists('site',$arr) && $location['url'] == $arr['site']['url']) {
- q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d",
+ q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_connected < '%s'",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
- intval($r[0]['hubloc_id'])
+ intval($r[0]['hubloc_id']),
+ dbesc($t)
);
$current_site = true;
}
@@ -2945,8 +2979,6 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
if(UNO)
return;
- $a = get_app();
-
logger('build_sync_packet');
if($packet)
@@ -3029,7 +3061,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
}
if($groups_changed) {
- $r = q("select hash as collection, visible, deleted, name from groups where uid = %d",
+ $r = q("select hash as collection, visible, deleted, gname as name from groups where uid = %d",
intval($uid)
);
if($r)
@@ -3060,7 +3092,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) {
'msg' => json_encode($info)
));
- proc_run('php', 'include/deliver.php', $hash);
+ Zotlabs\Daemon\Master::Summon(array('Deliver', $hash));
$total = $total - 1;
if($interval && $total)
@@ -3222,7 +3254,6 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
$clean = array();
if($abook['abook_xchan'] && $abook['entry_deleted']) {
logger('process_channel_sync_delivery: removing abook entry for ' . $abook['abook_xchan']);
- require_once('include/Contact.php');
$r = q("select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1",
dbesc($abook['abook_xchan']),
@@ -3323,10 +3354,10 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
}
}
if($found) {
- if(($y['name'] != $cl['name'])
+ if(($y['gname'] != $cl['name'])
|| ($y['visible'] != $cl['visible'])
|| ($y['deleted'] != $cl['deleted'])) {
- q("update groups set name = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d",
+ q("update groups set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d",
dbesc($cl['name']),
intval($cl['visible']),
intval($cl['deleted']),
@@ -3342,7 +3373,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
}
}
if(! $found) {
- $r = q("INSERT INTO `groups` ( hash, uid, visible, deleted, name )
+ $r = q("INSERT INTO `groups` ( hash, uid, visible, deleted, gname )
VALUES( '%s', %d, %d, %d, '%s' ) ",
dbesc($cl['collection']),
intval($channel['channel_id']),
@@ -3449,7 +3480,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('profile',$arr) && is_array($arr['profile']) && count($arr['profile'])) {
- $disallowed = array('id','aid','uid');
+ $disallowed = array('id','aid','uid','guid');
foreach($arr['profile'] as $profile) {
$x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1",
@@ -3473,13 +3504,22 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
foreach($profile as $k => $v) {
if(in_array($k,$disallowed))
continue;
+
+ if($k === 'name')
+ $clean['fullname'] = $v;
+ elseif($k === 'with')
+ $clean['partner'] = $v;
+ elseif($k === 'work')
+ $clean['employment'] = $v;
+ elseif(array_key_exists($k,$x[0]))
+ $clean[$k] = $v;
- $clean[$k] = $v;
/**
- * @TODO check if these are allowed, otherwise we'll error
+ * @TODO
* We also need to import local photos if a custom photo is selected
*/
}
+
if(count($clean)) {
foreach($clean as $k => $v) {
$r = dbq("UPDATE profile set `" . dbesc($k) . "` = '" . dbesc($v)
@@ -3652,7 +3692,7 @@ function zot_reply_message_request($data) {
* invoke delivery to send out the notify packet
*/
- proc_run('php', 'include/deliver.php', $hash);
+ Zotlabs\Daemon\Master::Summon(array('Deliver', $hash));
}
}
$ret['success'] = true;
@@ -3672,6 +3712,8 @@ function zotinfo($arr) {
$zsig = ((x($arr,'target_sig')) ? $arr['target_sig'] : '');
$zkey = ((x($arr,'key')) ? $arr['key'] : '');
$mindate = ((x($arr,'mindate')) ? $arr['mindate'] : '');
+ $token = ((x($arr,'token')) ? $arr['token'] : '');
+
$feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0);
if($ztarget) {
@@ -3816,6 +3858,10 @@ function zotinfo($arr) {
// Communication details
+ if($token)
+ $ret['signed_token'] = base64url_encode(rsa_sign('token.' . $token,$e['channel_prvkey']));
+
+
$ret['guid'] = $e['xchan_guid'];
$ret['guid_sig'] = $e['xchan_guid_sig'];
$ret['key'] = $e['xchan_pubkey'];
@@ -3920,16 +3966,14 @@ function zotinfo($arr) {
$ret['site']['accounts'] = account_total();
- require_once('include/identity.php');
+ require_once('include/channel.php');
$ret['site']['channels'] = channel_total();
- $ret['site']['version'] = Zotlabs\Project\System::get_platform_name() . ' ' . STD_VERSION . '[' . DB_UPDATE_VERSION . ']';
+ $ret['site']['version'] = Zotlabs\Lib\System::get_platform_name() . ' ' . STD_VERSION . '[' . DB_UPDATE_VERSION . ']';
$ret['site']['admin'] = get_config('system','admin_email');
- $a = get_app();
-
$visible_plugins = array();
if(is_array(App::$plugins) && count(App::$plugins)) {
$r = q("select * from addon where hidden = 0");
@@ -3944,7 +3988,7 @@ function zotinfo($arr) {
$ret['site']['sellpage'] = get_config('system','sellpage');
$ret['site']['location'] = get_config('system','site_location');
$ret['site']['realm'] = get_directory_realm();
- $ret['site']['project'] = Zotlabs\Project\System::get_platform_name();
+ $ret['site']['project'] = Zotlabs\Lib\System::get_platform_name() . ' ' . Zotlabs\Lib\System::get_server_role();
}
@@ -4103,7 +4147,7 @@ function update_hub_connected($hub,$sitekey = '') {
$sitekey = $hub['sitekey'];
}
- // $sender['sitekey'] is a new addition to the protcol to distinguish
+ // $sender['sitekey'] is a new addition to the protocol to distinguish
// hublocs coming from re-installed sites. Older sites will not provide
// this field and we have to still mark them valid, since we can't tell
// if this hubloc has the same sitekey as the packet we received.
@@ -4112,10 +4156,13 @@ function update_hub_connected($hub,$sitekey = '') {
// Update our DB to show when we last communicated successfully with this hub
// This will allow us to prune dead hubs from using up resources
- $r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d and hubloc_sitekey = '%s' ",
+ $t = datetime_convert('UTC','UTC','now - 15 minutes');
+
+ $r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d and hubloc_sitekey = '%s' and hubloc_connected < '%s' ",
dbesc(datetime_convert()),
intval($hub['hubloc_id']),
- dbesc($sitekey)
+ dbesc($sitekey),
+ dbesc($t)
);
// a dead hub came back to life - reset any tombstones we might have
@@ -4415,7 +4462,6 @@ function zot_reply_purge($sender,$recipients) {
$arr = $sender;
$sender_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']);
- require_once('include/Contact.php');
remove_all_xchan_resources($sender_hash);
$ret['success'] = true;
diff --git a/index.php b/index.php
index 1178881ba..d47bda27e 100755
--- a/index.php
+++ b/index.php
@@ -1,182 +1,15 @@
run();
-// our global App object
-
-$a = new miniApp;
-
-App::init();
-
-/*
- * Load the configuration file which contains our DB credentials.
- * Ignore errors. If the file doesn't exist or is empty, we are running in
- * installation mode.
- */
-
-App::$install = ((file_exists('.htconfig.php') && filesize('.htconfig.php')) ? false : true);
-
-@include('.htconfig.php');
-
-if(! defined('UNO'))
- define('UNO', 0);
-
-$a->convert();
-
-App::$timezone = ((x($default_timezone)) ? $default_timezone : 'UTC');
-date_default_timezone_set(App::$timezone);
-
-
-/*
- * Try to open the database;
- */
-
-require_once('include/dba/dba_driver.php');
-
-if(! App::$install) {
- $db = dba_factory($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type, App::$install);
- if(! $db->connected) {
- system_unavailable();
- }
-
- unset($db_host, $db_port, $db_user, $db_pass, $db_data, $db_type);
-
- /**
- * Load configs from db. Overwrite configs from .htconfig.php
- */
-
- load_config('config');
- load_config('system');
- load_config('feature');
-
- \Zotlabs\Web\Session::init();
- load_hooks();
- call_hooks('init_1');
-
-}
-
-
- App::$language = get_best_language();
- load_translation_table(App::$language,App::$install);
-
-
-/**
- *
- * Important stuff we always need to do.
- *
- * The order of these may be important so use caution if you think they're all
- * intertwingled with no logical order and decide to sort it out. Some of the
- * dependencies have changed, but at least at one time in the recent past - the
- * order was critical to everything working properly
- *
- */
-
-\Zotlabs\Web\Session::start();
-
-/**
- * Language was set earlier, but we can over-ride it in the session.
- * We have to do it here because the session was just now opened.
- */
-
-if(array_key_exists('system_language',$_POST)) {
- if(strlen($_POST['system_language']))
- $_SESSION['language'] = $_POST['system_language'];
- else
- unset($_SESSION['language']);
-}
-if((x($_SESSION, 'language')) && ($_SESSION['language'] !== $lang)) {
- App::$language = $_SESSION['language'];
- load_translation_table(App::$language);
-}
-
-if((x($_GET,'zid')) && (! App::$install)) {
- App::$query_string = strip_zids(App::$query_string);
- if(! local_channel()) {
- $_SESSION['my_address'] = $_GET['zid'];
- zid_init($a);
- }
-}
-
-if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (App::$module === 'login'))
- require('include/auth.php');
-
-if(! x($_SESSION, 'sysmsg'))
- $_SESSION['sysmsg'] = array();
-
-if(! x($_SESSION, 'sysmsg_info'))
- $_SESSION['sysmsg_info'] = array();
-
-/*
- * check_config() is responsible for running update scripts. These automatically
- * update the DB schema whenever we push a new one out. It also checks to see if
- * any plugins have been added or removed and reacts accordingly.
- */
-
-
-if(App::$install) {
- /* Allow an exception for the view module so that pcss will be interpreted during installation */
- if(App::$module != 'view')
- App::$module = 'setup';
-}
-else
- check_config($a);
-
-nav_set_selected('nothing');
-
-$arr = array('app_menu' => App::get_apps());
-
-call_hooks('app_menu', $arr);
-
-App::set_apps($arr['app_menu']);
-
-$Router = new Zotlabs\Web\Router($a);
-
-/* initialise content region */
-
-if(! x(App::$page, 'content'))
- App::$page['content'] = '';
-
-call_hooks('page_content_top', App::$page['content']);
-
-
-$Router->Dispatch($a);
-
-
-// If you're just visiting, let javascript take you home
-
-if(x($_SESSION, 'visitor_home')) {
- $homebase = $_SESSION['visitor_home'];
-} elseif(local_channel()) {
- $homebase = z_root() . '/channel/' . App::$channel['channel_address'];
-}
-
-if(isset($homebase)) {
- App::$page['content'] .= '';
-}
-
-// now that we've been through the module content, see if the page reported
-// a permission problem and if so, a 403 response would seem to be in order.
-
-if(stristr(implode("", $_SESSION['sysmsg']), t('Permission denied'))) {
- header($_SERVER['SERVER_PROTOCOL'] . ' 403 ' . t('Permission denied.'));
-}
-
-
-call_hooks('page_end', App::$page['content']);
-
-construct_page($a);
-
-killme();
diff --git a/install/INSTALL.txt b/install/INSTALL.txt
index 18cf4a1db..670ad5af5 100644
--- a/install/INSTALL.txt
+++ b/install/INSTALL.txt
@@ -77,16 +77,15 @@ but may be an issue with nginx or other web server platforms.
Example config scripts are available for these platforms in doc/install.
Apache and nginx have the most support.
- - PHP 5.4 or later. The later the better.
+ - PHP 5.5 or later.
- PHP *command line* access with register_argc_argv set to true in the
php.ini file - and with no hosting provider restrictions on the use of
exec() and proc_open().
- - curl, gd (with at least jpeg and png support), mysqli, mbstring, mcrypt,
- and openssl extensions. The imagick extension is not required but desirable.
-
- - xml extension is required if you want webdav to work.
+ - curl, gd (with at least jpeg and png support), mysqli, mbstring, xml,
+ and openssl extensions. The imagick extension MAY be used instead of gd,
+ but is not required and MAY also be disabled via configuration option.
- some form of email server or email gateway such that PHP mail() works.
@@ -204,17 +203,17 @@ using web forms.
****************************************************************************
****************************************************************************
-8. Set up a cron job or scheduled task to run the poller once every 10-15
-minutes to pick up the recent "public" postings of your friends. Example:
+8. Set up a cron job or scheduled task to run the Cron manager once every 10-15
+minutes to perform background processing and maintenance. Example:
- cd /base/directory; /path/to/php include/poller.php
+ cd /base/directory; /path/to/php Zotlabs/Daemon/Master.php Cron
Change "/base/directory", and "/path/to/php" as appropriate for your situation.
If you are using a Linux server, run "crontab -e" and add a line like the
one shown, substituting for your unique paths and settings:
-*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php include/poller.php
+*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php Zotlabs/Daemon/Master.php Cron
You can generally find the location of PHP by executing "which php". If you
have troubles with this section please contact your hosting provider for
diff --git a/install/htconfig.sample.php b/install/htconfig.sample.php
index 5e506225e..c46805171 100755
--- a/install/htconfig.sample.php
+++ b/install/htconfig.sample.php
@@ -37,11 +37,11 @@ define( 'UNO', 0 );
// Choose a legal default timezone. If you are unsure, use "America/Los_Angeles".
// It can be changed later and only applies to timestamps for anonymous viewers.
-$default_timezone = 'America/Los_Angeles';
+App::$config['system']['timezone'] = 'America/Los_Angeles';
// What is your site name? DO NOT ADD A TRAILING SLASH!
-App::$config['system']['baseurl'] = 'https://myredsite.example';
+App::$config['system']['baseurl'] = 'https://mysite.example';
App::$config['system']['sitename'] = "Hubzilla";
App::$config['system']['location_hash'] = 'if the auto install failed, put a unique random string here';
diff --git a/install/schema_mysql.sql b/install/schema_mysql.sql
index 4751106da..a536c3f9a 100644
--- a/install/schema_mysql.sql
+++ b/install/schema_mysql.sql
@@ -96,15 +96,15 @@ CREATE TABLE IF NOT EXISTS `account` (
CREATE TABLE IF NOT EXISTS `addon` (
`id` int(11) NOT NULL AUTO_INCREMENT,
- `name` char(255) NOT NULL DEFAULT '',
+ `aname` char(255) NOT NULL DEFAULT '',
`version` char(255) NOT NULL DEFAULT '',
`installed` tinyint(1) NOT NULL DEFAULT '0',
`hidden` tinyint(1) NOT NULL DEFAULT '0',
- `timestamp` bigint(20) NOT NULL DEFAULT '0',
+ `tstamp` bigint(20) NOT NULL DEFAULT '0',
`plugin_admin` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `hidden` (`hidden`),
- KEY `name` (`name`),
+ KEY `aname` (`aname`),
KEY `installed` (`installed`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
@@ -158,7 +158,7 @@ CREATE TABLE IF NOT EXISTS `attach` (
`os_storage` tinyint(1) NOT NULL DEFAULT '0',
`os_path` mediumtext NOT NULL,
`display_path` mediumtext NOT NULL,
- `data` longblob NOT NULL,
+ `content` longblob NOT NULL,
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`edited` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`allow_cid` mediumtext NOT NULL,
@@ -188,7 +188,7 @@ CREATE TABLE IF NOT EXISTS `auth_codes` (
`client_id` varchar(20) NOT NULL DEFAULT '',
`redirect_uri` varchar(200) NOT NULL DEFAULT '',
`expires` int(11) NOT NULL DEFAULT '0',
- `scope` varchar(250) NOT NULL DEFAULT '',
+ `auth_scope` varchar(512) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
@@ -342,7 +342,7 @@ CREATE TABLE IF NOT EXISTS `clients` (
`client_id` varchar(20) NOT NULL DEFAULT '',
`pw` varchar(20) NOT NULL DEFAULT '',
`redirect_uri` varchar(200) NOT NULL DEFAULT '',
- `name` text,
+ `clname` text,
`icon` text,
`uid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`client_id`)
@@ -398,15 +398,15 @@ CREATE TABLE IF NOT EXISTS `event` (
`event_hash` char(255) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`edited` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
- `start` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
- `finish` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `dtstart` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `dtend` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`summary` text NOT NULL,
`description` text NOT NULL,
`location` text NOT NULL,
- `type` char(255) NOT NULL DEFAULT '',
+ `etype` char(255) NOT NULL DEFAULT '',
`nofinish` tinyint(1) NOT NULL DEFAULT '0',
`adjust` tinyint(1) NOT NULL DEFAULT '1',
- `ignore` tinyint(1) NOT NULL DEFAULT '0',
+ `dismissed` tinyint(1) NOT NULL DEFAULT '0',
`allow_cid` mediumtext NOT NULL,
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
@@ -420,12 +420,12 @@ CREATE TABLE IF NOT EXISTS `event` (
`event_vdata` text NOT NULL,
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
- KEY `type` (`type`),
- KEY `start` (`start`),
- KEY `finish` (`finish`),
+ KEY `etype` (`etype`),
+ KEY `dtstart` (`dtstart`),
+ KEY `dtend` (`dtend`),
KEY `adjust` (`adjust`),
KEY `nofinish` (`nofinish`),
- KEY `ignore` (`ignore`),
+ KEY `dismissed` (`dismissed`),
KEY `aid` (`aid`),
KEY `event_hash` (`event_hash`),
KEY `event_xchan` (`event_xchan`),
@@ -434,74 +434,19 @@ CREATE TABLE IF NOT EXISTS `event` (
KEY `event_priority` (`event_priority`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-CREATE TABLE IF NOT EXISTS `fcontact` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `url` char(255) NOT NULL,
- `name` char(255) NOT NULL,
- `photo` char(255) NOT NULL,
- `request` char(255) NOT NULL,
- `nick` char(255) NOT NULL,
- `addr` char(255) NOT NULL,
- `batch` char(255) NOT NULL,
- `notify` char(255) NOT NULL,
- `poll` char(255) NOT NULL,
- `confirm` char(255) NOT NULL,
- `priority` tinyint(1) NOT NULL,
- `network` char(32) NOT NULL,
- `alias` char(255) NOT NULL,
- `pubkey` text NOT NULL,
- `updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
- PRIMARY KEY (`id`),
- KEY `addr` (`addr`),
- KEY `network` (`network`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-CREATE TABLE IF NOT EXISTS `ffinder` (
- `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
- `uid` int(10) unsigned NOT NULL,
- `cid` int(10) unsigned NOT NULL,
- `fid` int(10) unsigned NOT NULL,
- PRIMARY KEY (`id`),
- KEY `uid` (`uid`),
- KEY `cid` (`cid`),
- KEY `fid` (`fid`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-CREATE TABLE IF NOT EXISTS `fserver` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `server` char(255) NOT NULL DEFAULT '',
- `posturl` char(255) NOT NULL DEFAULT '',
- `key` text NOT NULL,
- PRIMARY KEY (`id`),
- KEY `server` (`server`),
- KEY `posturl` (`posturl`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-CREATE TABLE IF NOT EXISTS `fsuggest` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `uid` int(11) NOT NULL DEFAULT '0',
- `cid` int(11) NOT NULL DEFAULT '0',
- `name` char(255) NOT NULL DEFAULT '',
- `url` char(255) NOT NULL DEFAULT '',
- `request` char(255) NOT NULL DEFAULT '',
- `photo` char(255) NOT NULL DEFAULT '',
- `note` text NOT NULL,
- `created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
- PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
CREATE TABLE IF NOT EXISTS `groups` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`hash` char(255) NOT NULL DEFAULT '',
`uid` int(10) unsigned NOT NULL DEFAULT '0',
`visible` tinyint(1) NOT NULL DEFAULT '0',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
- `name` char(255) NOT NULL DEFAULT '',
+ `gname` char(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
KEY `visible` (`visible`),
KEY `deleted` (`deleted`),
- KEY `hash` (`hash`)
+ KEY `hash` (`hash`),
+ KEY `gname` (`gname`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `group_member` (
@@ -519,7 +464,7 @@ CREATE TABLE IF NOT EXISTS `hook` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hook` char(255) NOT NULL DEFAULT '',
`file` char(255) NOT NULL DEFAULT '',
- `function` char(255) NOT NULL DEFAULT '',
+ `fn` char(255) NOT NULL DEFAULT '',
`priority` int(11) unsigned NOT NULL DEFAULT '0',
`hook_version` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
@@ -624,7 +569,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`revision` int(10) unsigned NOT NULL DEFAULT '0',
`verb` char(255) NOT NULL DEFAULT '',
`obj_type` char(255) NOT NULL DEFAULT '',
- `object` text NOT NULL,
+ `obj` text NOT NULL,
`tgt_type` char(255) NOT NULL DEFAULT '',
`target` text NOT NULL,
`layout_mid` char(255) NOT NULL DEFAULT '',
@@ -846,24 +791,24 @@ CREATE TABLE IF NOT EXISTS `menu_item` (
CREATE TABLE IF NOT EXISTS `notify` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`hash` char(64) NOT NULL DEFAULT '',
- `name` char(255) NOT NULL DEFAULT '',
+ `xname` char(255) NOT NULL DEFAULT '',
`url` char(255) NOT NULL DEFAULT '',
`photo` char(255) NOT NULL DEFAULT '',
- `date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`msg` mediumtext NOT NULL,
`aid` int(11) NOT NULL DEFAULT '0',
`uid` int(11) NOT NULL DEFAULT '0',
`link` char(255) NOT NULL DEFAULT '',
`parent` char(255) NOT NULL DEFAULT '',
`seen` tinyint(1) NOT NULL DEFAULT '0',
- `type` int(11) NOT NULL DEFAULT '0',
+ `ntype` int(11) NOT NULL DEFAULT '0',
`verb` char(255) NOT NULL DEFAULT '',
`otype` char(16) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
- KEY `type` (`type`),
+ KEY `ntype` (`ntype`),
KEY `seen` (`seen`),
KEY `uid` (`uid`),
- KEY `date` (`date`),
+ KEY `created` (`created`),
KEY `hash` (`hash`),
KEY `parent` (`parent`),
KEY `link` (`link`),
@@ -883,6 +828,7 @@ CREATE TABLE IF NOT EXISTS `obj` (
`obj_imgurl` char(255) NOT NULL DEFAULT '',
`obj_created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`obj_edited` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+ `obj_quantity` int(11) NOT NULL DEFAULT '0',
`allow_cid` mediumtext NOT NULL,
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
@@ -897,6 +843,7 @@ CREATE TABLE IF NOT EXISTS `obj` (
KEY `obj_imgurl` (`obj_imgurl`),
KEY `obj_created` (`obj_created`),
KEY `obj_edited` (`obj_edited`),
+ KEY `obj_quantity` (`obj_quantity`),
KEY `obj_obj` (`obj_obj`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
@@ -946,12 +893,12 @@ CREATE TABLE IF NOT EXISTS `photo` (
`description` text NOT NULL,
`album` char(255) NOT NULL DEFAULT '',
`filename` char(255) NOT NULL DEFAULT '',
- `type` char(128) NOT NULL DEFAULT 'image/jpeg',
+ `mimetype` char(128) NOT NULL DEFAULT 'image/jpeg',
`height` smallint(6) NOT NULL DEFAULT '0',
`width` smallint(6) NOT NULL DEFAULT '0',
- `size` int(10) unsigned NOT NULL DEFAULT '0',
- `data` mediumblob NOT NULL,
- `scale` tinyint(3) NOT NULL DEFAULT '0',
+ `filesize` int(10) unsigned NOT NULL DEFAULT '0',
+ `content` mediumblob NOT NULL,
+ `imgscale` tinyint(3) NOT NULL DEFAULT '0',
`photo_usage` smallint(6) NOT NULL DEFAULT '0',
`profile` tinyint(1) NOT NULL DEFAULT '0',
`is_nsfw` tinyint(1) NOT NULL DEFAULT '0',
@@ -966,13 +913,13 @@ CREATE TABLE IF NOT EXISTS `photo` (
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
KEY `album` (`album`),
- KEY `scale` (`scale`),
+ KEY `imgscale` (`imgscale`),
KEY `profile` (`profile`),
KEY `photo_flags` (`photo_flags`),
- KEY `type` (`type`),
+ KEY `mimetype` (`mimetype`),
KEY `aid` (`aid`),
KEY `xchan` (`xchan`),
- KEY `size` (`size`),
+ KEY `filesize` (`filesize`),
KEY `resource_id` (`resource_id`),
KEY `is_nsfw` (`is_nsfw`),
KEY `os_storage` (`os_storage`),
@@ -1033,7 +980,7 @@ CREATE TABLE IF NOT EXISTS `profile` (
`profile_name` char(255) NOT NULL DEFAULT '',
`is_default` tinyint(1) NOT NULL DEFAULT '0',
`hide_friends` tinyint(1) NOT NULL DEFAULT '0',
- `name` char(255) NOT NULL DEFAULT '',
+ `fullname` char(255) NOT NULL DEFAULT '',
`pdesc` char(255) NOT NULL DEFAULT '',
`chandesc` text NOT NULL,
`dob` char(32) NOT NULL DEFAULT '0000-00-00',
@@ -1046,7 +993,7 @@ CREATE TABLE IF NOT EXISTS `profile` (
`hometown` char(255) NOT NULL DEFAULT '',
`gender` char(32) NOT NULL DEFAULT '',
`marital` char(255) NOT NULL DEFAULT '',
- `with` text NOT NULL,
+ `partner` text NOT NULL,
`howlong` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`sexual` char(255) NOT NULL DEFAULT '',
`politic` char(255) NOT NULL DEFAULT '',
@@ -1062,7 +1009,7 @@ CREATE TABLE IF NOT EXISTS `profile` (
`film` text NOT NULL,
`interest` text NOT NULL,
`romance` text NOT NULL,
- `work` text NOT NULL,
+ `employment` text NOT NULL,
`education` text NOT NULL,
`contact` text NOT NULL,
`channels` text NOT NULL,
@@ -1108,7 +1055,7 @@ CREATE TABLE IF NOT EXISTS `register` (
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`uid` int(10) unsigned NOT NULL DEFAULT '0',
`password` char(255) NOT NULL DEFAULT '',
- `language` char(16) NOT NULL DEFAULT '',
+ `lang` char(16) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `hash` (`hash`),
KEY `created` (`created`),
@@ -1118,7 +1065,7 @@ CREATE TABLE IF NOT EXISTS `register` (
CREATE TABLE IF NOT EXISTS `session` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`sid` char(255) NOT NULL DEFAULT '',
- `data` text NOT NULL,
+ `sess_data` text NOT NULL,
`expire` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `sid` (`sid`),
@@ -1192,20 +1139,6 @@ CREATE TABLE IF NOT EXISTS `source` (
KEY `src_xchan` (`src_xchan`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-CREATE TABLE IF NOT EXISTS `spam` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `uid` int(11) NOT NULL DEFAULT '0',
- `spam` int(11) NOT NULL DEFAULT '0',
- `ham` int(11) NOT NULL DEFAULT '0',
- `term` char(255) NOT NULL DEFAULT '',
- `date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
- PRIMARY KEY (`id`),
- KEY `uid` (`uid`),
- KEY `spam` (`spam`),
- KEY `ham` (`ham`),
- KEY `term` (`term`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
CREATE TABLE IF NOT EXISTS `sys_perms` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cat` char(255) NOT NULL DEFAULT '',
@@ -1221,7 +1154,7 @@ CREATE TABLE IF NOT EXISTS `term` (
`uid` int(10) unsigned NOT NULL DEFAULT '0',
`oid` int(10) unsigned NOT NULL DEFAULT '0',
`otype` tinyint(3) unsigned NOT NULL DEFAULT '0',
- `type` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `ttype` tinyint(3) unsigned NOT NULL DEFAULT '0',
`term` char(255) NOT NULL DEFAULT '',
`url` char(255) NOT NULL DEFAULT '',
`imgurl` char(255) NOT NULL DEFAULT '',
@@ -1230,7 +1163,7 @@ CREATE TABLE IF NOT EXISTS `term` (
PRIMARY KEY (`tid`),
KEY `oid` (`oid`),
KEY `otype` (`otype`),
- KEY `type` (`type`),
+ KEY `ttype` (`ttype`),
KEY `term` (`term`),
KEY `uid` (`uid`),
KEY `aid` (`aid`),
@@ -1244,7 +1177,7 @@ CREATE TABLE IF NOT EXISTS `tokens` (
`secret` text NOT NULL,
`client_id` varchar(20) NOT NULL DEFAULT '',
`expires` bigint(20) unsigned NOT NULL DEFAULT '0',
- `scope` varchar(200) NOT NULL DEFAULT '',
+ `auth_scope` varchar(512) NOT NULL DEFAULT '',
`uid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `client_id` (`client_id`),
@@ -1272,13 +1205,13 @@ CREATE TABLE IF NOT EXISTS `updates` (
CREATE TABLE IF NOT EXISTS `verify` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`channel` int(10) unsigned NOT NULL DEFAULT '0',
- `type` char(32) NOT NULL DEFAULT '',
+ `vtype` char(32) NOT NULL DEFAULT '',
`token` char(255) NOT NULL DEFAULT '',
`meta` char(255) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `channel` (`channel`),
- KEY `type` (`type`),
+ KEY `vtype` (`vtype`),
KEY `token` (`token`),
KEY `meta` (`meta`),
KEY `created` (`created`)
diff --git a/install/schema_postgres.sql b/install/schema_postgres.sql
index 75e53d3dd..b637fea43 100644
--- a/install/schema_postgres.sql
+++ b/install/schema_postgres.sql
@@ -94,16 +94,16 @@ create index "account_level" on account ("account_level");
create index "account_password_changed" on account ("account_password_changed");
CREATE TABLE "addon" (
"id" serial NOT NULL,
- "name" text NOT NULL,
+ "aname" text NOT NULL,
"version" text NOT NULL DEFAULT '0',
"installed" numeric(1) NOT NULL DEFAULT '0',
"hidden" numeric(1) NOT NULL DEFAULT '0',
- "timestamp" numeric(20) NOT NULL DEFAULT '0',
+ "tstamp" numeric(20) NOT NULL DEFAULT '0',
"plugin_admin" numeric(1) NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
);
create index "addon_hidden_idx" on addon ("hidden");
-create index "addon_name_idx" on addon ("name");
+create index "addon_name_idx" on addon ("aname");
create index "addon_installed_idx" on addon ("installed");
CREATE TABLE "app" (
"id" serial NOT NULL,
@@ -154,7 +154,7 @@ CREATE TABLE "attach" (
"os_storage" smallint NOT NULL DEFAULT '0',
"os_path" text NOT NULL,
"display_path" text NOT NULL,
- "data" bytea NOT NULL,
+ "content" bytea NOT NULL,
"created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
"edited" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
"allow_cid" text NOT NULL,
@@ -184,7 +184,7 @@ CREATE TABLE "auth_codes" (
"client_id" varchar(20) NOT NULL,
"redirect_uri" varchar(200) NOT NULL,
"expires" bigint NOT NULL,
- "scope" varchar(250) NOT NULL,
+ "auth_scope" varchar(512) NOT NULL,
PRIMARY KEY ("id")
);
CREATE TABLE "cache" (
@@ -333,7 +333,7 @@ CREATE TABLE "clients" (
"client_id" varchar(20) NOT NULL,
"pw" varchar(20) NOT NULL,
"redirect_uri" varchar(200) NOT NULL,
- "name" text,
+ "clname" text,
"icon" text,
"uid" bigint NOT NULL DEFAULT '0',
PRIMARY KEY ("client_id")
@@ -390,17 +390,17 @@ CREATE TABLE "event" (
"uid" bigint NOT NULL,
"event_xchan" text NOT NULL DEFAULT '',
"event_hash" text NOT NULL DEFAULT '',
- "created" timestamp NOT NULL,
- "edited" timestamp NOT NULL,
- "start" timestamp NOT NULL,
- "finish" timestamp NOT NULL,
+ "created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
+ "edited" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
+ "dtstart" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
+ "dtend" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
"summary" text NOT NULL,
"description" text NOT NULL,
"location" text NOT NULL,
- "type" text NOT NULL,
+ "etype" text NOT NULL,
"nofinish" numeric(1) NOT NULL DEFAULT '0',
"adjust" numeric(1) NOT NULL DEFAULT '1',
- "ignore" numeric(1) NOT NULL DEFAULT '0',
+ "dismissed" numeric(1) NOT NULL DEFAULT '0',
"allow_cid" text NOT NULL,
"allow_gid" text NOT NULL,
"deny_cid" text NOT NULL,
@@ -415,12 +415,12 @@ CREATE TABLE "event" (
PRIMARY KEY ("id")
);
create index "event_uid_idx" on event ("uid");
-create index "event_type_idx" on event ("type");
-create index "event_start_idx" on event ("start");
-create index "event_finish_idx" on event ("finish");
+create index "event_etype_idx" on event ("etype");
+create index "event_dtstart_idx" on event ("dtstart");
+create index "event_dtend_idx" on event ("dtend");
create index "event_adjust_idx" on event ("adjust");
create index "event_nofinish_idx" on event ("nofinish");
-create index "event_ignore_idx" on event ("ignore");
+create index "event_dismissed_idx" on event ("dismissed");
create index "event_aid_idx" on event ("aid");
create index "event_hash_idx" on event ("event_hash");
create index "event_xchan_idx" on event ("event_xchan");
@@ -428,62 +428,6 @@ create index "event_status_idx" on event ("event_status");
create index "event_sequence_idx" on event ("event_sequence");
create index "event_priority_idx" on event ("event_priority");
-
-CREATE TABLE "fcontact" (
- "id" serial NOT NULL,
- "url" text NOT NULL,
- "name" text NOT NULL,
- "photo" text NOT NULL,
- "request" text NOT NULL,
- "nick" text NOT NULL,
- "addr" text NOT NULL,
- "batch" text NOT NULL,
- "notify" text NOT NULL,
- "poll" text NOT NULL,
- "confirm" text NOT NULL,
- "priority" numeric(1) NOT NULL,
- "network" varchar(32) NOT NULL DEFAULT '',
- "alias" text NOT NULL,
- "pubkey" text NOT NULL,
- "updated" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
- PRIMARY KEY ("id")
-);
-create index "fcontact_addr_idx" on fcontact ("addr");
-create index "fcontact_network_idx" on fcontact ("network");
-
-CREATE TABLE "ffinder" (
- "id" serial NOT NULL,
- "uid" bigint NOT NULL,
- "cid" bigint NOT NULL,
- "fid" bigint NOT NULL,
- PRIMARY KEY ("id")
-);
-create index "ffinder_uid_idx" on ffinder ("uid");
-create index "ffinder_cid_idx" on ffinder ("cid");
-create index "ffinder_fid_idx" on ffinder ("fid");
-
-CREATE TABLE "fserver" (
- "id" serial NOT NULL,
- "server" text NOT NULL,
- "posturl" text NOT NULL,
- "key" text NOT NULL,
- PRIMARY KEY ("id")
-);
-create index "fserver_server_idx" on fserver ("server");
-create index "fserver_posturl_idx" on fserver ("posturl");
-
-CREATE TABLE "fsuggest" (
- "id" serial NOT NULL,
- "uid" bigint NOT NULL,
- "cid" bigint NOT NULL,
- "name" text NOT NULL,
- "url" text NOT NULL,
- "request" text NOT NULL,
- "photo" text NOT NULL,
- "note" text NOT NULL,
- "created" timestamp NOT NULL,
- PRIMARY KEY ("id")
-);
CREATE TABLE "group_member" (
"id" serial NOT NULL,
"uid" bigint NOT NULL,
@@ -501,7 +445,7 @@ CREATE TABLE "groups" (
"uid" bigint NOT NULL,
"visible" numeric(1) NOT NULL DEFAULT '0',
"deleted" numeric(1) NOT NULL DEFAULT '0',
- "name" text NOT NULL,
+ "gname" text NOT NULL,
PRIMARY KEY ("id")
);
@@ -514,7 +458,7 @@ CREATE TABLE "hook" (
"id" serial NOT NULL,
"hook" text NOT NULL,
"file" text NOT NULL,
- "function" text NOT NULL,
+ "fn" text NOT NULL,
"priority" bigint NOT NULL DEFAULT '0',
"hook_version" smallint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
@@ -616,7 +560,7 @@ CREATE TABLE "item" (
"revision" bigint NOT NULL DEFAULT '0',
"verb" text NOT NULL DEFAULT '',
"obj_type" text NOT NULL DEFAULT '',
- "object" text NOT NULL,
+ "obj" text NOT NULL,
"tgt_type" text NOT NULL DEFAULT '',
"target" text NOT NULL,
"layout_mid" text NOT NULL DEFAULT '',
@@ -837,25 +781,25 @@ create index "mitem_flags" on menu_item ("mitem_flags");
CREATE TABLE "notify" (
"id" serial NOT NULL,
"hash" char(64) NOT NULL,
- "name" text NOT NULL,
+ "xname" text NOT NULL,
"url" text NOT NULL,
"photo" text NOT NULL,
- "date" timestamp NOT NULL,
+ "created" timestamp NOT NULL,
"msg" text NOT NULL DEFAULT '',
"aid" bigint NOT NULL,
"uid" bigint NOT NULL,
"link" text NOT NULL,
"parent" text NOT NULL DEFAULT '',
"seen" numeric(1) NOT NULL DEFAULT '0',
- "type" bigint NOT NULL,
+ "ntype" bigint NOT NULL,
"verb" text NOT NULL,
"otype" varchar(16) NOT NULL,
PRIMARY KEY ("id")
);
-create index "notify_type" on notify ("type");
+create index "notify_ntype" on notify ("ntype");
create index "notify_seen" on notify ("seen");
create index "notify_uid" on notify ("uid");
-create index "notify_date" on notify ("date");
+create index "notify_created" on notify ("created");
create index "notify_hash" on notify ("hash");
create index "notify_parent" on notify ("parent");
create index "notify_link" on notify ("link");
@@ -873,6 +817,7 @@ CREATE TABLE "obj" (
"obj_imgurl" char(255) NOT NULL DEFAULT '',
"obj_created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
"obj_edited" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
+ "obj_quantity" int(11) NOT NULL DEFAUL '0'.
"allow_cid" text NOT NULL,
"allow_gid" text NOT NULL,
"deny_cid" text NOT NULL,
@@ -890,6 +835,7 @@ create index "obj_url" on obj ("obj_url");
create index "obj_imgurl" on obj ("obj_imgurl");
create index "obj_created" on obj ("obj_created");
create index "obj_edited" on obj ("obj_edited");
+create index "obj_quantity" on obj ("obj_quantity");
CREATE TABLE "outq" (
"outq_hash" text NOT NULL,
@@ -936,12 +882,12 @@ CREATE TABLE "photo" (
"description" text NOT NULL,
"album" text NOT NULL,
"filename" text NOT NULL,
- "type" varchar(128) NOT NULL DEFAULT 'image/jpeg',
+ "mimetype" varchar(128) NOT NULL DEFAULT 'image/jpeg',
"height" numeric(6) NOT NULL,
"width" numeric(6) NOT NULL,
- "size" bigint NOT NULL DEFAULT '0',
- "data" bytea NOT NULL,
- "scale" numeric(3) NOT NULL,
+ "filesize" bigint NOT NULL DEFAULT '0',
+ "content" bytea NOT NULL,
+ "imgscale" numeric(3) NOT NULL DEFAULT '0',
"profile" numeric(1) NOT NULL DEFAULT '0',
"photo_usage" smallint NOT NULL DEFAULT '0',
"is_nsfw" smallint NOT NULL DEFAULT '0',
@@ -957,13 +903,13 @@ CREATE TABLE "photo" (
);
create index "photo_uid" on photo ("uid");
create index "photo_album" on photo ("album");
-create index "photo_scale" on photo ("scale");
+create index "photo_imgscale" on photo ("imgscale");
create index "photo_profile" on photo ("profile");
create index "photo_flags" on photo ("photo_flags");
create index "photo_type" on photo ("type");
create index "photo_aid" on photo ("aid");
create index "photo_xchan" on photo ("xchan");
-create index "photo_size" on photo ("size");
+create index "photo_filesize" on photo ("filesize");
create index "photo_resource_id" on photo ("resource_id");
create index "photo_usage" on photo ("photo_usage");
create index "photo_is_nsfw" on photo ("is_nsfw");
@@ -1022,7 +968,7 @@ CREATE TABLE "profile" (
"profile_name" text NOT NULL,
"is_default" numeric(1) NOT NULL DEFAULT '0',
"hide_friends" numeric(1) NOT NULL DEFAULT '0',
- "name" text NOT NULL,
+ "fullname" text NOT NULL,
"pdesc" text NOT NULL DEFAULT '',
"chandesc" text NOT NULL DEFAULT '',
"dob" varchar(32) NOT NULL DEFAULT '',
@@ -1035,7 +981,7 @@ CREATE TABLE "profile" (
"hometown" text NOT NULL DEFAULT '',
"gender" varchar(32) NOT NULL DEFAULT '',
"marital" text NOT NULL DEFAULT '',
- "with" text NOT NULL DEFAULT '',
+ "partner" text NOT NULL DEFAULT '',
"howlong" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
"sexual" text NOT NULL DEFAULT '',
"politic" text NOT NULL DEFAULT '',
@@ -1051,7 +997,7 @@ CREATE TABLE "profile" (
"film" text NOT NULL DEFAULT '',
"interest" text NOT NULL DEFAULT '',
"romance" text NOT NULL DEFAULT '',
- "work" text NOT NULL DEFAULT '',
+ "employment" text NOT NULL DEFAULT '',
"education" text NOT NULL DEFAULT '',
"contact" text NOT NULL DEFAULT '',
"channels" text NOT NULL DEFAULT '',
@@ -1097,7 +1043,7 @@ CREATE TABLE "register" (
"created" timestamp NOT NULL,
"uid" bigint NOT NULL,
"password" text NOT NULL,
- "language" varchar(16) NOT NULL,
+ "lang" varchar(16) NOT NULL,
PRIMARY KEY ("id")
);
create index "reg_hash" on register ("hash");
@@ -1106,7 +1052,7 @@ create index "reg_uid" on register ("uid");
CREATE TABLE "session" (
"id" serial,
"sid" text NOT NULL,
- "data" text NOT NULL,
+ "sess_data" text NOT NULL,
"expire" numeric(20) NOT NULL,
PRIMARY KEY ("id")
);
@@ -1177,19 +1123,6 @@ CREATE TABLE "source" (
create index "src_channel_id" on "source" ("src_channel_id");
create index "src_channel_xchan" on "source" ("src_channel_xchan");
create index "src_xchan" on "source" ("src_xchan");
-CREATE TABLE "spam" (
- "id" serial NOT NULL,
- "uid" bigint NOT NULL,
- "spam" bigint NOT NULL DEFAULT '0',
- "ham" bigint NOT NULL DEFAULT '0',
- "term" text NOT NULL,
- "date" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
- PRIMARY KEY ("id")
-);
-create index "spam_uid" on spam ("uid");
-create index "spam_spam" on spam ("spam");
-create index "spam_ham" on spam ("ham");
-create index "spam_term" on spam ("term");
CREATE TABLE "sys_perms" (
"id" serial NOT NULL,
"cat" text NOT NULL,
@@ -1204,7 +1137,7 @@ CREATE TABLE "term" (
"uid" bigint NOT NULL DEFAULT '0',
"oid" bigint NOT NULL,
"otype" numeric(3) NOT NULL,
- "type" numeric(3) NOT NULL,
+ "ttype" numeric(3) NOT NULL,
"term" text NOT NULL,
"url" text NOT NULL,
"imgurl" text NOT NULL DEFAULT '',
@@ -1214,7 +1147,7 @@ CREATE TABLE "term" (
);
create index "term_oid" on term ("oid");
create index "term_otype" on term ("otype");
-create index "term_type" on term ("type");
+create index "term_ttype" on term ("ttype");
create index "term_term" on term ("term");
create index "term_uid" on term ("uid");
create index "term_aid" on term ("aid");
@@ -1226,7 +1159,7 @@ CREATE TABLE "tokens" (
"secret" text NOT NULL,
"client_id" varchar(20) NOT NULL,
"expires" numeric(20) NOT NULL,
- "scope" varchar(200) NOT NULL,
+ "auth_scope" varchar(512) NOT NULL,
"uid" bigint NOT NULL,
PRIMARY KEY ("id")
);
@@ -1253,14 +1186,14 @@ create index "ud_last" on updates ("ud_last");
CREATE TABLE "verify" (
"id" serial NOT NULL,
"channel" bigint NOT NULL DEFAULT '0',
- "type" varchar(32) NOT NULL DEFAULT '',
+ "vtype" varchar(32) NOT NULL DEFAULT '',
"token" text NOT NULL DEFAULT '',
"meta" text NOT NULL DEFAULT '',
"created" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
PRIMARY KEY ("id")
);
create index "verify_channel" on verify ("channel");
-create index "verify_type" on verify ("type");
+create index "verify_vtype" on verify ("vtype");
create index "verify_token" on verify ("token");
create index "verify_meta" on verify ("meta");
create index "verify_created" on verify ("created");
diff --git a/install/update.php b/install/update.php
index ea1bd8bc7..908f60498 100644
--- a/install/update.php
+++ b/install/update.php
@@ -1,6 +1,6 @@
1&&u(t,"")>-1&&(a=RegExp(this.source,r.replace.call(o(this),"g","")),r.replace.call(e.slice(t.index),a,function(){for(var e=1;et.index&&this.lastIndex--}return t},s||(RegExp.prototype.test=function(e){var t=r.exec.call(this,e);return t&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--,!!t})}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+ta)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n=0?parseFloat((i.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]):parseFloat((i.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]),t.isOldIE=t.isIE&&t.isIE<9,t.isGecko=t.isMozilla=(window.Controllers||window.controllers)&&window.navigator.product==="Gecko",t.isOldGecko=t.isGecko&&parseInt((i.match(/rv\:(\d+)/)||[])[1],10)<4,t.isOpera=window.opera&&Object.prototype.toString.call(window.opera)=="[object Opera]",t.isWebKit=parseFloat(i.split("WebKit/")[1])||undefined,t.isChrome=parseFloat(i.split(" Chrome/")[1])||undefined,t.isAIR=i.indexOf("AdobeAIR")>=0,t.isIPad=i.indexOf("iPad")>=0,t.isTouchPad=i.indexOf("TouchPad")>=0,t.isChromeOS=i.indexOf(" CrOS ")>=0}),ace.define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function a(e,t,n){var a=u(t);if(!i.isMac&&s){s.OSKey&&(a|=8);if(s.altGr){if((3&a)==3)return;s.altGr=0}if(n===18||n===17){var f="location"in t?t.location:t.keyLocation;if(n===17&&f===1)s[n]==1&&(o=t.timeStamp);else if(n===18&&a===3&&f===2){var l=t.timeStamp-o;l<50&&(s.altGr=!0)}}}n in r.MODIFIER_KEYS&&(n=-1),a&8&&n>=91&&n<=93&&(n=-1);if(!a&&n===13){var f="location"in t?t.location:t.keyLocation;if(f===3){e(t,a,-n);if(t.defaultPrevented)return}}if(i.isChromeOS&&a&8){e(t,a,n);if(t.defaultPrevented)return;a&=-9}return!!a||n in r.FUNCTION_KEYS||n in r.PRINTABLE_KEYS?e(t,a,n):!1}function f(){s=Object.create(null),s.count=0,s.lastT=0}var r=e("./keys"),i=e("./useragent"),s=null,o=0;t.addListener=function(e,t,n){if(e.addEventListener)return e.addEventListener(t,n,!1);if(e.attachEvent){var r=function(){n.call(e,window.event)};n._wrapper=r,e.attachEvent("on"+t,r)}},t.removeListener=function(e,t,n){if(e.removeEventListener)return e.removeEventListener(t,n,!1);e.detachEvent&&e.detachEvent("on"+t,n._wrapper||n)},t.stopEvent=function(e){return t.stopPropagation(e),t.preventDefault(e),!1},t.stopPropagation=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},t.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},t.getButton=function(e){return e.type=="dblclick"?0:e.type=="contextmenu"||i.isMac&&e.ctrlKey&&!e.altKey&&!e.shiftKey?2:e.preventDefault?e.button:{1:0,2:2,4:1}[e.button]},t.capture=function(e,n,r){function i(e){n&&n(e),r&&r(e),t.removeListener(document,"mousemove",n,!0),t.removeListener(document,"mouseup",i,!0),t.removeListener(document,"dragstart",i,!0)}return t.addListener(document,"mousemove",n,!0),t.addListener(document,"mouseup",i,!0),t.addListener(document,"dragstart",i,!0),i},t.addTouchMoveListener=function(e,n){if("ontouchmove"in e){var r,i;t.addListener(e,"touchstart",function(e){var t=e.changedTouches[0];r=t.clientX,i=t.clientY}),t.addListener(e,"touchmove",function(e){var t=1,s=e.changedTouches[0];e.wheelX=-(s.clientX-r)/t,e.wheelY=-(s.clientY-i)/t,r=s.clientX,i=s.clientY,n(e)})}},t.addMouseWheelListener=function(e,n){"onmousewheel"in e?t.addListener(e,"mousewheel",function(e){var t=8;e.wheelDeltaX!==undefined?(e.wheelX=-e.wheelDeltaX/t,e.wheelY=-e.wheelDeltaY/t):(e.wheelX=0,e.wheelY=-e.wheelDelta/t),n(e)}):"onwheel"in e?t.addListener(e,"wheel",function(e){var t=.35;switch(e.deltaMode){case e.DOM_DELTA_PIXEL:e.wheelX=e.deltaX*t||0,e.wheelY=e.deltaY*t||0;break;case e.DOM_DELTA_LINE:case e.DOM_DELTA_PAGE:e.wheelX=(e.deltaX||0)*5,e.wheelY=(e.deltaY||0)*5}n(e)}):t.addListener(e,"DOMMouseScroll",function(e){e.axis&&e.axis==e.HORIZONTAL_AXIS?(e.wheelX=(e.detail||0)*5,e.wheelY=0):(e.wheelX=0,e.wheelY=(e.detail||0)*5),n(e)})},t.addMultiMouseDownListener=function(e,n,r,s){function c(e){t.getButton(e)!==0?o=0:e.detail>1?(o++,o>4&&(o=1)):o=1;if(i.isIE){var c=Math.abs(e.clientX-u)>5||Math.abs(e.clientY-a)>5;if(!f||c)o=1;f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),o==1&&(u=e.clientX,a=e.clientY)}e._clicks=o,r[s]("mousedown",e);if(o>4)o=0;else if(o>1)return r[s](l[o],e)}function h(e){o=2,f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),r[s]("mousedown",e),r[s](l[o],e)}var o=0,u,a,f,l={2:"dblclick",3:"tripleclick",4:"quadclick"};Array.isArray(e)||(e=[e]),e.forEach(function(e){t.addListener(e,"mousedown",c),i.isOldIE&&t.addListener(e,"dblclick",h)})};var u=!i.isMac||!i.isOpera||"KeyboardEvent"in window?function(e){return 0|(e.ctrlKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.metaKey?8:0)}:function(e){return 0|(e.metaKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.ctrlKey?8:0)};t.getModifierString=function(e){return r.KEY_MODS[u(e)]},t.addCommandKeyListener=function(e,n){var r=t.addListener;if(i.isOldGecko||i.isOpera&&!("KeyboardEvent"in window)){var o=null;r(e,"keydown",function(e){o=e.keyCode}),r(e,"keypress",function(e){return a(n,e,o)})}else{var u=null;r(e,"keydown",function(e){var t=e.keyCode;s[t]=(s[t]||0)+1,t==91||t==92?s.OSKey=!0:s.OSKey&&e.timeStamp-s.lastT>200&&s.count==1&&f(),s[t]==1&&s.count++,s.lastT=e.timeStamp;var r=a(n,e,t);return u=e.defaultPrevented,r}),r(e,"keypress",function(e){u&&(e.ctrlKey||e.altKey||e.shiftKey||e.metaKey)&&(t.stopEvent(e),u=null)}),r(e,"keyup",function(e){var t=e.keyCode;s[t]?s.count=Math.max(s.count-1,0):f();if(t==91||t==92)s.OSKey=!1;s[t]=null}),s||(f(),r(window,"focus",f))}};if(typeof window=="object"&&window.postMessage&&!i.isOldIE){var l=1;t.nextTick=function(e,n){n=n||window;var r="zero-timeout-message-"+l;t.addListener(n,"message",function i(s){s.data==r&&(t.stopPropagation(s),t.removeListener(n,"message",i),e())}),n.postMessage(r,"*")}}t.nextFrame=typeof window=="object"&&(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame),t.nextFrame?t.nextFrame=t.nextFrame.bind(window):t.nextFrame=function(e){setTimeout(e,17)}}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n1),e.preventDefault()},this.startSelect=function(e,t){e=e||this.editor.renderer.screenToTextCoordinates(this.x,this.y);var n=this.editor;n.$blockScrolling++,this.mousedownEvent.getShiftKey()?n.selection.selectToPosition(e):t||n.selection.moveToPosition(e),t||this.select(),n.renderer.scroller.setCapture&&n.renderer.scroller.setCapture(),n.setStyle("ace_selecting"),this.setState("select"),n.$blockScrolling--},this.select=function(){var e,t=this.editor,n=t.renderer.screenToTextCoordinates(this.x,this.y);t.$blockScrolling++;if(this.$clickSelection){var r=this.$clickSelection.comparePoint(n);if(r==-1)e=this.$clickSelection.end;else if(r==1)e=this.$clickSelection.start;else{var i=f(this.$clickSelection,n);n=i.cursor,e=i.anchor}t.selection.setSelectionAnchor(e.row,e.column)}t.selection.selectToPosition(n),t.$blockScrolling--,t.renderer.scrollCursorIntoView()},this.extendSelectionBy=function(e){var t,n=this.editor,r=n.renderer.screenToTextCoordinates(this.x,this.y),i=n.selection[e](r.row,r.column);n.$blockScrolling++;if(this.$clickSelection){var s=this.$clickSelection.comparePoint(i.start),o=this.$clickSelection.comparePoint(i.end);if(s==-1&&o<=0){t=this.$clickSelection.end;if(i.end.row!=r.row||i.end.column!=r.column)r=i.start}else if(o==1&&s>=0){t=this.$clickSelection.start;if(i.start.row!=r.row||i.start.column!=r.column)r=i.end}else if(s==-1&&o==1)r=i.end,t=i.start;else{var u=f(this.$clickSelection,r);r=u.cursor,t=u.anchor}n.selection.setSelectionAnchor(t.row,t.column)}n.selection.selectToPosition(r),n.$blockScrolling--,n.renderer.scrollCursorIntoView()},this.selectEnd=this.selectAllEnd=this.selectByWordsEnd=this.selectByLinesEnd=function(){this.$clickSelection=null,this.editor.unsetStyle("ace_selecting"),this.editor.renderer.scroller.releaseCapture&&this.editor.renderer.scroller.releaseCapture()},this.focusWait=function(){var e=a(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),t=Date.now();(e>o||t-this.mousedownEvent.time>this.$focusTimout)&&this.startSelect(this.mousedownEvent.getDocumentPosition())},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),n=this.editor,r=n.session,i=r.getBracketRange(t);i?(i.isEmpty()&&(i.start.column--,i.end.column++),this.setState("select")):(i=n.selection.getWordRange(t.row,t.column),this.setState("selectByWords")),this.$clickSelection=i,this.select()},this.onTripleClick=function(e){var t=e.getDocumentPosition(),n=this.editor;this.setState("selectByLines");var r=n.getSelectionRange();r.isMultiLine()&&r.contains(t.row,t.column)?(this.$clickSelection=n.selection.getLineRange(r.start.row),this.$clickSelection.end=n.selection.getLineRange(r.end.row).end):this.$clickSelection=n.selection.getLineRange(t.row),this.select()},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState("selectAll")},this.onMouseWheel=function(e){if(e.getAccelKey())return;e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=e.domEvent.timeStamp,n=t-(this.$lastScrollTime||0),r=this.editor,i=r.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(i||n<200)return this.$lastScrollTime=t,r.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()},this.onTouchMove=function(e){var t=e.domEvent.timeStamp,n=t-(this.$lastScrollTime||0),r=this.editor,i=r.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(i||n<200)return this.$lastScrollTime=t,r.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()}}).call(u.prototype),t.DefaultHandlers=u}),ace.define("ace/tooltip",["require","exports","module","ace/lib/oop","ace/lib/dom"],function(e,t,n){"use strict";function s(e){this.isOpen=!1,this.$element=null,this.$parentNode=e}var r=e("./lib/oop"),i=e("./lib/dom");(function(){this.$init=function(){return this.$element=i.createElement("div"),this.$element.className="ace_tooltip",this.$element.style.display="none",this.$parentNode.appendChild(this.$element),this.$element},this.getElement=function(){return this.$element||this.$init()},this.setText=function(e){i.setInnerText(this.getElement(),e)},this.setHtml=function(e){this.getElement().innerHTML=e},this.setPosition=function(e,t){this.getElement().style.left=e+"px",this.getElement().style.top=t+"px"},this.setClassName=function(e){i.addCssClass(this.getElement(),e)},this.show=function(e,t,n){e!=null&&this.setText(e),t!=null&&n!=null&&this.setPosition(t,n),this.isOpen||(this.getElement().style.display="block",this.isOpen=!0)},this.hide=function(){this.isOpen&&(this.getElement().style.display="none",this.isOpen=!1)},this.getHeight=function(){return this.getElement().offsetHeight},this.getWidth=function(){return this.getElement().offsetWidth}}).call(s.prototype),t.Tooltip=s}),ace.define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/tooltip"],function(e,t,n){"use strict";function u(e){function l(){var r=u.getDocumentPosition().row,s=n.$annotations[r];if(!s)return c();var o=t.session.getLength();if(r==o){var a=t.renderer.pixelToScreenCoordinates(0,u.y).row,l=u.$pos;if(a>t.session.documentToScreenRow(l.row,l.column))return c()}if(f==s)return;f=s.text.join(" "),i.setHtml(f),i.show(),t.on("mousewheel",c);if(e.$tooltipFollowsMouse)h(u);else{var p=u.domEvent.target,d=p.getBoundingClientRect(),v=i.getElement().style;v.left=d.right+"px",v.top=d.bottom+"px"}}function c(){o&&(o=clearTimeout(o)),f&&(i.hide(),f=null,t.removeEventListener("mousewheel",c))}function h(e){i.setPosition(e.x,e.y)}var t=e.editor,n=t.renderer.$gutterLayer,i=new a(t.container);e.editor.setDefaultHandler("guttermousedown",function(r){if(!t.isFocused()||r.getButton()!=0)return;var i=n.getRegion(r);if(i=="foldWidgets")return;var s=r.getDocumentPosition().row,o=t.session.selection;if(r.getShiftKey())o.selectTo(s,0);else{if(r.domEvent.detail==2)return t.selectAll(),r.preventDefault();e.$clickSelection=t.selection.getLineRange(s)}return e.setState("selectByLines"),e.captureMouse(r),r.preventDefault()});var o,u,f;e.editor.setDefaultHandler("guttermousemove",function(t){var n=t.domEvent.target||t.domEvent.srcElement;if(r.hasCssClass(n,"ace_fold-widget"))return c();f&&e.$tooltipFollowsMouse&&h(t),u=t;if(o)return;o=setTimeout(function(){o=null,u&&!e.isMousePressed?l():c()},50)}),s.addListener(t.renderer.$gutter,"mouseout",function(e){u=null;if(!f||o)return;o=setTimeout(function(){o=null,c()},50)}),t.on("changeSession",c)}function a(e){o.call(this,e)}var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/event"),o=e("../tooltip").Tooltip;i.inherits(a,o),function(){this.setPosition=function(e,t){var n=window.innerWidth||document.documentElement.clientWidth,r=window.innerHeight||document.documentElement.clientHeight,i=this.getWidth(),s=this.getHeight();e+=15,t+=15,e+i>n&&(e-=e+i-n),t+s>r&&(t-=20+s),o.prototype.setPosition.call(this,e,t)}}.call(a.prototype),t.GutterHandler=u}),ace.define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){r.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){r.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos?this.$pos:(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY),this.$pos)},this.inSelection=function(){if(this.$inSelection!==null)return this.$inSelection;var e=this.editor,t=e.getSelectionRange();if(t.isEmpty())this.$inSelection=!1;else{var n=this.getDocumentPosition();this.$inSelection=t.contains(n.row,n.column)}return this.$inSelection},this.getButton=function(){return r.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=i.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(s.prototype)}),ace.define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";function f(e){function T(e,n){var r=Date.now(),i=!n||e.row!=n.row,s=!n||e.column!=n.column;if(!S||i||s)t.$blockScrolling+=1,t.moveCursorToPosition(e),t.$blockScrolling-=1,S=r,x={x:p,y:d};else{var o=l(x.x,x.y,p,d);o>a?S=null:r-S>=u&&(t.renderer.scrollCursorIntoView(),S=null)}}function N(e,n){var r=Date.now(),i=t.renderer.layerConfig.lineHeight,s=t.renderer.layerConfig.characterWidth,u=t.renderer.scroller.getBoundingClientRect(),a={x:{left:p-u.left,right:u.right-p},y:{top:d-u.top,bottom:u.bottom-d}},f=Math.min(a.x.left,a.x.right),l=Math.min(a.y.top,a.y.bottom),c={row:e.row,column:e.column};f/s<=2&&(c.column+=a.x.left=o&&t.renderer.scrollCursorIntoView(c):E=r:E=null}function C(){var e=g;g=t.renderer.screenToTextCoordinates(p,d),T(g,e),N(g,e)}function k(){m=t.selection.toOrientedRange(),h=t.session.addMarker(m,"ace_selection",t.getSelectionStyle()),t.clearSelection(),t.isFocused()&&t.renderer.$cursorLayer.setBlinking(!1),clearInterval(v),C(),v=setInterval(C,20),y=0,i.addListener(document,"mousemove",O)}function L(){clearInterval(v),t.session.removeMarker(h),h=null,t.$blockScrolling+=1,t.selection.fromOrientedRange(m),t.$blockScrolling-=1,t.isFocused()&&!w&&t.renderer.$cursorLayer.setBlinking(!t.getReadOnly()),m=null,g=null,y=0,E=null,S=null,i.removeListener(document,"mousemove",O)}function O(){A==null&&(A=setTimeout(function(){A!=null&&h&&L()},20))}function M(e){var t=e.types;return!t||Array.prototype.some.call(t,function(e){return e=="text/plain"||e=="Text"})}function _(e){var t=["copy","copymove","all","uninitialized"],n=["move","copymove","linkmove","all","uninitialized"],r=s.isMac?e.altKey:e.ctrlKey,i="uninitialized";try{i=e.dataTransfer.effectAllowed.toLowerCase()}catch(e){}var o="none";return r&&t.indexOf(i)>=0?o="copy":n.indexOf(i)>=0?o="move":t.indexOf(i)>=0&&(o="copy"),o}var t=e.editor,n=r.createElement("img");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",s.isOpera&&(n.style.cssText="width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;");var f=["dragWait","dragWaitEnd","startDrag","dragReadyEnd","onMouseDrag"];f.forEach(function(t){e[t]=this[t]},this),t.addEventListener("mousedown",this.onMouseDown.bind(e));var c=t.container,h,p,d,v,m,g,y=0,b,w,E,S,x;this.onDragStart=function(e){if(this.cancelDrag||!c.draggable){var r=this;return setTimeout(function(){r.startSelect(),r.captureMouse(e)},0),e.preventDefault()}m=t.getSelectionRange();var i=e.dataTransfer;i.effectAllowed=t.getReadOnly()?"copy":"copyMove",s.isOpera&&(t.container.appendChild(n),n.scrollTop=0),i.setDragImage&&i.setDragImage(n,0,0),s.isOpera&&t.container.removeChild(n),i.clearData(),i.setData("Text",t.session.getTextRange()),w=!0,this.setState("drag")},this.onDragEnd=function(e){c.draggable=!1,w=!1,this.setState(null);if(!t.getReadOnly()){var n=e.dataTransfer.dropEffect;!b&&n=="move"&&t.session.remove(t.getSelectionRange()),t.renderer.$cursorLayer.setBlinking(!0)}this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle("")},this.onDragEnter=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||k(),y++,e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragOver=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||(k(),y++),A!==null&&(A=null),e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragLeave=function(e){y--;if(y<=0&&h)return L(),b=null,i.preventDefault(e)},this.onDrop=function(e){if(!g)return;var n=e.dataTransfer;if(w)switch(b){case"move":m.contains(g.row,g.column)?m={start:g,end:g}:m=t.moveText(m,g);break;case"copy":m=t.moveText(m,g,!0)}else{var r=n.getData("Text");m={start:g,end:t.session.insert(g,r)},t.focus(),b=null}return L(),i.preventDefault(e)},i.addListener(c,"dragstart",this.onDragStart.bind(e)),i.addListener(c,"dragend",this.onDragEnd.bind(e)),i.addListener(c,"dragenter",this.onDragEnter.bind(e)),i.addListener(c,"dragover",this.onDragOver.bind(e)),i.addListener(c,"dragleave",this.onDragLeave.bind(e)),i.addListener(c,"drop",this.onDrop.bind(e));var A=null}function l(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}var r=e("../lib/dom"),i=e("../lib/event"),s=e("../lib/useragent"),o=200,u=200,a=5;(function(){this.dragWait=function(){var e=Date.now()-this.mousedownEvent.time;e>this.editor.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(){var e=this.editor.container;e.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()),this.selectEnd()},this.dragReadyEnd=function(e){this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly()),this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle(""),this.dragWaitEnd()},this.startDrag=function(){this.cancelDrag=!1;var e=this.editor,t=e.container;t.draggable=!0,e.renderer.$cursorLayer.setBlinking(!1),e.setStyle("ace_dragging");var n=s.isWin?"default":"move";e.renderer.setCursorStyle(n),this.setState("dragReady")},this.onMouseDrag=function(e){var t=this.editor.container;if(s.isIE&&this.state=="dragReady"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>3&&t.dragDrop()}if(this.state==="dragWait"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>0&&(t.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()))}},this.onMouseDown=function(e){if(!this.$dragEnabled)return;this.mousedownEvent=e;var t=this.editor,n=e.inSelection(),r=e.getButton(),i=e.domEvent.detail||1;if(i===1&&r===0&&n){if(e.editor.inMultiSelectMode&&(e.getAccelKey()||e.getShiftKey()))return;this.mousedownEvent.time=Date.now();var o=e.domEvent.target||e.domEvent.srcElement;"unselectable"in o&&(o.unselectable="on");if(t.getDragDelay()){if(s.isWebKit){this.cancelDrag=!0;var u=t.container;u.draggable=!0}this.setState("dragWait")}else this.startDrag();this.captureMouse(e,this.onMouseDrag.bind(this)),e.defaultPrevented=!0}}}).call(f.prototype),t.DragdropHandler=f}),ace.define("ace/lib/net",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("./dom");t.get=function(e,t){var n=new XMLHttpRequest;n.open("GET",e,!0),n.onreadystatechange=function(){n.readyState===4&&t(n.responseText)},n.send(null)},t.loadScript=function(e,t){var n=r.getDocumentHead(),i=document.createElement("script");i.src=e,n.appendChild(i),i.onload=i.onreadystatechange=function(e,n){if(n||!i.readyState||i.readyState=="loaded"||i.readyState=="complete")i=i.onload=i.onreadystatechange=null,n||t()}},t.qualifyURL=function(e){var t=document.createElement("a");return t.href=e,t.href}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o1&&(i=n[n.length-2]);var o=a[t+"Path"];return o==null?o=a.basePath:r=="/"&&(t=r=""),o&&o.slice(-1)!="/"&&(o+="/"),o+t+r+i+this.get("suffix")},t.setModuleUrl=function(e,t){return a.$moduleUrls[e]=t},t.$loading={},t.loadModule=function(n,r){var i,o;Array.isArray(n)&&(o=n[0],n=n[1]);try{i=e(n)}catch(u){}if(i&&!t.$loading[n])return r&&r(i);t.$loading[n]||(t.$loading[n]=[]),t.$loading[n].push(r);if(t.$loading[n].length>1)return;var a=function(){e([n],function(e){t._emit("load.module",{name:n,module:e});var r=t.$loading[n];t.$loading[n]=null,r.forEach(function(t){t&&t(e)})})};if(!t.get("packaged"))return a();s.loadScript(t.moduleUrl(n,o),a)},t.init=f}),ace.define("ace/mouse/mouse_handler",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/mouse/default_handlers","ace/mouse/default_gutter_handler","ace/mouse/mouse_event","ace/mouse/dragdrop_handler","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("./default_handlers").DefaultHandlers,o=e("./default_gutter_handler").GutterHandler,u=e("./mouse_event").MouseEvent,a=e("./dragdrop_handler").DragdropHandler,f=e("../config"),l=function(e){var t=this;this.editor=e,new s(this),new o(this),new a(this);var n=function(t){var n=!document.hasFocus||!document.hasFocus()||!e.isFocused()&&document.activeElement==(e.textInput&&e.textInput.getElement());n&&window.focus(),e.focus()},u=e.renderer.getMouseEventTarget();r.addListener(u,"click",this.onMouseEvent.bind(this,"click")),r.addListener(u,"mousemove",this.onMouseMove.bind(this,"mousemove")),r.addMultiMouseDownListener([u,e.renderer.scrollBarV&&e.renderer.scrollBarV.inner,e.renderer.scrollBarH&&e.renderer.scrollBarH.inner,e.textInput&&e.textInput.getElement()].filter(Boolean),[400,300,250],this,"onMouseEvent"),r.addMouseWheelListener(e.container,this.onMouseWheel.bind(this,"mousewheel")),r.addTouchMoveListener(e.container,this.onTouchMove.bind(this,"touchmove"));var f=e.renderer.$gutter;r.addListener(f,"mousedown",this.onMouseEvent.bind(this,"guttermousedown")),r.addListener(f,"click",this.onMouseEvent.bind(this,"gutterclick")),r.addListener(f,"dblclick",this.onMouseEvent.bind(this,"gutterdblclick")),r.addListener(f,"mousemove",this.onMouseEvent.bind(this,"guttermousemove")),r.addListener(u,"mousedown",n),r.addListener(f,"mousedown",n),i.isIE&&e.renderer.scrollBarV&&(r.addListener(e.renderer.scrollBarV.element,"mousedown",n),r.addListener(e.renderer.scrollBarH.element,"mousedown",n)),e.on("mousemove",function(n){if(t.state||t.$dragDelay||!t.$dragEnabled)return;var r=e.renderer.screenToTextCoordinates(n.x,n.y),i=e.session.selection.getRange(),s=e.renderer;!i.isEmpty()&&i.insideStart(r.row,r.column)?s.setCursorStyle("default"):s.setCursorStyle("")})};(function(){this.onMouseEvent=function(e,t){this.editor._emit(e,new u(t,this.editor))},this.onMouseMove=function(e,t){var n=this.editor._eventRegistry&&this.editor._eventRegistry.mousemove;if(!n||!n.length)return;this.editor._emit(e,new u(t,this.editor))},this.onMouseWheel=function(e,t){var n=new u(t,this.editor);n.speed=this.$scrollSpeed*2,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.onTouchMove=function(e,t){var n=new u(t,this.editor);n.speed=1,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.setState=function(e){this.state=e},this.captureMouse=function(e,t){this.x=e.x,this.y=e.y,this.isMousePressed=!0;var n=this.editor.renderer;n.$keepTextAreaAtCursor&&(n.$keepTextAreaAtCursor=null);var s=this,o=function(e){if(!e)return;if(i.isWebKit&&!e.which&&s.releaseMouse)return s.releaseMouse();s.x=e.clientX,s.y=e.clientY,t&&t(e),s.mouseEvent=new u(e,s.editor),s.$mouseMoved=!0},a=function(e){clearInterval(l),f(),s[s.state+"End"]&&s[s.state+"End"](e),s.state="",n.$keepTextAreaAtCursor==null&&(n.$keepTextAreaAtCursor=!0,n.$moveTextAreaToCursor()),s.isMousePressed=!1,s.$onCaptureMouseMove=s.releaseMouse=null,e&&s.onMouseEvent("mouseup",e)},f=function(){s[s.state]&&s[s.state](),s.$mouseMoved=!1};if(i.isOldIE&&e.domEvent.type=="dblclick")return setTimeout(function(){a(e)});s.$onCaptureMouseMove=o,s.releaseMouse=r.capture(this.editor.container,o,a);var l=setInterval(f,20)},this.releaseMouse=null,this.cancelContextMenu=function(){var e=function(t){if(t&&t.domEvent&&t.domEvent.type!="contextmenu")return;this.editor.off("nativecontextmenu",e),t&&t.domEvent&&r.stopEvent(t.domEvent)}.bind(this);setTimeout(e,10),this.editor.on("nativecontextmenu",e)}}).call(l.prototype),f.defineOptions(l.prototype,"mouseHandler",{scrollSpeed:{initialValue:2},dragDelay:{initialValue:i.isMac?150:0},dragEnabled:{initialValue:!0},focusTimout:{initialValue:0},tooltipFollowsMouse:{initialValue:!0}}),t.MouseHandler=l}),ace.define("ace/mouse/fold_handler",["require","exports","module"],function(e,t,n){"use strict";function r(e){e.on("click",function(t){var n=t.getDocumentPosition(),r=e.session,i=r.getFoldAt(n.row,n.column,1);i&&(t.getAccelKey()?r.removeFold(i):r.expandFold(i),t.stop())}),e.on("gutterclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session;i.foldWidgets&&i.foldWidgets[r]&&e.session.onFoldWidgetClick(r,t),e.isFocused()||e.focus(),t.stop()}}),e.on("gutterdblclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session,s=i.getParentFoldRangeData(r,!0),o=s.range||s.firstRange;if(o){r=o.start.row;var u=i.getFoldAt(r,i.getLine(r).length,1);u?i.removeFold(u):(i.addFold("...",o),e.renderer.scrollCursorIntoView({row:o.start.row,column:0}))}t.stop()}})}t.FoldHandler=r}),ace.define("ace/keyboard/keybinding",["require","exports","module","ace/lib/keys","ace/lib/event"],function(e,t,n){"use strict";var r=e("../lib/keys"),i=e("../lib/event"),s=function(e){this.$editor=e,this.$data={editor:e},this.$handlers=[],this.setDefaultHandler(e.commands)};(function(){this.setDefaultHandler=function(e){this.removeKeyboardHandler(this.$defaultHandler),this.$defaultHandler=e,this.addKeyboardHandler(e,0)},this.setKeyboardHandler=function(e){var t=this.$handlers;if(t[t.length-1]==e)return;while(t[t.length-1]&&t[t.length-1]!=this.$defaultHandler)this.removeKeyboardHandler(t[t.length-1]);this.addKeyboardHandler(e,1)},this.addKeyboardHandler=function(e,t){if(!e)return;typeof e=="function"&&!e.handleKeyboard&&(e.handleKeyboard=e);var n=this.$handlers.indexOf(e);n!=-1&&this.$handlers.splice(n,1),t==undefined?this.$handlers.push(e):this.$handlers.splice(t,0,e),n==-1&&e.attach&&e.attach(this.$editor)},this.removeKeyboardHandler=function(e){var t=this.$handlers.indexOf(e);return t==-1?!1:(this.$handlers.splice(t,1),e.detach&&e.detach(this.$editor),!0)},this.getKeyboardHandler=function(){return this.$handlers[this.$handlers.length-1]},this.getStatusText=function(){var e=this.$data,t=e.editor;return this.$handlers.map(function(n){return n.getStatusText&&n.getStatusText(t,e)||""}).filter(Boolean).join(" ")},this.$callKeyboardHandlers=function(e,t,n,r){var s,o=!1,u=this.$editor.commands;for(var a=this.$handlers.length;a--;){s=this.$handlers[a].handleKeyboard(this.$data,e,t,n,r);if(!s||!s.command)continue;s.command=="null"?o=!0:o=u.exec(s.command,this.$editor,s.args,r),o&&r&&e!=-1&&s.passEvent!=1&&s.command.passEvent!=1&&i.stopEvent(r);if(o)break}return!o&&e==-1&&(s={command:"insertstring"},o=u.exec("insertstring",this.$editor,t)),o&&this.$editor._signal("keyboardActivity",s),o},this.onCommandKey=function(e,t,n){var i=r.keyCodeToString(n);this.$callKeyboardHandlers(t,i,n,e)},this.onTextInput=function(e){this.$callKeyboardHandlers(-1,e)}}).call(s.prototype),t.KeyBinding=s}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?tthis.end.column?1:0:ethis.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.rowt)var r={row:t+1,column:0};else if(this.start.rowt.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.isEmpty()?o.fromPoints(t,t):this.isBackwards()?o.fromPoints(t,e):o.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit("changeSelection"))},this.selectAll=function(){var e=this.doc.getLength()-1;this.setSelectionAnchor(0,0),this.moveCursorTo(e,this.doc.getLine(e).length)},this.setRange=this.setSelectionRange=function(e,t){t?(this.setSelectionAnchor(e.end.row,e.end.column),this.selectTo(e.start.row,e.start.column)):(this.setSelectionAnchor(e.start.row,e.start.column),this.selectTo(e.end.row,e.end.column)),this.getRange().isEmpty()&&(this.$isEmpty=!0),this.$desiredColumn=null},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.moveTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.moveToPosition=function(e){this.clearSelection(),this.moveCursorToPosition(e)},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){if(typeof t=="undefined"){var n=e||this.lead;e=n.row,t=n.column}return this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var n=typeof e=="number"?e:this.lead.row,r,i=this.session.getFoldLine(n);return i?(n=i.start.row,r=i.end.row):r=n,t===!0?new o(n,0,r,this.session.getLine(r).length):new o(n,0,r+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.moveCursorLeft=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,-1))this.moveCursorTo(t.start.row,t.start.column);else if(e.column===0)e.row>0&&this.moveCursorTo(e.row-1,this.doc.getLine(e.row-1).length);else{var n=this.session.getTabSize();this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(e.column-n,e.column).split(" ").length-1==n?this.moveCursorBy(0,-n):this.moveCursorBy(0,-1)}},this.moveCursorRight=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,1))this.moveCursorTo(t.end.row,t.end.column);else if(this.lead.column==this.doc.getLine(this.lead.row).length)this.lead.row0&&(t.column=r)}}this.moveCursorTo(t.row,t.column)},this.moveCursorFileEnd=function(){var e=this.doc.getLength()-1,t=this.doc.getLine(e).length;this.moveCursorTo(e,t)},this.moveCursorFileStart=function(){this.moveCursorTo(0,0)},this.moveCursorLongWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i;this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;var s=this.session.getFoldAt(e,t,1);if(s){this.moveCursorTo(s.end.row,s.end.column);return}if(i=this.session.nonTokenRe.exec(r))t+=this.session.nonTokenRe.lastIndex,this.session.nonTokenRe.lastIndex=0,r=n.substring(t);if(t>=n.length){this.moveCursorTo(e,n.length),this.moveCursorRight(),e0&&this.moveCursorWordLeft();return}if(o=this.session.tokenRe.exec(s))t-=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0;this.moveCursorTo(e,t)},this.$shortWordEndIndex=function(e){var t,n=0,r,i=/\s/,s=this.session.tokenRe;s.lastIndex=0;if(t=this.session.tokenRe.exec(e))n=this.session.tokenRe.lastIndex;else{while((r=e[n])&&i.test(r))n++;if(n<1){s.lastIndex=0;while((r=e[n])&&!s.test(r)){s.lastIndex=0,n++;if(i.test(r)){if(n>2){n--;break}while((r=e[n])&&i.test(r))n++;if(n>2)break}}}}return s.lastIndex=0,n},this.moveCursorShortWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i=this.session.getFoldAt(e,t,1);if(i)return this.moveCursorTo(i.end.row,i.end.column);if(t==n.length){var s=this.doc.getLength();do e++,r=this.doc.getLine(e);while(e0&&/^\s*$/.test(r));t=r.length,/\s+$/.test(r)||(r="")}var s=i.stringReverse(r),o=this.$shortWordEndIndex(s);return this.moveCursorTo(e,t-o)},this.moveCursorWordRight=function(){this.session.$selectLongWords?this.moveCursorLongWordRight():this.moveCursorShortWordRight()},this.moveCursorWordLeft=function(){this.session.$selectLongWords?this.moveCursorLongWordLeft():this.moveCursorShortWordLeft()},this.moveCursorBy=function(e,t){var n=this.session.documentToScreenPosition(this.lead.row,this.lead.column);t===0&&(this.$desiredColumn?n.column=this.$desiredColumn:this.$desiredColumn=n.column);var r=this.session.screenToDocumentPosition(n.row+e,n.column);e!==0&&t===0&&r.row===this.lead.row&&r.column===this.lead.column&&this.session.lineWidgets&&this.session.lineWidgets[r.row]&&(r.row>0||e>0)&&r.row++,this.moveCursorTo(r.row,r.column+t,t===0)},this.moveCursorToPosition=function(e){this.moveCursorTo(e.row,e.column)},this.moveCursorTo=function(e,t,n){var r=this.session.getFoldAt(e,t,1);r&&(e=r.start.row,t=r.start.column),this.$keepDesiredColumnOnChange=!0,this.lead.setPosition(e,t),this.$keepDesiredColumnOnChange=!1,n||(this.$desiredColumn=null)},this.moveCursorToScreen=function(e,t,n){var r=this.session.screenToDocumentPosition(e,t);this.moveCursorTo(r.row,r.column,n)},this.detach=function(){this.lead.detach(),this.anchor.detach(),this.session=this.doc=null},this.fromOrientedRange=function(e){this.setSelectionRange(e,e.cursor==e.start),this.$desiredColumn=e.desiredColumn||this.$desiredColumn},this.toOrientedRange=function(e){var t=this.getRange();return e?(e.start.column=t.start.column,e.start.row=t.start.row,e.end.column=t.end.column,e.end.row=t.end.row):e=t,e.cursor=this.isBackwards()?e.start:e.end,e.desiredColumn=this.$desiredColumn,e},this.getRangeOfMovements=function(e){var t=this.getCursor();try{e(this);var n=this.getCursor();return o.fromPoints(t,n)}catch(r){return o.fromPoints(t,t)}finally{this.moveCursorToPosition(t)}},this.toJSON=function(){if(this.rangeCount)var e=this.ranges.map(function(e){var t=e.clone();return t.isBackwards=e.cursor==e.start,t});else{var e=this.getRange();e.isBackwards=this.isBackwards()}return e},this.fromJSON=function(e){if(e.start==undefined){if(this.rangeList){this.toSingleRange(e[0]);for(var t=e.length;t--;){var n=o.fromPoints(e[t].start,e[t].end);e[t].isBackwards&&(n.cursor=n.start),this.addRange(n,!0)}return}e=e[0]}this.rangeList&&this.toSingleRange(e),this.setSelectionRange(e,e.isBackwards)},this.isEqual=function(e){if((e.length||this.rangeCount)&&e.length!=this.rangeCount)return!1;if(!e.length||!this.ranges)return this.getRange().isEqual(e);for(var t=this.ranges.length;t--;)if(!this.ranges[t].isEqual(e[t]))return!1;return!0}}).call(u.prototype),t.Selection=u}),ace.define("ace/tokenizer",["require","exports","module","ace/config"],function(e,t,n){"use strict";var r=e("./config"),i=2e3,s=function(e){this.states=e,this.regExps={},this.matchMappings={};for(var t in this.states){var n=this.states[t],r=[],i=0,s=this.matchMappings[t]={defaultToken:"text"},o="g",u=[];for(var a=0;a1?f.onMatch=this.$applyToken:f.onMatch=f.token),c>1&&(/\\\d/.test(f.regex)?l=f.regex.replace(/\\([0-9]+)/g,function(e,t){return"\\"+(parseInt(t,10)+i+1)}):(c=1,l=this.removeCapturingGroups(f.regex)),!f.splitRegex&&typeof f.token!="string"&&u.push(f)),s[i]=a,i+=c,r.push(l),f.onMatch||(f.onMatch=null)}r.length||(s[0]=0,r.push("$")),u.forEach(function(e){e.splitRegex=this.createSplitterRegexp(e.regex,o)},this),this.regExps[t]=new RegExp("("+r.join(")|(")+")|($)",o)}};(function(){this.$setMaxTokenCount=function(e){i=e|0},this.$applyToken=function(e){var t=this.splitRegex.exec(e).slice(1),n=this.token.apply(this,t);if(typeof n=="string")return[{type:n,value:e}];var r=[];for(var i=0,s=n.length;il){var g=e.substring(l,m-v.length);h.type==p?h.value+=g:(h.type&&f.push(h),h={type:p,value:g})}for(var y=0;yi){c>2*e.length&&this.reportError("infinite loop with in ace tokenizer",{startState:t,line:e});while(l1&&n[0]!==r&&n.unshift("#tmp",r),{tokens:f,state:n.length?n:r}},this.reportError=r.reportError}).call(s.prototype),t.Tokenizer=s}),ace.define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang"),i=function(){this.$rules={start:[{token:"empty_line",regex:"^$"},{defaultToken:"text"}]}};(function(){this.addRules=function(e,t){if(!t){for(var n in e)this.$rules[n]=e[n];return}for(var n in e){var r=e[n];for(var i=0;i=this.$rowTokens.length){this.$row+=1,e||(e=this.$session.getLength());if(this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,n=e[t].start;if(n!==undefined)return n;n=0;while(t>0)t-=1,n+=e[t].value.length;return n},this.getCurrentTokenPosition=function(){return{row:this.$row,column:this.getCurrentTokenColumn()}}}).call(r.prototype),t.TokenIterator=r}),ace.define("ace/mode/text",["require","exports","module","ace/tokenizer","ace/mode/text_highlight_rules","ace/mode/behaviour","ace/unicode","ace/lib/lang","ace/token_iterator","ace/range"],function(e,t,n){"use strict";var r=e("../tokenizer").Tokenizer,i=e("./text_highlight_rules").TextHighlightRules,s=e("./behaviour").Behaviour,o=e("../unicode"),u=e("../lib/lang"),a=e("../token_iterator").TokenIterator,f=e("../range").Range,l=function(){this.HighlightRules=i,this.$behaviour=new s};(function(){this.tokenRe=new RegExp("^["+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]+","g"),this.nonTokenRe=new RegExp("^(?:[^"+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]|\\s])+","g"),this.getTokenizer=function(){return this.$tokenizer||(this.$highlightRules=this.$highlightRules||new this.HighlightRules,this.$tokenizer=new r(this.$highlightRules.getRules())),this.$tokenizer},this.lineCommentStart="",this.blockComment="",this.toggleCommentLines=function(e,t,n,r){function w(e){for(var t=n;t<=r;t++)e(i.getLine(t),t)}var i=t.doc,s=!0,o=!0,a=Infinity,f=t.getTabSize(),l=!1;if(!this.lineCommentStart){if(!this.blockComment)return!1;var c=this.blockComment.start,h=this.blockComment.end,p=new RegExp("^(\\s*)(?:"+u.escapeRegExp(c)+")"),d=new RegExp("(?:"+u.escapeRegExp(h)+")\\s*$"),v=function(e,t){if(g(e,t))return;if(!s||/\S/.test(e))i.insertInLine({row:t,column:e.length},h),i.insertInLine({row:t,column:a},c)},m=function(e,t){var n;(n=e.match(d))&&i.removeInLine(t,e.length-n[0].length,e.length),(n=e.match(p))&&i.removeInLine(t,n[1].length,n[0].length)},g=function(e,n){if(p.test(e))return!0;var r=t.getTokens(n);for(var i=0;i2?r%f!=f-1:r%f==0}}var E=Infinity;w(function(e,t){var n=e.search(/\S/);n!==-1?(ne.length&&(E=e.length)}),a==Infinity&&(a=E,s=!1,o=!1),l&&a%f!=0&&(a=Math.floor(a/f)*f),w(o?m:v)},this.toggleBlockComment=function(e,t,n,r){var i=this.blockComment;if(!i)return;!i.start&&i[0]&&(i=i[0]);var s=new a(t,r.row,r.column),o=s.getCurrentToken(),u=t.selection,l=t.selection.toOrientedRange(),c,h;if(o&&/comment/.test(o.type)){var p,d;while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.start);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;p=new f(m,g,m,g+i.start.length);break}o=s.stepBackward()}var s=new a(t,r.row,r.column),o=s.getCurrentToken();while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.end);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;d=new f(m,g,m,g+i.end.length);break}o=s.stepForward()}d&&t.remove(d),p&&(t.remove(p),c=p.start.row,h=-i.start.length)}else h=i.start.length,c=n.start.row,t.insert(n.end,i.end),t.insert(n.start,i.start);l.start.row==c&&(l.start.column+=h),l.end.row==c&&(l.end.column+=h),t.selection.fromOrientedRange(l)},this.getNextLineIndent=function(e,t,n){return this.$getIndent(t)},this.checkOutdent=function(e,t,n){return!1},this.autoOutdent=function(e,t,n){},this.$getIndent=function(e){return e.match(/^\s*/)[0]},this.createWorker=function(e){return null},this.createModeDelegates=function(e){this.$embeds=[],this.$modes={};for(var t in e)e[t]&&(this.$embeds.push(t),this.$modes[t]=new e[t]);var n=["toggleBlockComment","toggleCommentLines","getNextLineIndent","checkOutdent","autoOutdent","transformAction","getCompletions"];for(var t=0;t=0&&t.row=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.columnthis.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e0,r=t=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i20){n.running=setTimeout(n.$worker,20);break}}n.currentLine=t,s<=r&&n.fireUpdateEvent(s,r)}};(function(){r.implement(this,i),this.setTokenizer=function(e){this.tokenizer=e,this.lines=[],this.states=[],this.start(0)},this.setDocument=function(e){this.doc=e,this.lines=[],this.states=[],this.stop()},this.fireUpdateEvent=function(e,t){var n={first:e,last:t};this._signal("update",{data:n})},this.start=function(e){this.currentLine=Math.min(e||0,this.currentLine,this.doc.getLength()),this.lines.splice(this.currentLine,this.lines.length),this.states.splice(this.currentLine,this.states.length),this.stop(),this.running=setTimeout(this.$worker,700)},this.scheduleStart=function(){this.running||(this.running=setTimeout(this.$worker,700))},this.$updateOnChange=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.lines[t]=null;else if(e.action=="remove")this.lines.splice(t,n+1,null),this.states.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.lines.splice.apply(this.lines,r),this.states.splice.apply(this.states,r)}this.currentLine=Math.min(t,this.currentLine,this.doc.getLength()),this.stop()},this.stop=function(){this.running&&clearTimeout(this.running),this.running=!1},this.getTokens=function(e){return this.lines[e]||this.$tokenizeRow(e)},this.getState=function(e){return this.currentLine==e&&this.$tokenizeRow(e),this.states[e]||"start"},this.$tokenizeRow=function(e){var t=this.doc.getLine(e),n=this.states[e-1],r=this.tokenizer.getLineTokens(t,n,e);return this.states[e]+""!=r.state+""?(this.states[e]=r.state,this.lines[e+1]=null,this.currentLine>e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=r.tokens}}).call(s.prototype),t.BackgroundTokenizer=s}),ace.define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(e,t,n){this.setRegexp(e),this.clazz=t,this.type=n||"text"};(function(){this.MAX_RANGES=500,this.setRegexp=function(e){if(this.regExp+""==e+"")return;this.regExp=e,this.cache=[]},this.update=function(e,t,n,i){if(!this.regExp)return;var o=i.firstRow,u=i.lastRow;for(var a=o;a<=u;a++){var f=this.cache[a];f==null&&(f=r.getMatchOffsets(n.getLine(a),this.regExp),f.length>this.MAX_RANGES&&(f=f.slice(0,this.MAX_RANGES)),f=f.map(function(e){return new s(a,e.offset,a,e.offset+e.length)}),this.cache[a]=f.length?f:"");for(var l=f.length;l--;)t.drawSingleLineMarker(e,f[l].toScreenRange(n),this.clazz,i)}}}).call(o.prototype),t.SearchHighlight=o}),ace.define("ace/edit_session/fold_line",["require","exports","module","ace/range"],function(e,t,n){"use strict";function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var n=t[t.length-1];this.range=new r(t[0].start.row,t[0].start.column,n.end.row,n.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}var r=e("../range").Range;(function(){this.shiftRow=function(e){this.start.row+=e,this.end.row+=e,this.folds.forEach(function(t){t.start.row+=e,t.end.row+=e})},this.addFold=function(e){if(e.sameRow){if(e.start.rowthis.endRow)throw new Error("Can't add a fold to this FoldLine as it has no connection");this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),this.range.compareEnd(e.start.row,e.start.column)>0?(this.end.row=e.end.row,this.end.column=e.end.column):this.range.compareStart(e.end.row,e.end.column)<0&&(this.start.row=e.start.row,this.start.column=e.start.column)}else if(e.start.row==this.end.row)this.folds.push(e),this.end.row=e.end.row,this.end.column=e.end.column;else{if(e.end.row!=this.start.row)throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");this.folds.unshift(e),this.start.row=e.start.row,this.start.column=e.start.column}e.foldLine=this},this.containsRow=function(e){return e>=this.start.row&&e<=this.end.row},this.walk=function(e,t,n){var r=0,i=this.folds,s,o,u,a=!0;t==null&&(t=this.end.row,n=this.end.column);for(var f=0;f0)continue;var a=i(e,o.start);return u===0?t&&a!==0?-s-2:s:a>0||a===0&&!t?s:-s-1}return-s-1},this.add=function(e){var t=!e.isEmpty(),n=this.pointIndex(e.start,t);n<0&&(n=-n-1);var r=this.pointIndex(e.end,t,n);return r<0?r=-r-1:r++,this.ranges.splice(n,r-n,e)},this.addList=function(e){var t=[];for(var n=e.length;n--;)t.push.apply(t,this.add(e[n]));return t},this.substractPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges.splice(t,1)},this.merge=function(){var e=[],t=this.ranges;t=t.sort(function(e,t){return i(e.start,t.start)});var n=t[0],r;for(var s=1;s=0},this.containsPoint=function(e){return this.pointIndex(e)>=0},this.rangeAtPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges[t]},this.clipRows=function(e,t){var n=this.ranges;if(n[0].start.row>t||n[n.length-1].start.rowr)break;l.start.row==r&&l.start.column>=t.column&&(l.start.column!=t.column||!this.$insertRight)&&(l.start.column+=o,l.start.row+=s);if(l.end.row==r&&l.end.column>=t.column){if(l.end.column==t.column&&this.$insertRight)continue;l.end.column==t.column&&o>0&&al.start.column&&l.end.column==u[a+1].start.column&&(l.end.column-=o),l.end.column+=o,l.end.row+=s}}if(s!=0&&a=e)return i;if(i.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r=e)return i}return null},this.getFoldedRowCount=function(e,t){var n=this.$foldData,r=t-e+1;for(var i=0;i=t){u=e?r-=t-u:r=0);break}o>=e&&(u>=e?r-=o-u:r-=o-e+1)}return r},this.$addFoldLine=function(e){return this.$foldData.push(e),this.$foldData.sort(function(e,t){return e.start.row-t.start.row}),e},this.addFold=function(e,t){var n=this.$foldData,r=!1,o;e instanceof s?o=e:(o=new s(t,e),o.collapseChildren=t.collapseChildren),this.$clipRangeToDocument(o.range);var u=o.start.row,a=o.start.column,f=o.end.row,l=o.end.column;if(u0&&(this.removeFolds(p),p.forEach(function(e){o.addSubFold(e)}));for(var d=0;d0&&this.foldAll(e.start.row+1,e.end.row,e.collapseChildren-1),e.subFolds=[]},this.expandFolds=function(e){e.forEach(function(e){this.expandFold(e)},this)},this.unfold=function(e,t){var n,i;e==null?(n=new r(0,0,this.getLength(),0),t=!0):typeof e=="number"?n=new r(e,0,e,this.getLine(e).length):"row"in e?n=r.fromPoints(e,e):n=e,i=this.getFoldsInRangeList(n);if(t)this.removeFolds(i);else{var s=i;while(s.length)this.expandFolds(s),s=this.getFoldsInRangeList(n)}if(i.length)return i},this.isRowFolded=function(e,t){return!!this.getFoldLine(e,t)},this.getRowFoldEnd=function(e,t){var n=this.getFoldLine(e,t);return n?n.end.row:e},this.getRowFoldStart=function(e,t){var n=this.getFoldLine(e,t);return n?n.start.row:e},this.getFoldDisplayLine=function(e,t,n,r,i){r==null&&(r=e.start.row),i==null&&(i=0),t==null&&(t=e.end.row),n==null&&(n=this.getLine(t).length);var s=this.doc,o="";return e.walk(function(e,t,n,u){if(t=e){i=s.end.row;try{var o=this.addFold("...",s);o&&(o.collapseChildren=n)}catch(u){}}}},this.$foldStyles={manual:1,markbegin:1,markbeginend:1},this.$foldStyle="markbegin",this.setFoldStyle=function(e){if(!this.$foldStyles[e])throw new Error("invalid fold style: "+e+"["+Object.keys(this.$foldStyles).join(", ")+"]");if(this.$foldStyle==e)return;this.$foldStyle=e,e=="manual"&&this.unfold();var t=this.$foldMode;this.$setFolding(null),this.$setFolding(t)},this.$setFolding=function(e){if(this.$foldMode==e)return;this.$foldMode=e,this.off("change",this.$updateFoldWidgets),this.off("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets),this._signal("changeAnnotation");if(!e||this.$foldStyle=="manual"){this.foldWidgets=null;return}this.foldWidgets=[],this.getFoldWidget=e.getFoldWidget.bind(e,this,this.$foldStyle),this.getFoldWidgetRange=e.getFoldWidgetRange.bind(e,this,this.$foldStyle),this.$updateFoldWidgets=this.updateFoldWidgets.bind(this),this.$tokenizerUpdateFoldWidgets=this.tokenizerUpdateFoldWidgets.bind(this),this.on("change",this.$updateFoldWidgets),this.on("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets)},this.getParentFoldRangeData=function(e,t){var n=this.foldWidgets;if(!n||t&&n[e])return{};var r=e-1,i;while(r>=0){var s=n[r];s==null&&(s=n[r]=this.getFoldWidget(r));if(s=="start"){var o=this.getFoldWidgetRange(r);i||(i=o);if(o&&o.end.row>=e)break}r--}return{range:r!==-1&&o,firstRange:i}},this.onFoldWidgetClick=function(e,t){t=t.domEvent;var n={children:t.shiftKey,all:t.ctrlKey||t.metaKey,siblings:t.altKey},r=this.$toggleFoldWidget(e,n);if(!r){var i=t.target||t.srcElement;i&&/ace_fold-widget/.test(i.className)&&(i.className+=" ace_invalid")}},this.$toggleFoldWidget=function(e,t){if(!this.getFoldWidget)return;var n=this.getFoldWidget(e),r=this.getLine(e),i=n==="end"?-1:1,s=this.getFoldAt(e,i===-1?0:r.length,i);if(s){t.children||t.all?this.removeFold(s):this.expandFold(s);return}var o=this.getFoldWidgetRange(e,!0);if(o&&!o.isMultiLine()){s=this.getFoldAt(o.start.row,o.start.column,1);if(s&&o.isEqual(s.range)){this.removeFold(s);return}}if(t.siblings){var u=this.getParentFoldRangeData(e);if(u.range)var a=u.range.start.row+1,f=u.range.end.row;this.foldAll(a,f,t.all?1e4:0)}else t.children?(f=o?o.end.row:this.getLength(),this.foldAll(e+1,f,t.all?1e4:0)):o&&(t.all&&(o.collapseChildren=1e4),this.addFold("...",o));return o},this.toggleFoldWidget=function(e){var t=this.selection.getCursor().row;t=this.getRowFoldStart(t);var n=this.$toggleFoldWidget(t,{});if(n)return;var r=this.getParentFoldRangeData(t,!0);n=r.range||r.firstRange;if(n){t=n.start.row;var i=this.getFoldAt(t,this.getLine(t).length,1);i?this.removeFold(i):this.addFold("...",n)}},this.updateFoldWidgets=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.foldWidgets[t]=null;else if(e.action=="remove")this.foldWidgets.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.foldWidgets.splice.apply(this.foldWidgets,r)}},this.tokenizerUpdateFoldWidgets=function(e){var t=e.data;t.first!=t.last&&this.foldWidgets.length>t.first&&this.foldWidgets.splice(t.first,this.foldWidgets.length)}}var r=e("../range").Range,i=e("./fold_line").FoldLine,s=e("./fold").Fold,o=e("../token_iterator").TokenIterator;t.Folding=u}),ace.define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"],function(e,t,n){"use strict";function s(){this.findMatchingBracket=function(e,t){if(e.column==0)return null;var n=t||this.getLine(e.row).charAt(e.column-1);if(n=="")return null;var r=n.match(/([\(\[\{])|([\)\]\}])/);return r?r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e):null},this.getBracketRange=function(e){var t=this.getLine(e.row),n=!0,r,s=t.charAt(e.column-1),o=s&&s.match(/([\(\[\{])|([\)\]\}])/);o||(s=t.charAt(e.column),e={row:e.row,column:e.column+1},o=s&&s.match(/([\(\[\{])|([\)\]\}])/),n=!1);if(!o)return null;if(o[1]){var u=this.$findClosingBracket(o[1],e);if(!u)return null;r=i.fromPoints(e,u),n||(r.end.column++,r.start.column--),r.cursor=r.end}else{var u=this.$findOpeningBracket(o[2],e);if(!u)return null;r=i.fromPoints(u,e),n||(r.start.column++,r.end.column--),r.cursor=r.start}return r},this.$brackets={")":"(","(":")","]":"[","[":"]","{":"}","}":"{"},this.$findOpeningBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("rparen",".paren").replace(/\b(?:end)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn()-2,f=u.value;for(;;){while(a>=0){var l=f.charAt(a);if(l==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else l==e&&(s+=1);a-=1}do u=o.stepBackward();while(u&&!n.test(u.type));if(u==null)break;f=u.value,a=f.length-1}return null},this.$findClosingBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("lparen",".paren").replace(/\b(?:start|begin)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn();for(;;){var f=u.value,l=f.length;while(a=4352&&e<=4447||e>=4515&&e<=4519||e>=4602&&e<=4607||e>=9001&&e<=9002||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12283||e>=12288&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12589||e>=12593&&e<=12686||e>=12688&&e<=12730||e>=12736&&e<=12771||e>=12784&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=13054||e>=13056&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=55216&&e<=55238||e>=55243&&e<=55291||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=65281&&e<=65376||e>=65504&&e<=65510}r.implement(this,o),this.setDocument=function(e){this.doc&&this.doc.removeListener("change",this.$onChange),this.doc=e,e.on("change",this.$onChange),this.bgTokenizer&&this.bgTokenizer.setDocument(this.getDocument()),this.resetCaches()},this.getDocument=function(){return this.doc},this.$resetRowCache=function(e){if(!e){this.$docRowCache=[],this.$screenRowCache=[];return}var t=this.$docRowCache.length,n=this.$getRowCacheIndex(this.$docRowCache,e)+1;t>n&&(this.$docRowCache.splice(n,t),this.$screenRowCache.splice(n,t))},this.$getRowCacheIndex=function(e,t){var n=0,r=e.length-1;while(n<=r){var i=n+r>>1,s=e[i];if(t>s)n=i+1;else{if(!(t=t)break}return r=n[s],r?(r.index=s,r.start=i-r.value.length,r):null},this.setUndoManager=function(e){this.$undoManager=e,this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.$informUndoManager&&this.$informUndoManager.cancel();if(e){var t=this;this.$syncInformUndoManager=function(){t.$informUndoManager.cancel(),t.$deltasFold.length&&(t.$deltas.push({group:"fold",deltas:t.$deltasFold}),t.$deltasFold=[]),t.$deltasDoc.length&&(t.$deltas.push({group:"doc",deltas:t.$deltasDoc}),t.$deltasDoc=[]),t.$deltas.length>0&&e.execute({action:"aceupdate",args:[t.$deltas,t],merge:t.mergeUndoDeltas}),t.mergeUndoDeltas=!1,t.$deltas=[]},this.$informUndoManager=i.delayedCall(this.$syncInformUndoManager)}},this.markUndoGroup=function(){this.$syncInformUndoManager&&this.$syncInformUndoManager()},this.$defaultUndoManager={undo:function(){},redo:function(){},reset:function(){}},this.getUndoManager=function(){return this.$undoManager||this.$defaultUndoManager},this.getTabString=function(){return this.getUseSoftTabs()?i.stringRepeat(" ",this.getTabSize()):" "},this.setUseSoftTabs=function(e){this.setOption("useSoftTabs",e)},this.getUseSoftTabs=function(){return this.$useSoftTabs&&!this.$mode.$indentWithTabs},this.setTabSize=function(e){this.setOption("tabSize",e)},this.getTabSize=function(){return this.$tabSize},this.isTabStop=function(e){return this.$useSoftTabs&&e.column%this.$tabSize===0},this.$overwrite=!1,this.setOverwrite=function(e){this.setOption("overwrite",e)},this.getOverwrite=function(){return this.$overwrite},this.toggleOverwrite=function(){this.setOverwrite(!this.$overwrite)},this.addGutterDecoration=function(e,t){this.$decorations[e]||(this.$decorations[e]=""),this.$decorations[e]+=" "+t,this._signal("changeBreakpoint",{})},this.removeGutterDecoration=function(e,t){this.$decorations[e]=(this.$decorations[e]||"").replace(" "+t,""),this._signal("changeBreakpoint",{})},this.getBreakpoints=function(){return this.$breakpoints},this.setBreakpoints=function(e){this.$breakpoints=[];for(var t=0;t0&&(r=!!n.charAt(t-1).match(this.tokenRe)),r||(r=!!n.charAt(t).match(this.tokenRe));if(r)var i=this.tokenRe;else if(/^\s+$/.test(n.slice(t-1,t+1)))var i=/\s/;else var i=this.nonTokenRe;var s=t;if(s>0){do s--;while(s>=0&&n.charAt(s).match(i));s++}var o=t;while(oe&&(e=t.screenWidth)}),this.lineWidgetWidth=e},this.$computeWidth=function(e){if(this.$modified||e){this.$modified=!1;if(this.$useWrapMode)return this.screenWidth=this.$wrapLimit;var t=this.doc.getAllLines(),n=this.$rowLengthCache,r=0,i=0,s=this.$foldData[i],o=s?s.start.row:Infinity,u=t.length;for(var a=0;ao){a=s.end.row+1;if(a>=u)break;s=this.$foldData[i++],o=s?s.start.row:Infinity}n[a]==null&&(n[a]=this.$getStringScreenWidth(t[a])[0]),n[a]>r&&(r=n[a])}this.screenWidth=r}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.removeFullLines=function(e,t){return this.doc.removeFullLines(e,t)},this.undoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=e.length-1;r!=-1;r--){var i=e[r];i.group=="doc"?(this.doc.revertDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!0,n)):i.deltas.forEach(function(e){this.addFolds(e.folds)},this)}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n},this.redoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=0;re.end.column&&(s.start.column+=u),s.end.row==e.end.row&&s.end.column>e.end.column&&(s.end.column+=u)),o&&s.start.row>=e.end.row&&(s.start.row+=o,s.end.row+=o)}s.end=this.insert(s.start,r);if(i.length){var a=e.start,l=s.start,o=l.row-a.row,u=l.column-a.column;this.addFolds(i.map(function(e){return e=e.clone(),e.start.row==a.row&&(e.start.column+=u),e.end.row==a.row&&(e.end.column+=u),e.start.row+=o,e.end.row+=o,e}))}return s},this.indentRows=function(e,t,n){n=n.replace(/\t/g,this.getTabString());for(var r=e;r<=t;r++)this.doc.insertInLine({row:r,column:0},n)},this.outdentRows=function(e){var t=e.collapseRows(),n=new f(0,0,0,0),r=this.getTabSize();for(var i=t.start.row;i<=t.end.row;++i){var s=this.getLine(i);n.start.row=i,n.end.row=i;for(var o=0;o0){var r=this.getRowFoldEnd(t+n);if(r>this.doc.getLength()-1)return 0;var i=r-t}else{e=this.$clipRowToDocument(e),t=this.$clipRowToDocument(t);var i=t-e+1}var s=new f(e,0,t,Number.MAX_VALUE),o=this.getFoldsInRange(s).map(function(e){return e=e.clone(),e.start.row+=i,e.end.row+=i,e}),u=n==0?this.doc.getLines(e,t):this.doc.removeFullLines(e,t);return this.doc.insertFullLines(e+i,u),o.length&&this.addFolds(o),i},this.moveLinesUp=function(e,t){return this.$moveLines(e,t,-1)},this.moveLinesDown=function(e,t){return this.$moveLines(e,t,1)},this.duplicateLines=function(e,t){return this.$moveLines(e,t,0)},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){t=Math.max(0,t);if(e<0)e=0,t=0;else{var n=this.doc.getLength();e>=n?(e=n-1,t=this.doc.getLine(n-1).length):t=Math.min(this.doc.getLine(e).length,t)}return{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){if(e!=this.$useWrapMode){this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0);if(e){var t=this.getLength();this.$wrapData=Array(t),this.$updateWrapData(0,t-1)}this._signal("changeWrapMode")}},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){if(this.$wrapLimitRange.min!==e||this.$wrapLimitRange.max!==t)this.$wrapLimitRange={min:e,max:t},this.$modified=!0,this.$useWrapMode&&this._signal("changeWrapMode")},this.adjustWrapLimit=function(e,t){var n=this.$wrapLimitRange;n.max<0&&(n={min:t,max:t});var r=this.$constrainWrapLimit(e,n.min,n.max);return r!=this.$wrapLimit&&r>1?(this.$wrapLimit=r,this.$modified=!0,this.$useWrapMode&&(this.$updateWrapData(0,this.getLength()-1),this.$resetRowCache(0),this._signal("changeWrapLimit")),!0):!1},this.$constrainWrapLimit=function(e,t,n){return t&&(e=Math.max(t,e)),n&&(e=Math.min(n,e)),e},this.getWrapLimit=function(){return this.$wrapLimit},this.setWrapLimit=function(e){this.setWrapLimitRange(e,e)},this.getWrapLimitRange=function(){return{min:this.$wrapLimitRange.min,max:this.$wrapLimitRange.max}},this.$updateInternalDataOnChange=function(e){var t=this.$useWrapMode,n=e.action,r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=null;this.$updating=!0;if(u!=0)if(n==="remove"){this[t?"$wrapData":"$rowLengthCache"].splice(s,u);var f=this.$foldData;a=this.getFoldsInRange(e),this.removeFolds(a);var l=this.getFoldLine(i.row),c=0;if(l){l.addRemoveChars(i.row,i.column,r.column-i.column),l.shiftRow(-u);var h=this.getFoldLine(s);h&&h!==l&&(h.merge(l),l=h),c=f.indexOf(l)+1}for(c;c=i.row&&l.shiftRow(-u)}o=s}else{var p=Array(u);p.unshift(s,0);var d=t?this.$wrapData:this.$rowLengthCache;d.splice.apply(d,p);var f=this.$foldData,l=this.getFoldLine(s),c=0;if(l){var v=l.range.compareInside(r.row,r.column);v==0?(l=l.split(r.row,r.column),l&&(l.shiftRow(u),l.addRemoveChars(o,0,i.column-r.column))):v==-1&&(l.addRemoveChars(s,0,i.column-r.column),l.shiftRow(u)),c=f.indexOf(l)+1}for(c;c=s&&l.shiftRow(u)}}else{u=Math.abs(e.start.column-e.end.column),n==="remove"&&(a=this.getFoldsInRange(e),this.removeFolds(a),u=-u);var l=this.getFoldLine(s);l&&l.addRemoveChars(s,r.column,u)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error("doc.getLength() and $wrapData.length have to be the same!"),this.$updating=!1,t?this.$updateWrapData(s,o):this.$updateRowLengthCache(s,o),a},this.$updateRowLengthCache=function(e,t,n){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var r=this.doc.getAllLines(),i=this.getTabSize(),s=this.$wrapData,o=this.$wrapLimit,a,f,l=e;t=Math.min(t,r.length-1);while(l<=t)f=this.getFoldLine(l,f),f?(a=[],f.walk(function(e,t,i,s){var o;if(e!=null){o=this.$getDisplayTokens(e,a.length),o[0]=n;for(var f=1;fr-b){var w=a+r-b;if(e[w-1]>=p&&e[w]>=p){y(w);continue}if(e[w]==n||e[w]==u){for(w;w!=a-1;w--)if(e[w]==n)break;if(w>a){y(w);continue}w=a+r;for(w;w>2)),a-1);while(w>E&&e[w]E&&e[w]E&&e[w]==l)w--}else while(w>E&&e[w]E){y(++w);continue}w=a+r,e[w]==t&&w--,y(w-b)}return s},this.$getDisplayTokens=function(n,r){var i=[],s;r=r||0;for(var o=0;o39&&u<48||u>57&&u<64?i.push(l):u>=4352&&m(u)?i.push(e,t):i.push(e)}return i},this.$getStringScreenWidth=function(e,t,n){if(t==0)return[0,0];t==null&&(t=Infinity),n=n||0;var r,i;for(i=0;i=4352&&m(r)?n+=2:n+=1;if(n>t)break}return[n,i]},this.lineWidgets=null,this.getRowLength=function(e){if(this.lineWidgets)var t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0;else t=0;return!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.getRowLineCount=function(e){return!this.$useWrapMode||!this.$wrapData[e]?1:this.$wrapData[e].length+1},this.getRowWrapIndent=function(e){if(this.$useWrapMode){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE),n=this.$wrapData[t.row];return n.length&&n[0]=0)var o=a[f],r=this.$docRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getLength()-1,p=this.getNextFoldLine(r),d=p?p.start.row:Infinity;while(o<=e){u=this.getRowLength(r);if(o+u>e||r>=h)break;o+=u,r++,r>d&&(r=p.end.row+1,p=this.getNextFoldLine(r,p),d=p?p.start.row:Infinity),c&&(this.$docRowCache.push(r),this.$screenRowCache.push(o))}if(p&&p.start.row<=r)n=this.getFoldDisplayLine(p),r=p.start.row;else{if(o+u<=e||r>h)return{row:h,column:this.getLine(h).length};n=this.getLine(r),p=null}var v=0;if(this.$useWrapMode){var m=this.$wrapData[r];if(m){var g=Math.floor(e-o);s=m[g],g>0&&m.length&&(v=m.indent,i=m[g-1]||m[m.length-1],n=n.substring(i))}}return i+=this.$getStringScreenWidth(n,t-v)[1],this.$useWrapMode&&i>=s&&(i=s-1),p?p.idxToPosition(i):{row:r,column:i}},this.documentToScreenPosition=function(e,t){if(typeof t=="undefined")var n=this.$clipPositionToDocument(e.row,e.column);else n=this.$clipPositionToDocument(e,t);e=n.row,t=n.column;var r=0,i=null,s=null;s=this.getFoldAt(e,t,1),s&&(e=s.start.row,t=s.start.column);var o,u=0,a=this.$docRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var u=a[f],r=this.$screenRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getNextFoldLine(u),p=h?h.start.row:Infinity;while(u=p){o=h.end.row+1;if(o>e)break;h=this.getNextFoldLine(o,h),p=h?h.start.row:Infinity}else o=u+1;r+=this.getRowLength(u),u=o,c&&(this.$docRowCache.push(u),this.$screenRowCache.push(r))}var d="";h&&u>=p?(d=this.getFoldDisplayLine(h,e,t),i=h.start.row):(d=this.getLine(e).substring(0,t),i=e);var v=0;if(this.$useWrapMode){var m=this.$wrapData[i];if(m){var g=0;while(d.length>=m[g])r++,g++;d=d.substring(m[g-1]||0,d.length),v=g>0?m.indent:0}}return{row:r,column:v+this.$getStringScreenWidth(d)[0]}},this.documentToScreenColumn=function(e,t){return this.documentToScreenPosition(e,t).column},this.documentToScreenRow=function(e,t){return this.documentToScreenPosition(e,t).row},this.getScreenLength=function(){var e=0,t=null;if(!this.$useWrapMode){e=this.getLength();var n=this.$foldData;for(var r=0;ro&&(s=t.end.row+1,t=this.$foldData[r++],o=t?t.start.row:Infinity)}}return this.lineWidgets&&(e+=this.$getWidgetScreenLength()),e},this.$setFontMetrics=function(e){if(!this.$enableVarChar)return;this.$getStringScreenWidth=function(t,n,r){if(n===0)return[0,0];n||(n=Infinity),r=r||0;var i,s;for(s=0;sn)break}return[r,s]}},this.destroy=function(){this.bgTokenizer&&(this.bgTokenizer.setDocument(null),this.bgTokenizer=null),this.$stopWorker()}}).call(p.prototype),e("./edit_session/folding").Folding.call(p.prototype),e("./edit_session/bracket_match").BracketMatch.call(p.prototype),s.defineOptions(p.prototype,"session",{wrap:{set:function(e){!e||e=="off"?e=!1:e=="free"?e=!0:e=="printMargin"?e=-1:typeof e=="string"&&(e=parseInt(e,10)||!1);if(this.$wrap==e)return;this.$wrap=e;if(!e)this.setUseWrapMode(!1);else{var t=typeof e=="number"?e:null;this.setWrapLimitRange(t,t),this.setUseWrapMode(!0)}},get:function(){return this.getUseWrapMode()?this.$wrap==-1?"printMargin":this.getWrapLimitRange().min?this.$wrap:"free":"off"},handlesSet:!0},wrapMethod:{set:function(e){e=e=="auto"?this.$mode.type!="text":e!="text",e!=this.$wrapAsCode&&(this.$wrapAsCode=e,this.$useWrapMode&&(this.$modified=!0,this.$resetRowCache(0),this.$updateWrapData(0,this.getLength()-1)))},initialValue:"auto"},indentedSoftWrap:{initialValue:!0},firstLineNumber:{set:function(){this._signal("changeBreakpoint")},initialValue:1},useWorker:{set:function(e){this.$useWorker=e,this.$stopWorker(),e&&this.$startWorker()},initialValue:!0},useSoftTabs:{initialValue:!0},tabSize:{set:function(e){if(isNaN(e)||this.$tabSize===e)return;this.$modified=!0,this.$rowLengthCache=[],this.$tabSize=e,this._signal("changeTabSize")},initialValue:4,handlesSet:!0},overwrite:{set:function(e){this._signal("changeOverwrite")},initialValue:!1},newLineMode:{set:function(e){this.doc.setNewLineMode(e)},get:function(){return this.doc.getNewLineMode()},handlesSet:!0},mode:{set:function(e){this.setMode(e)},get:function(){return this.$modeId}}}),t.EditSession=p}),ace.define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(){this.$options={}};(function(){this.set=function(e){return i.mixin(this.$options,e),this},this.getOptions=function(){return r.copyObject(this.$options)},this.setOptions=function(e){this.$options=e},this.find=function(e){var t=this.$options,n=this.$matchIterator(e,t);if(!n)return!1;var r=null;return n.forEach(function(e,n,i){if(!e.start){var o=e.offset+(i||0);r=new s(n,o,n,o+e.length);if(!e.length&&t.start&&t.start.start&&t.skipCurrent!=0&&r.isEqual(t.start))return r=null,!1}else r=e;return!0}),r},this.findAll=function(e){var t=this.$options;if(!t.needle)return[];this.$assembleRegExp(t);var n=t.range,i=n?e.getLines(n.start.row,n.end.row):e.doc.getAllLines(),o=[],u=t.re;if(t.$isMultiLine){var a=u.length,f=i.length-a,l;e:for(var c=u.offset||0;c<=f;c++){for(var h=0;hv)continue;o.push(l=new s(c,v,c+a-1,m)),a>2&&(c=c+a-2)}}else for(var g=0;gE&&o[h].end.row==n.end.row)h--;o=o.slice(g,h+1);for(g=0,h=o.length;g=0;u--)if(i(o[u],t,s))return!0};else var u=function(e,t,s){var o=r.getMatchOffsets(e,n);for(var u=0;u=o;r--)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=u,o=s.row;r>=o;r--)if(n(e.getLine(r),r))return}:function(n){var r=s.row,i=e.getLine(r).substr(s.column);if(n(i,r,s.column))return;for(r+=1;r<=u;r++)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=o,u=s.row;r<=u;r++)if(n(e.getLine(r),r))return};return{forEach:a}}}).call(o.prototype),t.Search=o}),ace.define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function o(e,t){this.platform=t||(i.isMac?"mac":"win"),this.commands={},this.commandKeyBinding={},this.addCommands(e),this.$singleCommand=!0}function u(e,t){o.call(this,e,t),this.$singleCommand=!1}var r=e("../lib/keys"),i=e("../lib/useragent"),s=r.KEY_MODS;u.prototype=o.prototype,function(){function e(e){return typeof e=="object"&&e.bindKey&&e.bindKey.position||0}this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),this.commands[e.name]=e,e.bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e,t){var n=e&&(typeof e=="string"?e:e.name);e=this.commands[n],t||delete this.commands[n];var r=this.commandKeyBinding;for(var i in r){var s=r[i];if(s==e)delete r[i];else if(Array.isArray(s)){var o=s.indexOf(e);o!=-1&&(s.splice(o,1),s.length==1&&(r[i]=s[0]))}}},this.bindKey=function(e,t,n){typeof e=="object"&&e&&(n==undefined&&(n=e.position),e=e[this.platform]);if(!e)return;if(typeof t=="function")return this.addCommand({exec:t,bindKey:e,name:t.name||e});e.split("|").forEach(function(e){var r="";if(e.indexOf(" ")!=-1){var i=e.split(/\s+/);e=i.pop(),i.forEach(function(e){var t=this.parseKeys(e),n=s[t.hashId]+t.key;r+=(r?" ":"")+n,this._addCommandToBinding(r,"chainKeys")},this),r+=" "}var o=this.parseKeys(e),u=s[o.hashId]+o.key;this._addCommandToBinding(r+u,t,n)},this)},this._addCommandToBinding=function(t,n,r){var i=this.commandKeyBinding,s;if(!n)delete i[t];else if(!i[t]||this.$singleCommand)i[t]=n;else{Array.isArray(i[t])?(s=i[t].indexOf(n))!=-1&&i[t].splice(s,1):i[t]=[i[t]],typeof r!="number"&&(r||n.isDefault?r=-100:r=e(n));var o=i[t];for(s=0;sr)break}o.splice(s,0,n)}},this.addCommands=function(e){e&&Object.keys(e).forEach(function(t){var n=e[t];if(!n)return;if(typeof n=="string")return this.bindKey(n,t);typeof n=="function"&&(n={exec:n});if(typeof n!="object")return;n.name||(n.name=t),this.addCommand(n)},this)},this.removeCommands=function(e){Object.keys(e).forEach(function(t){this.removeCommand(e[t])},this)},this.bindKeys=function(e){Object.keys(e).forEach(function(t){this.bindKey(t,e[t])},this)},this._buildKeyHash=function(e){this.bindKey(e.bindKey,e)},this.parseKeys=function(e){var t=e.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(e){return e}),n=t.pop(),i=r[n];if(r.FUNCTION_KEYS[i])n=r.FUNCTION_KEYS[i].toLowerCase();else{if(!t.length)return{key:n,hashId:-1};if(t.length==1&&t[0]=="shift")return{key:n.toUpperCase(),hashId:-1}}var s=0;for(var o=t.length;o--;){var u=r.KEY_MODS[t[o]];if(u==null)return typeof console!="undefined"&&console.error("invalid modifier "+t[o]+" in "+e),!1;s|=u}return{key:n,hashId:s}},this.findKeyCommand=function(t,n){var r=s[t]+n;return this.commandKeyBinding[r]},this.handleKeyboard=function(e,t,n,r){if(r<0)return;var i=s[t]+n,o=this.commandKeyBinding[i];e.$keyChain&&(e.$keyChain+=" "+i,o=this.commandKeyBinding[e.$keyChain]||o);if(o)if(o=="chainKeys"||o[o.length-1]=="chainKeys")return e.$keyChain=e.$keyChain||i,{command:"null"};if(e.$keyChain)if(!!t&&t!=4||n.length!=1){if(t==-1||r>0)e.$keyChain=""}else e.$keyChain=e.$keyChain.slice(0,-i.length-1);return{command:o}},this.getStatusText=function(e,t){return t.$keyChain||""}}.call(o.prototype),t.HashHandler=o,t.MultiHashHandler=u}),ace.define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../keyboard/hash_handler").MultiHashHandler,s=e("../lib/event_emitter").EventEmitter,o=function(e,t){i.call(this,t,e),this.byName=this.commands,this.setDefaultHandler("exec",function(e){return e.command.exec(e.editor,e.args||{})})};r.inherits(o,i),function(){r.implement(this,s),this.exec=function(e,t,n){if(Array.isArray(e)){for(var r=e.length;r--;)if(this.exec(e[r],t,n))return!0;return!1}typeof e=="string"&&(e=this.commands[e]);if(!e)return!1;if(t&&t.$readOnly&&!e.readOnly)return!1;var i={editor:t,command:e,args:n};return i.returnValue=this._emit("exec",i),this._signal("afterExec",i),i.returnValue===!1?!1:!0},this.toggleRecording=function(e){if(this.$inReplay)return;return e&&e._emit("changeStatus"),this.recording?(this.macro.pop(),this.removeEventListener("exec",this.$addCommandToMacro),this.macro.length||(this.macro=this.oldMacro),this.recording=!1):(this.$addCommandToMacro||(this.$addCommandToMacro=function(e){this.macro.push([e.command,e.args])}.bind(this)),this.oldMacro=this.macro,this.macro=[],this.on("exec",this.$addCommandToMacro),this.recording=!0)},this.replay=function(e){if(this.$inReplay||!this.macro)return;if(this.recording)return this.toggleRecording(e);try{this.$inReplay=!0,this.macro.forEach(function(t){typeof t=="string"?this.exec(t,e):this.exec(t[0],e,t[1])},this)}finally{this.$inReplay=!1}},this.trimMacro=function(e){return e.map(function(e){return typeof e[0]!="string"&&(e[0]=e[0].name),e[1]||(e=e[0]),e})}}.call(o.prototype),t.CommandManager=o}),ace.define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"],function(e,t,n){"use strict";function o(e,t){return{win:e,mac:t}}var r=e("../lib/lang"),i=e("../config"),s=e("../range").Range;t.commands=[{name:"showSettingsMenu",bindKey:o("Ctrl-,","Command-,"),exec:function(e){i.loadModule("ace/ext/settings_menu",function(t){t.init(e),e.showSettingsMenu()})},readOnly:!0},{name:"goToNextError",bindKey:o("Alt-E","Ctrl-E"),exec:function(e){i.loadModule("ace/ext/error_marker",function(t){t.showErrorMarker(e,1)})},scrollIntoView:"animate",readOnly:!0},{name:"goToPreviousError",bindKey:o("Alt-Shift-E","Ctrl-Shift-E"),exec:function(e){i.loadModule("ace/ext/error_marker",function(t){t.showErrorMarker(e,-1)})},scrollIntoView:"animate",readOnly:!0},{name:"selectall",bindKey:o("Ctrl-A","Command-A"),exec:function(e){e.selectAll()},readOnly:!0},{name:"centerselection",bindKey:o(null,"Ctrl-L"),exec:function(e){e.centerSelection()},readOnly:!0},{name:"gotoline",bindKey:o("Ctrl-L","Command-L"),exec:function(e){var t=parseInt(prompt("Enter line number:"),10);isNaN(t)||e.gotoLine(t)},readOnly:!0},{name:"fold",bindKey:o("Alt-L|Ctrl-F1","Command-Alt-L|Command-F1"),exec:function(e){e.session.toggleFold(!1)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"unfold",bindKey:o("Alt-Shift-L|Ctrl-Shift-F1","Command-Alt-Shift-L|Command-Shift-F1"),exec:function(e){e.session.toggleFold(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleFoldWidget",bindKey:o("F2","F2"),exec:function(e){e.session.toggleFoldWidget()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleParentFoldWidget",bindKey:o("Alt-F2","Alt-F2"),exec:function(e){e.session.toggleFoldWidget(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"foldall",bindKey:o(null,"Ctrl-Command-Option-0"),exec:function(e){e.session.foldAll()},scrollIntoView:"center",readOnly:!0},{name:"foldOther",bindKey:o("Alt-0","Command-Option-0"),exec:function(e){e.session.foldAll(),e.session.unfold(e.selection.getAllRanges())},scrollIntoView:"center",readOnly:!0},{name:"unfoldall",bindKey:o("Alt-Shift-0","Command-Option-Shift-0"),exec:function(e){e.session.unfold()},scrollIntoView:"center",readOnly:!0},{name:"findnext",bindKey:o("Ctrl-K","Command-G"),exec:function(e){e.findNext()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"findprevious",bindKey:o("Ctrl-Shift-K","Command-Shift-G"),exec:function(e){e.findPrevious()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"selectOrFindNext",bindKey:o("Alt-K","Ctrl-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findNext()},readOnly:!0},{name:"selectOrFindPrevious",bindKey:o("Alt-Shift-K","Ctrl-Shift-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findPrevious()},readOnly:!0},{name:"find",bindKey:o("Ctrl-F","Command-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e)})},readOnly:!0},{name:"overwrite",bindKey:"Insert",exec:function(e){e.toggleOverwrite()},readOnly:!0},{name:"selecttostart",bindKey:o("Ctrl-Shift-Home","Command-Shift-Up"),exec:function(e){e.getSelection().selectFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotostart",bindKey:o("Ctrl-Home","Command-Home|Command-Up"),exec:function(e){e.navigateFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectup",bindKey:o("Shift-Up","Shift-Up"),exec:function(e){e.getSelection().selectUp()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golineup",bindKey:o("Up","Up|Ctrl-P"),exec:function(e,t){e.navigateUp(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttoend",bindKey:o("Ctrl-Shift-End","Command-Shift-Down"),exec:function(e){e.getSelection().selectFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotoend",bindKey:o("Ctrl-End","Command-End|Command-Down"),exec:function(e){e.navigateFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectdown",bindKey:o("Shift-Down","Shift-Down"),exec:function(e){e.getSelection().selectDown()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golinedown",bindKey:o("Down","Down|Ctrl-N"),exec:function(e,t){e.navigateDown(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordleft",bindKey:o("Ctrl-Shift-Left","Option-Shift-Left"),exec:function(e){e.getSelection().selectWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordleft",bindKey:o("Ctrl-Left","Option-Left"),exec:function(e){e.navigateWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolinestart",bindKey:o("Alt-Shift-Left","Command-Shift-Left"),exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolinestart",bindKey:o("Alt-Left|Home","Command-Left|Home|Ctrl-A"),exec:function(e){e.navigateLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectleft",bindKey:o("Shift-Left","Shift-Left"),exec:function(e){e.getSelection().selectLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoleft",bindKey:o("Left","Left|Ctrl-B"),exec:function(e,t){e.navigateLeft(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordright",bindKey:o("Ctrl-Shift-Right","Option-Shift-Right"),exec:function(e){e.getSelection().selectWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordright",bindKey:o("Ctrl-Right","Option-Right"),exec:function(e){e.navigateWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolineend",bindKey:o("Alt-Shift-Right","Command-Shift-Right"),exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolineend",bindKey:o("Alt-Right|End","Command-Right|End|Ctrl-E"),exec:function(e){e.navigateLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectright",bindKey:o("Shift-Right","Shift-Right"),exec:function(e){e.getSelection().selectRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoright",bindKey:o("Right","Right|Ctrl-F"),exec:function(e,t){e.navigateRight(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectpagedown",bindKey:"Shift-PageDown",exec:function(e){e.selectPageDown()},readOnly:!0},{name:"pagedown",bindKey:o(null,"Option-PageDown"),exec:function(e){e.scrollPageDown()},readOnly:!0},{name:"gotopagedown",bindKey:o("PageDown","PageDown|Ctrl-V"),exec:function(e){e.gotoPageDown()},readOnly:!0},{name:"selectpageup",bindKey:"Shift-PageUp",exec:function(e){e.selectPageUp()},readOnly:!0},{name:"pageup",bindKey:o(null,"Option-PageUp"),exec:function(e){e.scrollPageUp()},readOnly:!0},{name:"gotopageup",bindKey:"PageUp",exec:function(e){e.gotoPageUp()},readOnly:!0},{name:"scrollup",bindKey:o("Ctrl-Up",null),exec:function(e){e.renderer.scrollBy(0,-2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"scrolldown",bindKey:o("Ctrl-Down",null),exec:function(e){e.renderer.scrollBy(0,2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"selectlinestart",bindKey:"Shift-Home",exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectlineend",bindKey:"Shift-End",exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"togglerecording",bindKey:o("Ctrl-Alt-E","Command-Option-E"),exec:function(e){e.commands.toggleRecording(e)},readOnly:!0},{name:"replaymacro",bindKey:o("Ctrl-Shift-E","Command-Shift-E"),exec:function(e){e.commands.replay(e)},readOnly:!0},{name:"jumptomatching",bindKey:o("Ctrl-P","Ctrl-P"),exec:function(e){e.jumpToMatching()},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"selecttomatching",bindKey:o("Ctrl-Shift-P","Ctrl-Shift-P"),exec:function(e){e.jumpToMatching(!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"expandToMatching",bindKey:o("Ctrl-Shift-M","Ctrl-Shift-M"),exec:function(e){e.jumpToMatching(!0,!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"passKeysToBrowser",bindKey:o(null,null),exec:function(){},passEvent:!0,readOnly:!0},{name:"copy",exec:function(e){},readOnly:!0},{name:"cut",exec:function(e){var t=e.getSelectionRange();e._emit("cut",t),e.selection.isEmpty()||(e.session.remove(t),e.clearSelection())},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"paste",exec:function(e,t){e.$handlePaste(t)},scrollIntoView:"cursor"},{name:"removeline",bindKey:o("Ctrl-D","Command-D"),exec:function(e){e.removeLines()},scrollIntoView:"cursor",multiSelectAction:"forEachLine"},{name:"duplicateSelection",bindKey:o("Ctrl-Shift-D","Command-Shift-D"),exec:function(e){e.duplicateSelection()},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"sortlines",bindKey:o("Ctrl-Alt-S","Command-Alt-S"),exec:function(e){e.sortLines()},scrollIntoView:"selection",multiSelectAction:"forEachLine"},{name:"togglecomment",bindKey:o("Ctrl-/","Command-/"),exec:function(e){e.toggleCommentLines()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"toggleBlockComment",bindKey:o("Ctrl-Shift-/","Command-Shift-/"),exec:function(e){e.toggleBlockComment()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"modifyNumberUp",bindKey:o("Ctrl-Shift-Up","Alt-Shift-Up"),exec:function(e){e.modifyNumber(1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"modifyNumberDown",bindKey:o("Ctrl-Shift-Down","Alt-Shift-Down"),exec:function(e){e.modifyNumber(-1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"replace",bindKey:o("Ctrl-H","Command-Option-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e,!0)})}},{name:"undo",bindKey:o("Ctrl-Z","Command-Z"),exec:function(e){e.undo()}},{name:"redo",bindKey:o("Ctrl-Shift-Z|Ctrl-Y","Command-Shift-Z|Command-Y"),exec:function(e){e.redo()}},{name:"copylinesup",bindKey:o("Alt-Shift-Up","Command-Option-Up"),exec:function(e){e.copyLinesUp()},scrollIntoView:"cursor"},{name:"movelinesup",bindKey:o("Alt-Up","Option-Up"),exec:function(e){e.moveLinesUp()},scrollIntoView:"cursor"},{name:"copylinesdown",bindKey:o("Alt-Shift-Down","Command-Option-Down"),exec:function(e){e.copyLinesDown()},scrollIntoView:"cursor"},{name:"movelinesdown",bindKey:o("Alt-Down","Option-Down"),exec:function(e){e.moveLinesDown()},scrollIntoView:"cursor"},{name:"del",bindKey:o("Delete","Delete|Ctrl-D|Shift-Delete"),exec:function(e){e.remove("right")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"backspace",bindKey:o("Shift-Backspace|Backspace","Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H"),exec:function(e){e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"cut_or_delete",bindKey:o("Shift-Delete",null),exec:function(e){if(!e.selection.isEmpty())return!1;e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolinestart",bindKey:o("Alt-Backspace","Command-Backspace"),exec:function(e){e.removeToLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolineend",bindKey:o("Alt-Delete","Ctrl-K"),exec:function(e){e.removeToLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordleft",bindKey:o("Ctrl-Backspace","Alt-Backspace|Ctrl-Alt-Backspace"),exec:function(e){e.removeWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordright",bindKey:o("Ctrl-Delete","Alt-Delete"),exec:function(e){e.removeWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"outdent",bindKey:o("Shift-Tab","Shift-Tab"),exec:function(e){e.blockOutdent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"indent",bindKey:o("Tab","Tab"),exec:function(e){e.indent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"blockoutdent",bindKey:o("Ctrl-[","Ctrl-["),exec:function(e){e.blockOutdent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"blockindent",bindKey:o("Ctrl-]","Ctrl-]"),exec:function(e){e.blockIndent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"insertstring",exec:function(e,t){e.insert(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"inserttext",exec:function(e,t){e.insert(r.stringRepeat(t.text||"",t.times||1))},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"splitline",bindKey:o(null,"Ctrl-O"),exec:function(e){e.splitLine()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"transposeletters",bindKey:o("Ctrl-T","Ctrl-T"),exec:function(e){e.transposeLetters()},multiSelectAction:function(e){e.transposeSelections(1)},scrollIntoView:"cursor"},{name:"touppercase",bindKey:o("Ctrl-U","Ctrl-U"),exec:function(e){e.toUpperCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"tolowercase",bindKey:o("Ctrl-Shift-U","Ctrl-Shift-U"),exec:function(e){e.toLowerCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"expandtoline",bindKey:o("Ctrl-Shift-L","Command-Shift-L"),exec:function(e){var t=e.selection.getRange();t.start.column=t.end.column=0,t.end.row++,e.selection.setRange(t,!1)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"joinlines",bindKey:o(null,null),exec:function(e){var t=e.selection.isBackwards(),n=t?e.selection.getSelectionLead():e.selection.getSelectionAnchor(),i=t?e.selection.getSelectionAnchor():e.selection.getSelectionLead(),o=e.session.doc.getLine(n.row).length,u=e.session.doc.getTextRange(e.selection.getRange()),a=u.replace(/\n\s*/," ").length,f=e.session.doc.getLine(n.row);for(var l=n.row+1;l<=i.row+1;l++){var c=r.stringTrimLeft(r.stringTrimRight(e.session.doc.getLine(l)));c.length!==0&&(c=" "+c),f+=c}i.row+10?(e.selection.moveCursorTo(n.row,n.column),e.selection.selectTo(n.row,n.column+a)):(o=e.session.doc.getLine(n.row).length>o?o+1:o,e.selection.moveCursorTo(n.row,o))},multiSelectAction:"forEach",readOnly:!0},{name:"invertSelection",bindKey:o(null,null),exec:function(e){var t=e.session.doc.getLength()-1,n=e.session.doc.getLine(t).length,r=e.selection.rangeList.ranges,i=[];r.length<1&&(r=[e.selection.getRange()]);for(var o=0;o0&&this.$blockScrolling--;var n=t&&t.scrollIntoView;if(n){switch(n){case"center-animate":n="animate";case"center":this.renderer.scrollCursorIntoView(null,.5);break;case"animate":case"cursor":this.renderer.scrollCursorIntoView();break;case"selectionPart":var r=this.selection.getRange(),i=this.renderer.layerConfig;(r.start.row>=i.lastRow||r.end.row<=i.firstRow)&&this.renderer.scrollSelectionIntoView(this.selection.anchor,this.selection.lead);break;default:}n=="animate"&&this.renderer.animateScrolling(this.curOp.scrollTop)}this.prevOp=this.curOp,this.curOp=null}},this.$mergeableCommands=["backspace","del","insertstring"],this.$historyTracker=function(e){if(!this.$mergeUndoDeltas)return;var t=this.prevOp,n=this.$mergeableCommands,r=t.command&&e.command.name==t.command.name;if(e.command.name=="insertstring"){var i=e.args;this.mergeNextCommand===undefined&&(this.mergeNextCommand=!0),r=r&&this.mergeNextCommand&&(!/\s/.test(i)||/\s/.test(t.args)),this.mergeNextCommand=!0}else r=r&&n.indexOf(e.command.name)!==-1;this.$mergeUndoDeltas!="always"&&Date.now()-this.sequenceStartTime>2e3&&(r=!1),r?this.session.mergeUndoDeltas=!0:n.indexOf(e.command.name)!==-1&&(this.sequenceStartTime=Date.now())},this.setKeyboardHandler=function(e,t){if(e&&typeof e=="string"){this.$keybindingId=e;var n=this;g.loadModule(["keybinding",e],function(r){n.$keybindingId==e&&n.keyBinding.setKeyboardHandler(r&&r.handler),t&&t()})}else this.$keybindingId=null,this.keyBinding.setKeyboardHandler(e),t&&t()},this.getKeyboardHandler=function(){return this.keyBinding.getKeyboardHandler()},this.setSession=function(e){if(this.session==e)return;this.curOp&&this.endOperation(),this.curOp={};var t=this.session;if(t){this.session.off("change",this.$onDocumentChange),this.session.off("changeMode",this.$onChangeMode),this.session.off("tokenizerUpdate",this.$onTokenizerUpdate),this.session.off("changeTabSize",this.$onChangeTabSize),this.session.off("changeWrapLimit",this.$onChangeWrapLimit),this.session.off("changeWrapMode",this.$onChangeWrapMode),this.session.off("changeFold",this.$onChangeFold),this.session.off("changeFrontMarker",this.$onChangeFrontMarker),this.session.off("changeBackMarker",this.$onChangeBackMarker),this.session.off("changeBreakpoint",this.$onChangeBreakpoint),this.session.off("changeAnnotation",this.$onChangeAnnotation),this.session.off("changeOverwrite",this.$onCursorChange),this.session.off("changeScrollTop",this.$onScrollTopChange),this.session.off("changeScrollLeft",this.$onScrollLeftChange);var n=this.session.getSelection();n.off("changeCursor",this.$onCursorChange),n.off("changeSelection",this.$onSelectionChange)}this.session=e,e?(this.$onDocumentChange=this.onDocumentChange.bind(this),e.on("change",this.$onDocumentChange),this.renderer.setSession(e),this.$onChangeMode=this.onChangeMode.bind(this),e.on("changeMode",this.$onChangeMode),this.$onTokenizerUpdate=this.onTokenizerUpdate.bind(this),e.on("tokenizerUpdate",this.$onTokenizerUpdate),this.$onChangeTabSize=this.renderer.onChangeTabSize.bind(this.renderer),e.on("changeTabSize",this.$onChangeTabSize),this.$onChangeWrapLimit=this.onChangeWrapLimit.bind(this),e.on("changeWrapLimit",this.$onChangeWrapLimit),this.$onChangeWrapMode=this.onChangeWrapMode.bind(this),e.on("changeWrapMode",this.$onChangeWrapMode),this.$onChangeFold=this.onChangeFold.bind(this),e.on("changeFold",this.$onChangeFold),this.$onChangeFrontMarker=this.onChangeFrontMarker.bind(this),this.session.on("changeFrontMarker",this.$onChangeFrontMarker),this.$onChangeBackMarker=this.onChangeBackMarker.bind(this),this.session.on("changeBackMarker",this.$onChangeBackMarker),this.$onChangeBreakpoint=this.onChangeBreakpoint.bind(this),this.session.on("changeBreakpoint",this.$onChangeBreakpoint),this.$onChangeAnnotation=this.onChangeAnnotation.bind(this),this.session.on("changeAnnotation",this.$onChangeAnnotation),this.$onCursorChange=this.onCursorChange.bind(this),this.session.on("changeOverwrite",this.$onCursorChange),this.$onScrollTopChange=this.onScrollTopChange.bind(this),this.session.on("changeScrollTop",this.$onScrollTopChange),this.$onScrollLeftChange=this.onScrollLeftChange.bind(this),this.session.on("changeScrollLeft",this.$onScrollLeftChange),this.selection=e.getSelection(),this.selection.on("changeCursor",this.$onCursorChange),this.$onSelectionChange=this.onSelectionChange.bind(this),this.selection.on("changeSelection",this.$onSelectionChange),this.onChangeMode(),this.$blockScrolling+=1,this.onCursorChange(),this.$blockScrolling-=1,this.onScrollTopChange(),this.onScrollLeftChange(),this.onSelectionChange(),this.onChangeFrontMarker(),this.onChangeBackMarker(),this.onChangeBreakpoint(),this.onChangeAnnotation(),this.session.getUseWrapMode()&&this.renderer.adjustWrapLimit(),this.renderer.updateFull()):(this.selection=null,this.renderer.setSession(e)),this._signal("changeSession",{session:e,oldSession:t}),this.curOp=null,t&&t._signal("changeEditor",{oldEditor:this}),e&&e._signal("changeEditor",{editor:this})},this.getSession=function(){return this.session},this.setValue=function(e,t){return this.session.doc.setValue(e),t?t==1?this.navigateFileEnd():t==-1&&this.navigateFileStart():this.selectAll(),e},this.getValue=function(){return this.session.getValue()},this.getSelection=function(){return this.selection},this.resize=function(e){this.renderer.onResize(e)},this.setTheme=function(e,t){this.renderer.setTheme(e,t)},this.getTheme=function(){return this.renderer.getTheme()},this.setStyle=function(e){this.renderer.setStyle(e)},this.unsetStyle=function(e){this.renderer.unsetStyle(e)},this.getFontSize=function(){return this.getOption("fontSize")||i.computedStyle(this.container,"fontSize")},this.setFontSize=function(e){this.setOption("fontSize",e)},this.$highlightBrackets=function(){this.session.$bracketHighlight&&(this.session.removeMarker(this.session.$bracketHighlight),this.session.$bracketHighlight=null);if(this.$highlightPending)return;var e=this;this.$highlightPending=!0,setTimeout(function(){e.$highlightPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=t.findMatchingBracket(e.getCursorPosition());if(n)var r=new p(n.row,n.column,n.row,n.column+1);else if(t.$mode.getMatching)var r=t.$mode.getMatching(e.session);r&&(t.$bracketHighlight=t.addMarker(r,"ace_bracket","text"))},50)},this.$highlightTags=function(){if(this.$highlightTagPending)return;var e=this;this.$highlightTagPending=!0,setTimeout(function(){e.$highlightTagPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=e.getCursorPosition(),r=new y(e.session,n.row,n.column),i=r.getCurrentToken();if(!i||!/\b(?:tag-open|tag-name)/.test(i.type)){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}if(i.type.indexOf("tag-open")!=-1){i=r.stepForward();if(!i)return}var s=i.value,o=0,u=r.stepBackward();if(u.value=="<"){do u=i,i=r.stepForward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value===""&&o--);while(i&&o>=0)}else{do i=u,u=r.stepBackward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value===""&&o--);while(u&&o<=0);r.stepForward()}if(!i){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}var a=r.getCurrentTokenRow(),f=r.getCurrentTokenColumn(),l=new p(a,f,a,f+i.value.length);t.$tagHighlight&&l.compareRange(t.$backMarkers[t.$tagHighlight].range)!==0&&(t.removeMarker(t.$tagHighlight),t.$tagHighlight=null),l&&!t.$tagHighlight&&(t.$tagHighlight=t.addMarker(l,"ace_bracket","text"))},50)},this.focus=function(){var e=this;setTimeout(function(){e.textInput.focus()}),this.textInput.focus()},this.isFocused=function(){return this.textInput.isFocused()},this.blur=function(){this.textInput.blur()},this.onFocus=function(e){if(this.$isFocused)return;this.$isFocused=!0,this.renderer.showCursor(),this.renderer.visualizeFocus(),this._emit("focus",e)},this.onBlur=function(e){if(!this.$isFocused)return;this.$isFocused=!1,this.renderer.hideCursor(),this.renderer.visualizeBlur(),this._emit("blur",e)},this.$cursorChange=function(){this.renderer.updateCursor()},this.onDocumentChange=function(e){var t=this.session.$useWrapMode,n=e.start.row==e.end.row?e.end.row:Infinity;this.renderer.updateLines(e.start.row,n,t),this._signal("change",e),this.$cursorChange(),this.$updateHighlightActiveLine()},this.onTokenizerUpdate=function(e){var t=e.data;this.renderer.updateLines(t.first,t.last)},this.onScrollTopChange=function(){this.renderer.scrollToY(this.session.getScrollTop())},this.onScrollLeftChange=function(){this.renderer.scrollToX(this.session.getScrollLeft())},this.onCursorChange=function(){this.$cursorChange(),this.$blockScrolling||(g.warn("Automatically scrolling cursor into view after selection change","this will be disabled in the next version","set editor.$blockScrolling = Infinity to disable this message"),this.renderer.scrollCursorIntoView()),this.$highlightBrackets(),this.$highlightTags(),this.$updateHighlightActiveLine(),this._signal("changeSelection")},this.$updateHighlightActiveLine=function(){var e=this.getSession(),t;if(this.$highlightActiveLine){if(this.$selectionStyle!="line"||!this.selection.isMultiLine())t=this.getCursorPosition();this.renderer.$maxLines&&this.session.getLength()===1&&!(this.renderer.$minLines>1)&&(t=!1)}if(e.$highlightLineMarker&&!t)e.removeMarker(e.$highlightLineMarker.id),e.$highlightLineMarker=null;else if(!e.$highlightLineMarker&&t){var n=new p(t.row,t.column,t.row,Infinity);n.id=e.addMarker(n,"ace_active-line","screenLine"),e.$highlightLineMarker=n}else t&&(e.$highlightLineMarker.start.row=t.row,e.$highlightLineMarker.end.row=t.row,e.$highlightLineMarker.start.column=t.column,e._signal("changeBackMarker"))},this.onSelectionChange=function(e){var t=this.session;t.$selectionMarker&&t.removeMarker(t.$selectionMarker),t.$selectionMarker=null;if(!this.selection.isEmpty()){var n=this.selection.getRange(),r=this.getSelectionStyle();t.$selectionMarker=t.addMarker(n,"ace_selection",r)}else this.$updateHighlightActiveLine();var i=this.$highlightSelectedWord&&this.$getSelectionHighLightRegexp();this.session.highlight(i),this._signal("changeSelection")},this.$getSelectionHighLightRegexp=function(){var e=this.session,t=this.getSelectionRange();if(t.isEmpty()||t.isMultiLine())return;var n=t.start.column-1,r=t.end.column+1,i=e.getLine(t.start.row),s=i.length,o=i.substring(Math.max(n,0),Math.min(r,s));if(n>=0&&/^[\w\d]/.test(o)||r<=s&&/[\w\d]$/.test(o))return;o=i.substring(t.start.column,t.end.column);if(!/^[\w\d]+$/.test(o))return;var u=this.$search.$assembleRegExp({wholeWord:!0,caseSensitive:!0,needle:o});return u},this.onChangeFrontMarker=function(){this.renderer.updateFrontMarkers()},this.onChangeBackMarker=function(){this.renderer.updateBackMarkers()},this.onChangeBreakpoint=function(){this.renderer.updateBreakpoints()},this.onChangeAnnotation=function(){this.renderer.setAnnotations(this.session.getAnnotations())},this.onChangeMode=function(e){this.renderer.updateText(),this._emit("changeMode",e)},this.onChangeWrapLimit=function(){this.renderer.updateFull()},this.onChangeWrapMode=function(){this.renderer.onResize(!0)},this.onChangeFold=function(){this.$updateHighlightActiveLine(),this.renderer.updateFull()},this.getSelectedText=function(){return this.session.getTextRange(this.getSelectionRange())},this.getCopyText=function(){var e=this.getSelectedText();return this._signal("copy",e),e},this.onCopy=function(){this.commands.exec("copy",this)},this.onCut=function(){this.commands.exec("cut",this)},this.onPaste=function(e,t){var n={text:e,event:t};this.commands.exec("paste",this,n)},this.$handlePaste=function(e){typeof e=="string"&&(e={text:e}),this._signal("paste",e);var t=e.text;if(!this.inMultiSelectMode||this.inVirtualSelectionMode)this.insert(t);else{var n=t.split(/\r\n|\r|\n/),r=this.selection.rangeList.ranges;if(n.length>r.length||n.length<2||!n[1])return this.commands.exec("insertstring",this,t);for(var i=r.length;i--;){var s=r[i];s.isEmpty()||this.session.remove(s),this.session.insert(s.start,n[i])}}},this.execCommand=function(e,t){return this.commands.exec(e,this,t)},this.insert=function(e,t){var n=this.session,r=n.getMode(),i=this.getCursorPosition();if(this.getBehavioursEnabled()&&!t){var s=r.transformAction(n.getState(i.row),"insertion",this,n,e);s&&(e!==s.text&&(this.session.mergeUndoDeltas=!1,this.$mergeNextCommand=!1),e=s.text)}e==" "&&(e=this.session.getTabString());if(!this.selection.isEmpty()){var o=this.getSelectionRange();i=this.session.remove(o),this.clearSelection()}else if(this.session.getOverwrite()){var o=new p.fromPoints(i,i);o.end.column+=e.length,this.session.remove(o)}if(e=="\n"||e=="\r\n"){var u=n.getLine(i.row);if(i.column>u.search(/\S|$/)){var a=u.substr(i.column).search(/\S|$/);n.doc.removeInLine(i.row,i.column,i.column+a)}}this.clearSelection();var f=i.column,l=n.getState(i.row),u=n.getLine(i.row),c=r.checkOutdent(l,u,e),h=n.insert(i,e);s&&s.selection&&(s.selection.length==2?this.selection.setSelectionRange(new p(i.row,f+s.selection[0],i.row,f+s.selection[1])):this.selection.setSelectionRange(new p(i.row+s.selection[0],s.selection[1],i.row+s.selection[2],s.selection[3])));if(n.getDocument().isNewLine(e)){var d=r.getNextLineIndent(l,u.slice(0,i.column),n.getTabString());n.insert({row:i.row+1,column:0},d)}c&&r.autoOutdent(l,n,i.row)},this.onTextInput=function(e){this.keyBinding.onTextInput(e)},this.onCommandKey=function(e,t,n){this.keyBinding.onCommandKey(e,t,n)},this.setOverwrite=function(e){this.session.setOverwrite(e)},this.getOverwrite=function(){return this.session.getOverwrite()},this.toggleOverwrite=function(){this.session.toggleOverwrite()},this.setScrollSpeed=function(e){this.setOption("scrollSpeed",e)},this.getScrollSpeed=function(){return this.getOption("scrollSpeed")},this.setDragDelay=function(e){this.setOption("dragDelay",e)},this.getDragDelay=function(){return this.getOption("dragDelay")},this.setSelectionStyle=function(e){this.setOption("selectionStyle",e)},this.getSelectionStyle=function(){return this.getOption("selectionStyle")},this.setHighlightActiveLine=function(e){this.setOption("highlightActiveLine",e)},this.getHighlightActiveLine=function(){return this.getOption("highlightActiveLine")},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.setHighlightSelectedWord=function(e){this.setOption("highlightSelectedWord",e)},this.getHighlightSelectedWord=function(){return this.$highlightSelectedWord},this.setAnimatedScroll=function(e){this.renderer.setAnimatedScroll(e)},this.getAnimatedScroll=function(){return this.renderer.getAnimatedScroll()},this.setShowInvisibles=function(e){this.renderer.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.renderer.getShowInvisibles()},this.setDisplayIndentGuides=function(e){this.renderer.setDisplayIndentGuides(e)},this.getDisplayIndentGuides=function(){return this.renderer.getDisplayIndentGuides()},this.setShowPrintMargin=function(e){this.renderer.setShowPrintMargin(e)},this.getShowPrintMargin=function(){return this.renderer.getShowPrintMargin()},this.setPrintMarginColumn=function(e){this.renderer.setPrintMarginColumn(e)},this.getPrintMarginColumn=function(){return this.renderer.getPrintMarginColumn()},this.setReadOnly=function(e){this.setOption("readOnly",e)},this.getReadOnly=function(){return this.getOption("readOnly")},this.setBehavioursEnabled=function(e){this.setOption("behavioursEnabled",e)},this.getBehavioursEnabled=function(){return this.getOption("behavioursEnabled")},this.setWrapBehavioursEnabled=function(e){this.setOption("wrapBehavioursEnabled",e)},this.getWrapBehavioursEnabled=function(){return this.getOption("wrapBehavioursEnabled")},this.setShowFoldWidgets=function(e){this.setOption("showFoldWidgets",e)},this.getShowFoldWidgets=function(){return this.getOption("showFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.remove=function(e){this.selection.isEmpty()&&(e=="left"?this.selection.selectLeft():this.selection.selectRight());var t=this.getSelectionRange();if(this.getBehavioursEnabled()){var n=this.session,r=n.getState(t.start.row),i=n.getMode().transformAction(r,"deletion",this,n,t);if(t.end.column===0){var s=n.getTextRange(t);if(s[s.length-1]=="\n"){var o=n.getLine(t.end.row);/^\s+$/.test(o)&&(t.end.column=o.length)}}i&&(t=i)}this.session.remove(t),this.clearSelection()},this.removeWordRight=function(){this.selection.isEmpty()&&this.selection.selectWordRight(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeWordLeft=function(){this.selection.isEmpty()&&this.selection.selectWordLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineStart=function(){this.selection.isEmpty()&&this.selection.selectLineStart(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineEnd=function(){this.selection.isEmpty()&&this.selection.selectLineEnd();var e=this.getSelectionRange();e.start.column==e.end.column&&e.start.row==e.end.row&&(e.end.column=0,e.end.row++),this.session.remove(e),this.clearSelection()},this.splitLine=function(){this.selection.isEmpty()||(this.session.remove(this.getSelectionRange()),this.clearSelection());var e=this.getCursorPosition();this.insert("\n"),this.moveCursorToPosition(e)},this.transposeLetters=function(){if(!this.selection.isEmpty())return;var e=this.getCursorPosition(),t=e.column;if(t===0)return;var n=this.session.getLine(e.row),r,i;tt.toLowerCase()?1:0});var r=new p(0,0,0,0);for(var i=e.first;i<=e.last;i++){var s=t.getLine(i);r.start.row=i,r.end.row=i,r.end.column=s.length,t.replace(r,n[i-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.toggleBlockComment=function(){var e=this.getCursorPosition(),t=this.session.getState(e.row),n=this.getSelectionRange();this.session.getMode().toggleBlockComment(t,this.session,n,e)},this.getNumberAt=function(e,t){var n=/[\-]?[0-9]+(?:\.[0-9]+)?/g;n.lastIndex=0;var r=this.session.getLine(e);while(n.lastIndex=t){var s={value:i[0],start:i.index,end:i.index+i[0].length};return s}}return null},this.modifyNumber=function(e){var t=this.selection.getCursor().row,n=this.selection.getCursor().column,r=new p(t,n-1,t,n),i=this.session.getTextRange(r);if(!isNaN(parseFloat(i))&&isFinite(i)){var s=this.getNumberAt(t,n);if(s){var o=s.value.indexOf(".")>=0?s.start+s.value.indexOf(".")+1:s.end,u=s.start+s.value.length-o,a=parseFloat(s.value);a*=Math.pow(10,u),o!==s.end&&np+1)break;p=d.last}l--,u=this.session.$moveLines(h,p,t?0:e),t&&e==-1&&(c=l+1);while(c<=l)o[c].moveBy(u,0),c++;t||(u=0),a+=u}i.fromOrientedRange(i.ranges[0]),i.rangeList.attach(this.session),this.inVirtualSelectionMode=!1}},this.$getSelectedRows=function(e){return e=(e||this.getSelectionRange()).collapseRows(),{first:this.session.getRowFoldStart(e.start.row),last:this.session.getRowFoldEnd(e.end.row)}},this.onCompositionStart=function(e){this.renderer.showComposition(this.getCursorPosition())},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var n=this.renderer,r=this.renderer.layerConfig,i=e*Math.floor(r.height/r.lineHeight);this.$blockScrolling++,t===!0?this.selection.$moveSelection(function(){this.moveCursorBy(i,0)}):t===!1&&(this.selection.moveCursorBy(i,0),this.selection.clearSelection()),this.$blockScrolling--;var s=n.scrollTop;n.scrollBy(0,i*r.lineHeight),t!=null&&n.scrollCursorIntoView(null,.5),n.animateScrolling(s)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,n,r){this.renderer.scrollToLine(e,t,n,r)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.$blockScrolling+=1,this.selection.selectAll(),this.$blockScrolling-=1},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e,t){var n=this.getCursorPosition(),r=new y(this.session,n.row,n.column),i=r.getCurrentToken(),s=i||r.stepForward();if(!s)return;var o,u=!1,a={},f=n.column-s.start,l,c={")":"(","(":"(","]":"[","[":"[","{":"{","}":"{"};do{if(s.value.match(/[{}()\[\]]/g))for(;f=0;--s)this.$tryReplace(n[s],e)&&r++;return this.selection.setSelectionRange(i),this.$blockScrolling-=1,r},this.$tryReplace=function(e,t){var n=this.session.getTextRange(e);return t=this.$search.replace(n,t),t!==null?(e.end=this.session.replace(e,t),e):null},this.getLastSearchOptions=function(){return this.$search.getOptions()},this.find=function(e,t,n){t||(t={}),typeof e=="string"||e instanceof RegExp?t.needle=e:typeof e=="object"&&r.mixin(t,e);var i=this.selection.getRange();t.needle==null&&(e=this.session.getTextRange(i)||this.$search.$options.needle,e||(i=this.session.getWordRange(i.start.row,i.start.column),e=this.session.getTextRange(i)),this.$search.set({needle:e})),this.$search.set(t),t.start||this.$search.set({start:i});var s=this.$search.find(this.session);if(t.preventScroll)return s;if(s)return this.revealRange(s,n),s;t.backwards?i.start=i.end:i.end=i.start,this.selection.setRange(i)},this.findNext=function(e,t){this.find({skipCurrent:!0,backwards:!1},e,t)},this.findPrevious=function(e,t){this.find(e,{skipCurrent:!0,backwards:!0},t)},this.revealRange=function(e,t){this.$blockScrolling+=1,this.session.unfold(e),this.selection.setSelectionRange(e),this.$blockScrolling-=1;var n=this.renderer.scrollTop;this.renderer.scrollSelectionIntoView(e.start,e.end,.5),t!==!1&&this.renderer.animateScrolling(n)},this.undo=function(){this.$blockScrolling++,this.session.getUndoManager().undo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.redo=function(){this.$blockScrolling++,this.session.getUndoManager().redo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.destroy=function(){this.renderer.destroy(),this._signal("destroy",this),this.session&&this.session.destroy()},this.setAutoScrollEditorIntoView=function(e){if(!e)return;var t,n=this,r=!1;this.$scrollAnchor||(this.$scrollAnchor=document.createElement("div"));var i=this.$scrollAnchor;i.style.cssText="position:absolute",this.container.insertBefore(i,this.container.firstChild);var s=this.on("changeSelection",function(){r=!0}),o=this.renderer.on("beforeRender",function(){r&&(t=n.renderer.container.getBoundingClientRect())}),u=this.renderer.on("afterRender",function(){if(r&&t&&(n.isFocused()||n.searchBox&&n.searchBox.isFocused())){var e=n.renderer,s=e.$cursorLayer.$pixelPos,o=e.layerConfig,u=s.top-o.offset;s.top>=0&&u+t.top<0?r=!0:s.topwindow.innerHeight?r=!1:r=null,r!=null&&(i.style.top=u+"px",i.style.left=s.left+"px",i.style.height=o.lineHeight+"px",i.scrollIntoView(r)),r=t=null}});this.setAutoScrollEditorIntoView=function(e){if(e)return;delete this.setAutoScrollEditorIntoView,this.off("changeSelection",s),this.renderer.off("afterRender",u),this.renderer.off("beforeRender",o)}},this.$resetCursorStyle=function(){var e=this.$cursorStyle||"ace",t=this.renderer.$cursorLayer;if(!t)return;t.setSmoothBlinking(/smooth/.test(e)),t.isBlinking=!this.$readOnly&&e!="wide",i.setCssClass(t.element,"ace_slim-cursors",/slim/.test(e))}}).call(b.prototype),g.defineOptions(b.prototype,"editor",{selectionStyle:{set:function(e){this.onSelectionChange(),this._signal("changeSelectionStyle",{data:e})},initialValue:"line"},highlightActiveLine:{set:function(){this.$updateHighlightActiveLine()},initialValue:!0},highlightSelectedWord:{set:function(e){this.$onSelectionChange()},initialValue:!0},readOnly:{set:function(e){this.$resetCursorStyle()},initialValue:!1},cursorStyle:{set:function(e){this.$resetCursorStyle()},values:["ace","slim","smooth","wide"],initialValue:"ace"},mergeUndoDeltas:{values:[!1,!0,"always"],initialValue:!0},behavioursEnabled:{initialValue:!0},wrapBehavioursEnabled:{initialValue:!0},autoScrollEditorIntoView:{set:function(e){this.setAutoScrollEditorIntoView(e)}},keyboardHandler:{set:function(e){this.setKeyboardHandler(e)},get:function(){return this.keybindingId},handlesSet:!0},hScrollBarAlwaysVisible:"renderer",vScrollBarAlwaysVisible:"renderer",highlightGutterLine:"renderer",animatedScroll:"renderer",showInvisibles:"renderer",showPrintMargin:"renderer",printMarginColumn:"renderer",printMargin:"renderer",fadeFoldWidgets:"renderer",showFoldWidgets:"renderer",showLineNumbers:"renderer",showGutter:"renderer",displayIndentGuides:"renderer",fontSize:"renderer",fontFamily:"renderer",maxLines:"renderer",minLines:"renderer",scrollPastEnd:"renderer",fixedWidthGutter:"renderer",theme:"renderer",scrollSpeed:"$mouseHandler",dragDelay:"$mouseHandler",dragEnabled:"$mouseHandler",focusTimout:"$mouseHandler",tooltipFollowsMouse:"$mouseHandler",firstLineNumber:"session",overwrite:"session",newLineMode:"session",useWorker:"session",useSoftTabs:"session",tabSize:"session",wrap:"session",indentedSoftWrap:"session",foldStyle:"session",mode:"session"}),t.Editor=b}),ace.define("ace/undomanager",["require","exports","module"],function(e,t,n){"use strict";var r=function(){this.reset()};(function(){function e(e){return{action:e.action,start:e.start,end:e.end,lines:e.lines.length==1?null:e.lines,text:e.lines.length==1?e.lines[0]:null}}function t(e){return{action:e.action,start:e.start,end:e.end,lines:e.lines||[e.text]}}function n(e,t){var n=new Array(e.length);for(var r=0;r0},this.hasRedo=function(){return this.$redoStack.length>0},this.markClean=function(){this.dirtyCounter=0},this.isClean=function(){return this.dirtyCounter===0},this.$serializeDeltas=function(t){return n(t,e)},this.$deserializeDeltas=function(e){return n(e,t)}}).call(r.prototype),t.UndoManager=r}),ace.define("ace/layer/gutter",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/lang"),o=e("../lib/event_emitter").EventEmitter,u=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_gutter-layer",e.appendChild(this.element),this.setShowFoldWidgets(this.$showFoldWidgets),this.gutterWidth=0,this.$annotations=[],this.$updateAnnotations=this.$updateAnnotations.bind(this),this.$cells=[]};(function(){i.implement(this,o),this.setSession=function(e){this.session&&this.session.removeEventListener("change",this.$updateAnnotations),this.session=e,e&&e.on("change",this.$updateAnnotations)},this.addGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.addGutterDecoration"),this.session.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.removeGutterDecoration"),this.session.removeGutterDecoration(e,t)},this.setAnnotations=function(e){this.$annotations=[];for(var t=0;to&&(v=s.end.row+1,s=t.getNextFoldLine(v,s),o=s?s.start.row:Infinity);if(v>i){while(this.$cells.length>d+1)p=this.$cells.pop(),this.element.removeChild(p.element);break}p=this.$cells[++d],p||(p={element:null,textNode:null,foldWidget:null},p.element=r.createElement("div"),p.textNode=document.createTextNode(""),p.element.appendChild(p.textNode),this.element.appendChild(p.element),this.$cells[d]=p);var m="ace_gutter-cell ";a[v]&&(m+=a[v]),f[v]&&(m+=f[v]),this.$annotations[v]&&(m+=this.$annotations[v].className),p.element.className!=m&&(p.element.className=m);var g=t.getRowLength(v)*e.lineHeight+"px";g!=p.element.style.height&&(p.element.style.height=g);if(u){var y=u[v];y==null&&(y=u[v]=t.getFoldWidget(v))}if(y){p.foldWidget||(p.foldWidget=r.createElement("span"),p.element.appendChild(p.foldWidget));var m="ace_fold-widget ace_"+y;y=="start"&&v==o&&vn.right-t.right)return"foldWidgets"}}).call(u.prototype),t.Gutter=u}),ace.define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../lib/dom"),s=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_marker-layer",e.appendChild(this.element)};(function(){function e(e,t,n,r){return(e?1:0)|(t?2:0)|(n?4:0)|(r?8:0)}this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.update=function(e){var e=e||this.config;if(!e)return;this.config=e;var t=[];for(var n in this.markers){var r=this.markers[n];if(!r.range){r.update(t,this,this.session,e);continue}var i=r.range.clipRows(e.firstRow,e.lastRow);if(i.isEmpty())continue;i=i.toScreenRange(this.session);if(r.renderer){var s=this.$getTop(i.start.row,e),o=this.$padding+i.start.column*e.characterWidth;r.renderer(t,i,o,s,e)}else r.type=="fullLine"?this.drawFullLineMarker(t,i,r.clazz,e):r.type=="screenLine"?this.drawScreenLineMarker(t,i,r.clazz,e):i.isMultiLine()?r.type=="text"?this.drawTextMarker(t,i,r.clazz,e):this.drawMultiLineMarker(t,i,r.clazz,e):this.drawSingleLineMarker(t,i,r.clazz+" ace_start"+" ace_br15",e)}this.element.innerHTML=t.join("")},this.$getTop=function(e,t){return(e-t.firstRowScreen)*t.lineHeight},this.drawTextMarker=function(t,n,i,s,o){var u=this.session,a=n.start.row,f=n.end.row,l=a,c=0,h=0,p=u.getScreenLastRowColumn(l),d=new r(l,n.start.column,l,h);for(;l<=f;l++)d.start.row=d.end.row=l,d.start.column=l==a?n.start.column:u.getRowWrapIndent(l),d.end.column=p,c=h,h=p,p=l+1p,l==f),s,l==f?0:1,o)},this.drawMultiLineMarker=function(e,t,n,r,i){var s=this.$padding,o=r.lineHeight,u=this.$getTop(t.start.row,r),a=s+t.start.column*r.characterWidth;i=i||"",e.push("
"),u=this.$getTop(t.end.row,r);var f=t.end.column*r.characterWidth;e.push("
"),o=(t.end.row-t.start.row-1)*r.lineHeight;if(o<=0)return;u=this.$getTop(t.start.row+1,r);var l=(t.start.column?1:0)|(t.end.column?0:8);e.push("
")},this.drawSingleLineMarker=function(e,t,n,r,i,s){var o=r.lineHeight,u=(t.end.column+(i||0)-t.start.column)*r.characterWidth,a=this.$getTop(t.start.row,r),f=this.$padding+t.start.column*r.characterWidth;e.push("
")},this.drawFullLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;t.start.row!=t.end.row&&(o+=this.$getTop(t.end.row,r)-s),e.push("
")},this.drawScreenLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;e.push("
")}}).call(s.prototype),t.Marker=s}),ace.define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/useragent"),u=e("../lib/event_emitter").EventEmitter,a=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_text-layer",e.appendChild(this.element),this.$updateEolChar=this.$updateEolChar.bind(this)};(function(){r.implement(this,u),this.EOF_CHAR="\u00b6",this.EOL_CHAR_LF="\u00ac",this.EOL_CHAR_CRLF="\u00a4",this.EOL_CHAR=this.EOL_CHAR_LF,this.TAB_CHAR="\u2014",this.SPACE_CHAR="\u00b7",this.$padding=0,this.$updateEolChar=function(){var e=this.session.doc.getNewLineCharacter()=="\n"?this.EOL_CHAR_LF:this.EOL_CHAR_CRLF;if(this.EOL_CHAR!=e)return this.EOL_CHAR=e,!0},this.setPadding=function(e){this.$padding=e,this.element.style.padding="0 "+e+"px"},this.getLineHeight=function(){return this.$fontMetrics.$characterSize.height||0},this.getCharacterWidth=function(){return this.$fontMetrics.$characterSize.width||0},this.$setFontMetrics=function(e){this.$fontMetrics=e,this.$fontMetrics.on("changeCharacterSize",function(e){this._signal("changeCharacterSize",e)}.bind(this)),this.$pollSizeChanges()},this.checkForSizeChanges=function(){this.$fontMetrics.checkForSizeChanges()},this.$pollSizeChanges=function(){return this.$pollSizeChangesTimer=this.$fontMetrics.$pollSizeChanges()},this.setSession=function(e){this.session=e,e&&this.$computeTabString()},this.showInvisibles=!1,this.setShowInvisibles=function(e){return this.showInvisibles==e?!1:(this.showInvisibles=e,this.$computeTabString(),!0)},this.displayIndentGuides=!0,this.setDisplayIndentGuides=function(e){return this.displayIndentGuides==e?!1:(this.displayIndentGuides=e,this.$computeTabString(),!0)},this.$tabStrings=[],this.onChangeTabSize=this.$computeTabString=function(){var e=this.session.getTabSize();this.tabSize=e;var t=this.$tabStrings=[0];for(var n=1;n"+s.stringRepeat(this.TAB_CHAR,n)+""):t.push(s.stringRepeat(" ",n));if(this.displayIndentGuides){this.$indentGuideRe=/\s\S| \t|\t |\s$/;var r="ace_indent-guide",i="",o="";if(this.showInvisibles){r+=" ace_invisible",i=" ace_invisible_space",o=" ace_invisible_tab";var u=s.stringRepeat(this.SPACE_CHAR,this.tabSize),a=s.stringRepeat(this.TAB_CHAR,this.tabSize)}else var u=s.stringRepeat(" ",this.tabSize),a=u;this.$tabStrings[" "]=""+u+" ",this.$tabStrings[" "]=""+a+" "}},this.updateLines=function(e,t,n){(this.config.lastRow!=e.lastRow||this.config.firstRow!=e.firstRow)&&this.scrollLines(e),this.config=e;var r=Math.max(t,e.firstRow),i=Math.min(n,e.lastRow),s=this.element.childNodes,o=0;for(var u=e.firstRow;uf&&(u=a.end.row+1,a=this.session.getNextFoldLine(u,a),f=a?a.start.row:Infinity);if(u>i)break;var l=s[o++];if(l){var c=[];this.$renderLine(c,u,!this.$useLineGroups(),u==f?a:!1),l.style.height=e.lineHeight*this.session.getRowLength(u)+"px",l.innerHTML=c.join("")}u++}},this.scrollLines=function(e){var t=this.config;this.config=e;if(!t||t.lastRow0;r--)n.removeChild(n.firstChild);if(t.lastRow>e.lastRow)for(var r=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);r>0;r--)n.removeChild(n.lastChild);if(e.firstRowt.lastRow){var i=this.$renderLinesFragment(e,t.lastRow+1,e.lastRow);n.appendChild(i)}},this.$renderLinesFragment=function(e,t,n){var r=this.element.ownerDocument.createDocumentFragment(),s=t,o=this.session.getNextFoldLine(s),u=o?o.start.row:Infinity;for(;;){s>u&&(s=o.end.row+1,o=this.session.getNextFoldLine(s,o),u=o?o.start.row:Infinity);if(s>n)break;var a=i.createElement("div"),f=[];this.$renderLine(f,s,!1,s==u?o:!1),a.innerHTML=f.join("");if(this.$useLineGroups())a.className="ace_line_group",r.appendChild(a),a.style.height=e.lineHeight*this.session.getRowLength(s)+"px";else while(a.firstChild)r.appendChild(a.firstChild);s++}return r},this.update=function(e){this.config=e;var t=[],n=e.firstRow,r=e.lastRow,i=n,s=this.session.getNextFoldLine(i),o=s?s.start.row:Infinity;for(;;){i>o&&(i=s.end.row+1,s=this.session.getNextFoldLine(i,s),o=s?s.start.row:Infinity);if(i>r)break;this.$useLineGroups()&&t.push(""),this.$renderLine(t,i,!1,i==o?s:!1),this.$useLineGroups()&&t.push("
"),i++}this.element.innerHTML=t.join("")},this.$textToken={text:!0,rparen:!0,lparen:!0},this.$renderToken=function(e,t,n,r){var i=this,o=/\t|&|<|>|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF\uFFF9-\uFFFC])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g,u=function(e,n,r,o,u){if(n)return i.showInvisibles?""+s.stringRepeat(i.SPACE_CHAR,e.length)+" ":e;if(e=="&")return"&";if(e=="<")return"<";if(e==">")return">";if(e==" "){var a=i.session.getScreenTabSize(t+o);return t+=a-1,i.$tabStrings[a]}if(e=="\u3000"){var f=i.showInvisibles?"ace_cjk ace_invisible ace_invisible_space":"ace_cjk",l=i.showInvisibles?i.SPACE_CHAR:"";return t+=1,""+l+" "}return r?""+i.SPACE_CHAR+" ":(t+=1,""+e+" ")},a=r.replace(o,u);if(!this.$textToken[n.type]){var f="ace_"+n.type.replace(/\./g," ace_"),l="";n.type=="fold"&&(l=" style='width:"+n.value.length*this.config.characterWidth+"px;' "),e.push("",a," ")}else e.push(a);return t+r.length},this.renderIndentGuide=function(e,t,n){var r=t.search(this.$indentGuideRe);return r<=0||r>=n?t:t[0]==" "?(r-=r%this.tabSize,e.push(s.stringRepeat(this.$tabStrings[" "],r/this.tabSize)),t.substr(r)):t[0]==" "?(e.push(s.stringRepeat(this.$tabStrings[" "],r)),t.substr(r)):t},this.$renderWrappedLine=function(e,t,n,r){var i=0,o=0,u=n[0],a=0;for(var f=0;f=u)a=this.$renderToken(e,a,l,c.substring(0,u-i)),c=c.substring(u-i),i=u,r||e.push("",""),e.push(s.stringRepeat("\u00a0",n.indent)),o++,a=0,u=n[o]||Number.MAX_VALUE;c.length!=0&&(i+=c.length,a=this.$renderToken(e,a,l,c))}}},this.$renderSimpleLine=function(e,t){var n=0,r=t[0],i=r.value;this.displayIndentGuides&&(i=this.renderIndentGuide(e,i)),i&&(n=this.$renderToken(e,n,r,i));for(var s=1;s");if(i.length){var s=this.session.getRowSplitData(t);s&&s.length?this.$renderWrappedLine(e,i,s,n):this.$renderSimpleLine(e,i)}this.showInvisibles&&(r&&(t=r.end.row),e.push("",t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR," ")),n||e.push("
")},this.$getFoldLineTokens=function(e,t){function i(e,t,n){var i=0,s=0;while(s+e[i].value.lengthn-t&&(o=o.substring(0,n-t)),r.push({type:e[i].type,value:o}),s=t+o.length,i+=1}while(sn?r.push({type:e[i].type,value:o.substring(0,n-s)}):r.push(e[i]),s+=o.length,i+=1}}var n=this.session,r=[],s=n.getTokens(e);return t.walk(function(e,t,o,u,a){e!=null?r.push({type:"fold",value:e}):(a&&(s=n.getTokens(t)),s.length&&i(s,u,o))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$measureNode&&this.$measureNode.parentNode.removeChild(this.$measureNode),delete this.$measureNode}}).call(a.prototype),t.Text=a}),ace.define("ace/layer/cursor",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../lib/dom"),i,s=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_cursor-layer",e.appendChild(this.element),i===undefined&&(i=!("opacity"in this.element.style)),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),r.addCssClass(this.element,"ace_hidden-cursors"),this.$updateCursors=(i?this.$updateVisibility:this.$updateOpacity).bind(this)};(function(){this.$updateVisibility=function(e){var t=this.cursors;for(var n=t.length;n--;)t[n].style.visibility=e?"":"hidden"},this.$updateOpacity=function(e){var t=this.cursors;for(var n=t.length;n--;)t[n].style.opacity=e?"":"0"},this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e!=this.smoothBlinking&&!i&&(this.smoothBlinking=e,r.setCssClass(this.element,"ace_smooth-blinking",e),this.$updateCursors(!0),this.$updateCursors=this.$updateOpacity.bind(this),this.restartTimer())},this.addCursor=function(){var e=r.createElement("div");return e.className="ace_cursor",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(this.cursors.length>1){var e=this.cursors.pop();return e.parentNode.removeChild(e),e}},this.hideCursor=function(){this.isVisible=!1,r.addCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.showCursor=function(){this.isVisible=!0,r.removeCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.restartTimer=function(){var e=this.$updateCursors;clearInterval(this.intervalId),clearTimeout(this.timeoutId),this.smoothBlinking&&r.removeCssClass(this.element,"ace_smooth-blinking"),e(!0);if(!this.isBlinking||!this.blinkInterval||!this.isVisible)return;this.smoothBlinking&&setTimeout(function(){r.addCssClass(this.element,"ace_smooth-blinking")}.bind(this));var t=function(){this.timeoutId=setTimeout(function(){e(!1)},.6*this.blinkInterval)}.bind(this);this.intervalId=setInterval(function(){e(!0),t()},this.blinkInterval),t()},this.getPixelPosition=function(e,t){if(!this.config||!this.session)return{left:0,top:0};e||(e=this.session.selection.getCursor());var n=this.session.documentToScreenPosition(e),r=this.$padding+n.column*this.config.characterWidth,i=(n.row-(t?this.config.firstRowScreen:0))*this.config.lineHeight;return{left:r,top:i}},this.update=function(e){this.config=e;var t=this.session.$selectionMarkers,n=0,r=0;if(t===undefined||t.length===0)t=[{cursor:null}];for(var n=0,i=t.length;ne.height+e.offset||s.top<0)&&n>1)continue;var o=(this.cursors[r++]||this.addCursor()).style;this.drawCursor?this.drawCursor(o,s,e,t[n],this.session):(o.left=s.left+"px",o.top=s.top+"px",o.width=e.characterWidth+"px",o.height=e.lineHeight+"px")}while(this.cursors.length>r)this.removeCursor();var u=this.session.getOverwrite();this.$setOverwrite(u),this.$pixelPos=s,this.restartTimer()},this.drawCursor=null,this.$setOverwrite=function(e){e!=this.overwrite&&(this.overwrite=e,e?r.addCssClass(this.element,"ace_overwrite-cursors"):r.removeCssClass(this.element,"ace_overwrite-cursors"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(s.prototype),t.Cursor=s}),ace.define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/event"),o=e("./lib/event_emitter").EventEmitter,u=function(e){this.element=i.createElement("div"),this.element.className="ace_scrollbar ace_scrollbar"+this.classSuffix,this.inner=i.createElement("div"),this.inner.className="ace_scrollbar-inner",this.element.appendChild(this.inner),e.appendChild(this.element),this.setVisible(!1),this.skipEvent=!1,s.addListener(this.element,"scroll",this.onScroll.bind(this)),s.addListener(this.element,"mousedown",s.preventDefault)};(function(){r.implement(this,o),this.setVisible=function(e){this.element.style.display=e?"":"none",this.isVisible=e}}).call(u.prototype);var a=function(e,t){u.call(this,e),this.scrollTop=0,t.$scrollbarWidth=this.width=i.scrollbarWidth(e.ownerDocument),this.inner.style.width=this.element.style.width=(this.width||15)+5+"px"};r.inherits(a,u),function(){this.classSuffix="-v",this.onScroll=function(){this.skipEvent||(this.scrollTop=this.element.scrollTop,this._emit("scroll",{data:this.scrollTop})),this.skipEvent=!1},this.getWidth=function(){return this.isVisible?this.width:0},this.setHeight=function(e){this.element.style.height=e+"px"},this.setInnerHeight=function(e){this.inner.style.height=e+"px"},this.setScrollHeight=function(e){this.inner.style.height=e+"px"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=this.element.scrollTop=e)}}.call(a.prototype);var f=function(e,t){u.call(this,e),this.scrollLeft=0,this.height=t.$scrollbarWidth,this.inner.style.height=this.element.style.height=(this.height||15)+5+"px"};r.inherits(f,u),function(){this.classSuffix="-h",this.onScroll=function(){this.skipEvent||(this.scrollLeft=this.element.scrollLeft,this._emit("scroll",{data:this.scrollLeft})),this.skipEvent=!1},this.getHeight=function(){return this.isVisible?this.height:0},this.setWidth=function(e){this.element.style.width=e+"px"},this.setInnerWidth=function(e){this.inner.style.width=e+"px"},this.setScrollWidth=function(e){this.inner.style.width=e+"px"},this.setScrollLeft=function(e){this.scrollLeft!=e&&(this.skipEvent=!0,this.scrollLeft=this.element.scrollLeft=e)}}.call(f.prototype),t.ScrollBar=a,t.ScrollBarV=a,t.ScrollBarH=f,t.VScrollBar=a,t.HScrollBar=f}),ace.define("ace/renderloop",["require","exports","module","ace/lib/event"],function(e,t,n){"use strict";var r=e("./lib/event"),i=function(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.window=t||window};(function(){this.schedule=function(e){this.changes=this.changes|e;if(!this.pending&&this.changes){this.pending=!0;var t=this;r.nextFrame(function(){t.pending=!1;var e;while(e=t.changes)t.changes=0,t.onRender(e)},this.window)}}}).call(i.prototype),t.RenderLoop=i}),ace.define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/useragent"),u=e("../lib/event_emitter").EventEmitter,a=0,f=t.FontMetrics=function(e){this.el=i.createElement("div"),this.$setMeasureNodeStyles(this.el.style,!0),this.$main=i.createElement("div"),this.$setMeasureNodeStyles(this.$main.style),this.$measureNode=i.createElement("div"),this.$setMeasureNodeStyles(this.$measureNode.style),this.el.appendChild(this.$main),this.el.appendChild(this.$measureNode),e.appendChild(this.el),a||this.$testFractionalRect(),this.$measureNode.innerHTML=s.stringRepeat("X",a),this.$characterSize={width:0,height:0},this.checkForSizeChanges()};(function(){r.implement(this,u),this.$characterSize={width:0,height:0},this.$testFractionalRect=function(){var e=i.createElement("div");this.$setMeasureNodeStyles(e.style),e.style.width="0.2px",document.documentElement.appendChild(e);var t=e.getBoundingClientRect().width;t>0&&t<1?a=50:a=100,e.parentNode.removeChild(e)},this.$setMeasureNodeStyles=function(e,t){e.width=e.height="auto",e.left=e.top="0px",e.visibility="hidden",e.position="absolute",e.whiteSpace="pre",o.isIE<8?e["font-family"]="inherit":e.font="inherit",e.overflow=t?"hidden":"visible"},this.checkForSizeChanges=function(){var e=this.$measureSizes();if(e&&(this.$characterSize.width!==e.width||this.$characterSize.height!==e.height)){this.$measureNode.style.fontWeight="bold";var t=this.$measureSizes();this.$measureNode.style.fontWeight="",this.$characterSize=e,this.charSizes=Object.create(null),this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit("changeCharacterSize",{data:e})}},this.$pollSizeChanges=function(){if(this.$pollSizeChangesTimer)return this.$pollSizeChangesTimer;var e=this;return this.$pollSizeChangesTimer=setInterval(function(){e.checkForSizeChanges()},500)},this.setPolling=function(e){e?this.$pollSizeChanges():this.$pollSizeChangesTimer&&(clearInterval(this.$pollSizeChangesTimer),this.$pollSizeChangesTimer=0)},this.$measureSizes=function(){if(a===50){var e=null;try{e=this.$measureNode.getBoundingClientRect()}catch(t){e={width:0,height:0}}var n={height:e.height,width:e.width/a}}else var n={height:this.$measureNode.clientHeight,width:this.$measureNode.clientWidth/a};return n.width===0||n.height===0?null:n},this.$measureCharWidth=function(e){this.$main.innerHTML=s.stringRepeat(e,a);var t=this.$main.getBoundingClientRect();return t.width/a},this.getCharacterWidth=function(e){var t=this.charSizes[e];return t===undefined&&(t=this.charSizes[e]=this.$measureCharWidth(e)/this.$characterSize.width),t},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.el&&this.el.parentNode&&this.el.parentNode.removeChild(this.el)}}).call(f.prototype)}),ace.define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/lib/useragent","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./config"),o=e("./lib/useragent"),u=e("./layer/gutter").Gutter,a=e("./layer/marker").Marker,f=e("./layer/text").Text,l=e("./layer/cursor").Cursor,c=e("./scrollbar").HScrollBar,h=e("./scrollbar").VScrollBar,p=e("./renderloop").RenderLoop,d=e("./layer/font_metrics").FontMetrics,v=e("./lib/event_emitter").EventEmitter,m='.ace_editor {position: relative;overflow: hidden;font: 12px/normal \'Monaco\', \'Menlo\', \'Ubuntu Mono\', \'Consolas\', \'source-code-pro\', monospace;direction: ltr;}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;min-width: 100%;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: \'\';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");}.ace_scrollbar {position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;text-indent: -1em;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: inherit;color: inherit;z-index: 1000;opacity: 1;text-indent: 0;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;}.ace_text-layer {font: inherit !important;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_smooth-blinking .ace_cursor {-webkit-transition: opacity 0.18s;transition: opacity 0.18s;}.ace_editor.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;}.ace_line .ace_fold {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");}.ace_tooltip {background-color: #FFF;background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block; }.ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");}.ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");}.ace_dark .ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {-webkit-transition: opacity 0.4s ease 0.05s;transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {-webkit-transition: opacity 0.05s ease 0.05s;transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}.ace_br1 {border-top-left-radius : 3px;}.ace_br2 {border-top-right-radius : 3px;}.ace_br3 {border-top-left-radius : 3px; border-top-right-radius: 3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius : 3px; border-bottom-left-radius: 3px;}.ace_br10{border-top-right-radius : 3px; border-bottom-left-radius: 3px;}.ace_br11{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br13{border-top-left-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br14{border-top-right-radius : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}.ace_br15{border-top-left-radius : 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}';i.importCssString(m,"ace_editor.css");var g=function(e,t){var n=this;this.container=e||i.createElement("div"),this.$keepTextAreaAtCursor=!o.isOldIE,i.addCssClass(this.container,"ace_editor"),this.setTheme(t),this.$gutter=i.createElement("div"),this.$gutter.className="ace_gutter",this.container.appendChild(this.$gutter),this.scroller=i.createElement("div"),this.scroller.className="ace_scroller",this.container.appendChild(this.scroller),this.content=i.createElement("div"),this.content.className="ace_content",this.scroller.appendChild(this.content),this.$gutterLayer=new u(this.$gutter),this.$gutterLayer.on("changeGutterWidth",this.onGutterResize.bind(this)),this.$markerBack=new a(this.content);var r=this.$textLayer=new f(this.content);this.canvas=r.element,this.$markerFront=new a(this.content),this.$cursorLayer=new l(this.content),this.$horizScroll=!1,this.$vScroll=!1,this.scrollBar=this.scrollBarV=new h(this.container,this),this.scrollBarH=new c(this.container,this),this.scrollBarV.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollTop(e.data-n.scrollMargin.top)}),this.scrollBarH.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollLeft(e.data-n.scrollMargin.left)}),this.scrollTop=0,this.scrollLeft=0,this.cursorPos={row:0,column:0},this.$fontMetrics=new d(this.container),this.$textLayer.$setFontMetrics(this.$fontMetrics),this.$textLayer.addEventListener("changeCharacterSize",function(e){n.updateCharacterSize(),n.onResize(!0,n.gutterWidth,n.$size.width,n.$size.height),n._signal("changeCharacterSize",e)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0,$dirty:!0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:0,characterWidth:0,minHeight:1,maxHeight:1,offset:0,height:1,gutterOffset:1},this.scrollMargin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.$loop=new p(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4),s.resetOptions(this),s._emit("renderer",this)};(function(){this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,r.implement(this,v),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle("ace_nobold",!this.$allowBoldFonts)),this.layerConfig.characterWidth=this.characterWidth=this.$textLayer.getCharacterWidth(),this.layerConfig.lineHeight=this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin()},this.setSession=function(e){this.session&&this.session.doc.off("changeNewLineMode",this.onChangeNewLineMode),this.session=e,e&&this.scrollMargin.top&&e.getScrollTop()<=0&&e.setScrollTop(-this.scrollMargin.top),this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e);if(!e)return;this.$loop.schedule(this.CHANGE_FULL),this.session.$setFontMetrics(this.$fontMetrics),this.onChangeNewLineMode=this.onChangeNewLineMode.bind(this),this.onChangeNewLineMode(),this.session.doc.on("changeNewLineMode",this.onChangeNewLineMode)},this.updateLines=function(e,t,n){t===undefined&&(t=Infinity),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRowthis.layerConfig.lastRow)return;this.$loop.schedule(this.CHANGE_LINES)},this.onChangeNewLineMode=function(){this.$loop.schedule(this.CHANGE_TEXT),this.$textLayer.$updateEolChar()},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.$changes=0,this.$updateSizeAsync=function(){this.$loop.pending?this.$size.$dirty=!0:this.onResize()},this.onResize=function(e,t,n,r){if(this.resizing>2)return;this.resizing>0?this.resizing++:this.resizing=e?1:0;var i=this.container;r||(r=i.clientHeight||i.scrollHeight),n||(n=i.clientWidth||i.scrollWidth);var s=this.$updateCachedSize(e,t,n,r);if(!this.$size.scrollerHeight||!n&&!r)return this.resizing=0;e&&(this.$gutterLayer.$padding=null),e?this.$renderChanges(s|this.$changes,!0):this.$loop.schedule(s|this.$changes),this.resizing&&(this.resizing=0),this.scrollBarV.scrollLeft=this.scrollBarV.scrollTop=null},this.$updateCachedSize=function(e,t,n,r){r-=this.$extraHeight||0;var i=0,s=this.$size,o={width:s.width,height:s.height,scrollerHeight:s.scrollerHeight,scrollerWidth:s.scrollerWidth};r&&(e||s.height!=r)&&(s.height=r,i|=this.CHANGE_SIZE,s.scrollerHeight=s.height,this.$horizScroll&&(s.scrollerHeight-=this.scrollBarH.getHeight()),this.scrollBarV.element.style.bottom=this.scrollBarH.getHeight()+"px",i|=this.CHANGE_SCROLL);if(n&&(e||s.width!=n)){i|=this.CHANGE_SIZE,s.width=n,t==null&&(t=this.$showGutter?this.$gutter.offsetWidth:0),this.gutterWidth=t,this.scrollBarH.element.style.left=this.scroller.style.left=t+"px",s.scrollerWidth=Math.max(0,n-t-this.scrollBarV.getWidth()),this.scrollBarH.element.style.right=this.scroller.style.right=this.scrollBarV.getWidth()+"px",this.scroller.style.bottom=this.scrollBarH.getHeight()+"px";if(this.session&&this.session.getUseWrapMode()&&this.adjustWrapLimit()||e)i|=this.CHANGE_FULL}return s.$dirty=!n||!r,i&&this._signal("resize",o),i},this.onGutterResize=function(){var e=this.$showGutter?this.$gutter.offsetWidth:0;e!=this.gutterWidth&&(this.$changes|=this.$updateCachedSize(!0,e,this.$size.width,this.$size.height)),this.session.getUseWrapMode()&&this.adjustWrapLimit()?this.$loop.schedule(this.CHANGE_FULL):this.$size.$dirty?this.$loop.schedule(this.CHANGE_FULL):(this.$computeLayerConfig(),this.$loop.schedule(this.CHANGE_MARKER))},this.adjustWrapLimit=function(){var e=this.$size.scrollerWidth-this.$padding*2,t=Math.floor(e/this.characterWidth);return this.session.adjustWrapLimit(t,this.$showPrintMargin&&this.$printMarginColumn)},this.setAnimatedScroll=function(e){this.setOption("animatedScroll",e)},this.getAnimatedScroll=function(){return this.$animatedScroll},this.setShowInvisibles=function(e){this.setOption("showInvisibles",e)},this.getShowInvisibles=function(){return this.getOption("showInvisibles")},this.getDisplayIndentGuides=function(){return this.getOption("displayIndentGuides")},this.setDisplayIndentGuides=function(e){this.setOption("displayIndentGuides",e)},this.setShowPrintMargin=function(e){this.setOption("showPrintMargin",e)},this.getShowPrintMargin=function(){return this.getOption("showPrintMargin")},this.setPrintMarginColumn=function(e){this.setOption("printMarginColumn",e)},this.getPrintMarginColumn=function(){return this.getOption("printMarginColumn")},this.getShowGutter=function(){return this.getOption("showGutter")},this.setShowGutter=function(e){return this.setOption("showGutter",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.$updateGutterLineHighlight=function(){var e=this.$cursorLayer.$pixelPos,t=this.layerConfig.lineHeight;if(this.session.getUseWrapMode()){var n=this.session.selection.getCursor();n.column=0,e=this.$cursorLayer.getPixelPosition(n,!0),t*=this.session.getRowLength(n.row)}this.$gutterLineHighlight.style.top=e.top-this.layerConfig.offset+"px",this.$gutterLineHighlight.style.height=t+"px"},this.$updatePrintMargin=function(){if(!this.$showPrintMargin&&!this.$printMarginEl)return;if(!this.$printMarginEl){var e=i.createElement("div");e.className="ace_layer ace_print-margin-layer",this.$printMarginEl=i.createElement("div"),this.$printMarginEl.className="ace_print-margin",e.appendChild(this.$printMarginEl),this.content.insertBefore(e,this.content.firstChild)}var t=this.$printMarginEl.style;t.left=this.characterWidth*this.$printMarginColumn+this.$padding+"px",t.visibility=this.$showPrintMargin?"visible":"hidden",this.session&&this.session.$wrap==-1&&this.adjustWrapLimit()},this.getContainerElement=function(){return this.container},this.getMouseEventTarget=function(){return this.scroller},this.getTextAreaContainer=function(){return this.container},this.$moveTextAreaToCursor=function(){if(!this.$keepTextAreaAtCursor)return;var e=this.layerConfig,t=this.$cursorLayer.$pixelPos.top,n=this.$cursorLayer.$pixelPos.left;t-=e.offset;var r=this.textarea.style,i=this.lineHeight;if(t<0||t>e.height-i){r.top=r.left="0";return}var s=this.characterWidth;if(this.$composition){var o=this.textarea.value.replace(/^\x01+/,"");s*=this.session.$getStringScreenWidth(o)[0]+2,i+=2}n-=this.scrollLeft,n>this.$size.scrollerWidth-s&&(n=this.$size.scrollerWidth-s),n+=this.gutterWidth,r.height=i+"px",r.width=s+"px",r.left=Math.min(n,this.$size.scrollerWidth-s)+"px",r.top=Math.min(t,this.$size.height-i)+"px"},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(this.layerConfig.offset===0?0:1)},this.getLastFullyVisibleRow=function(){var e=this.layerConfig,t=e.lastRow,n=this.session.documentToScreenRow(t,0)*e.lineHeight;return n-this.session.getScrollTop()>e.height-e.lineHeight?t-1:t},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.setScrollMargin=function(e,t,n,r){var i=this.scrollMargin;i.top=e|0,i.bottom=t|0,i.right=r|0,i.left=n|0,i.v=i.top+i.bottom,i.h=i.left+i.right,i.top&&this.scrollTop<=0&&this.session&&this.session.setScrollTop(-i.top),this.updateFull()},this.getHScrollBarAlwaysVisible=function(){return this.$hScrollBarAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.setOption("hScrollBarAlwaysVisible",e)},this.getVScrollBarAlwaysVisible=function(){return this.$vScrollBarAlwaysVisible},this.setVScrollBarAlwaysVisible=function(e){this.setOption("vScrollBarAlwaysVisible",e)},this.$updateScrollBarV=function(){var e=this.layerConfig.maxHeight,t=this.$size.scrollerHeight;!this.$maxLines&&this.$scrollPastEnd&&(e-=(t-this.lineHeight)*this.$scrollPastEnd,this.scrollTop>e-t&&(e=this.scrollTop+t,this.scrollBarV.scrollTop=null)),this.scrollBarV.setScrollHeight(e+this.scrollMargin.v),this.scrollBarV.setScrollTop(this.scrollTop+this.scrollMargin.top)},this.$updateScrollBarH=function(){this.scrollBarH.setScrollWidth(this.layerConfig.width+2*this.$padding+this.scrollMargin.h),this.scrollBarH.setScrollLeft(this.scrollLeft+this.scrollMargin.left)},this.$frozen=!1,this.freeze=function(){this.$frozen=!0},this.unfreeze=function(){this.$frozen=!1},this.$renderChanges=function(e,t){this.$changes&&(e|=this.$changes,this.$changes=0);if(!this.session||!this.container.offsetWidth||this.$frozen||!e&&!t){this.$changes|=e;return}if(this.$size.$dirty)return this.$changes|=e,this.onResize(!0);this.lineHeight||this.$textLayer.checkForSizeChanges(),this._signal("beforeRender");var n=this.layerConfig;if(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL||e&this.CHANGE_H_SCROLL){e|=this.$computeLayerConfig();if(n.firstRow!=this.layerConfig.firstRow&&n.firstRowScreen==this.layerConfig.firstRowScreen){var r=this.scrollTop+(n.firstRow-this.layerConfig.firstRow)*this.lineHeight;r>0&&(this.scrollTop=r,e|=this.CHANGE_SCROLL,e|=this.$computeLayerConfig())}n=this.layerConfig,this.$updateScrollBarV(),e&this.CHANGE_H_SCROLL&&this.$updateScrollBarH(),this.$gutterLayer.element.style.marginTop=-n.offset+"px",this.content.style.marginTop=-n.offset+"px",this.content.style.width=n.width+2*this.$padding+"px",this.content.style.height=n.minHeight+"px"}e&this.CHANGE_H_SCROLL&&(this.content.style.marginLeft=-this.scrollLeft+"px",this.scroller.className=this.scrollLeft<=0?"ace_scroller":"ace_scroller ace_scroll-left");if(e&this.CHANGE_FULL){this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),this._signal("afterRender");return}if(e&this.CHANGE_SCROLL){e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(n):this.$textLayer.scrollLines(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),this.$moveTextAreaToCursor(),this._signal("afterRender");return}e&this.CHANGE_TEXT?(this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.$showGutter)&&this.$gutterLayer.update(n):(e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER)&&this.$showGutter&&this.$gutterLayer.update(n),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(n),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(n),this._signal("afterRender")},this.$autosize=function(){var e=this.session.getScreenLength()*this.lineHeight,t=this.$maxLines*this.lineHeight,n=Math.min(t,Math.max((this.$minLines||1)*this.lineHeight,e))+this.scrollMargin.v+(this.$extraHeight||0);this.$horizScroll&&(n+=this.scrollBarH.getHeight()),this.$maxPixelHeight&&n>this.$maxPixelHeight&&(n=this.$maxPixelHeight);var r=e>t;if(n!=this.desiredHeight||this.$size.height!=this.desiredHeight||r!=this.$vScroll){r!=this.$vScroll&&(this.$vScroll=r,this.scrollBarV.setVisible(r));var i=this.container.clientWidth;this.container.style.height=n+"px",this.$updateCachedSize(!0,this.$gutterWidth,i,n),this.desiredHeight=n,this._signal("autosize")}},this.$computeLayerConfig=function(){var e=this.session,t=this.$size,n=t.height<=2*this.lineHeight,r=this.session.getScreenLength(),i=r*this.lineHeight,s=this.$getLongestLine(),o=!n&&(this.$hScrollBarAlwaysVisible||t.scrollerWidth-s-2*this.$padding<0),u=this.$horizScroll!==o;u&&(this.$horizScroll=o,this.scrollBarH.setVisible(o));var a=this.$vScroll;this.$maxLines&&this.lineHeight>1&&this.$autosize();var f=this.scrollTop%this.lineHeight,l=t.scrollerHeight+this.lineHeight,c=!this.$maxLines&&this.$scrollPastEnd?(t.scrollerHeight-this.lineHeight)*this.$scrollPastEnd:0;i+=c;var h=this.scrollMargin;this.session.setScrollTop(Math.max(-h.top,Math.min(this.scrollTop,i-t.scrollerHeight+h.bottom))),this.session.setScrollLeft(Math.max(-h.left,Math.min(this.scrollLeft,s+2*this.$padding-t.scrollerWidth+h.right)));var p=!n&&(this.$vScrollBarAlwaysVisible||t.scrollerHeight-i+c<0||this.scrollTop>h.top),d=a!==p;d&&(this.$vScroll=p,this.scrollBarV.setVisible(p));var v=Math.ceil(l/this.lineHeight)-1,m=Math.max(0,Math.round((this.scrollTop-f)/this.lineHeight)),g=m+v,y,b,w=this.lineHeight;m=e.screenToDocumentRow(m,0);var E=e.getFoldLine(m);E&&(m=E.start.row),y=e.documentToScreenRow(m,0),b=e.getRowLength(m)*w,g=Math.min(e.screenToDocumentRow(g,0),e.getLength()-1),l=t.scrollerHeight+e.getRowLength(g)*w+b,f=this.scrollTop-y*w;var S=0;this.layerConfig.width!=s&&(S=this.CHANGE_H_SCROLL);if(u||d)S=this.$updateCachedSize(!0,this.gutterWidth,t.width,t.height),this._signal("scrollbarVisibilityChanged"),d&&(s=this.$getLongestLine());return this.layerConfig={width:s,padding:this.$padding,firstRow:m,firstRowScreen:y,lastRow:g,lineHeight:w,characterWidth:this.characterWidth,minHeight:l,maxHeight:i,offset:f,gutterOffset:Math.max(0,Math.ceil((f+t.height-t.scrollerHeight)/w)),height:this.$size.scrollerHeight},S},this.$updateLines=function(){var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var n=this.layerConfig;if(e>n.lastRow+1)return;if(ts?(t&&a+o>s+this.lineHeight&&(s-=t*this.$size.scrollerHeight),s===0&&(s=-this.scrollMargin.top),this.session.setScrollTop(s)):a+this.$size.scrollerHeight-ui?(i=1-this.scrollMargin.top)return!0;if(t>0&&this.session.getScrollTop()+this.$size.scrollerHeight-this.layerConfig.maxHeight<-1+this.scrollMargin.bottom)return!0;if(e<0&&this.session.getScrollLeft()>=1-this.scrollMargin.left)return!0;if(e>0&&this.session.getScrollLeft()+this.$size.scrollerWidth-this.layerConfig.width<-1+this.scrollMargin.right)return!0},this.pixelToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=(e+this.scrollLeft-n.left-this.$padding)/this.characterWidth,i=Math.floor((t+this.scrollTop-n.top)/this.lineHeight),s=Math.round(r);return{row:i,column:s,side:r-s>0?1:-1}},this.screenToTextCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=Math.round((e+this.scrollLeft-n.left-this.$padding)/this.characterWidth),i=(t+this.scrollTop-n.top)/this.lineHeight;return this.session.screenToDocumentPosition(i,Math.max(r,0))},this.textToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=this.session.documentToScreenPosition(e,t),i=this.$padding+Math.round(r.column*this.characterWidth),s=r.row*this.lineHeight;return{pageX:n.left+i-this.scrollLeft,pageY:n.top+s-this.scrollTop}},this.visualizeFocus=function(){i.addCssClass(this.container,"ace_focus")},this.visualizeBlur=function(){i.removeCssClass(this.container,"ace_focus")},this.showComposition=function(e){this.$composition||(this.$composition={keepTextAreaAtCursor:this.$keepTextAreaAtCursor,cssText:this.textarea.style.cssText}),this.$keepTextAreaAtCursor=!0,i.addCssClass(this.textarea,"ace_composition"),this.textarea.style.cssText="",this.$moveTextAreaToCursor()},this.setCompositionText=function(e){this.$moveTextAreaToCursor()},this.hideComposition=function(){if(!this.$composition)return;i.removeCssClass(this.textarea,"ace_composition"),this.$keepTextAreaAtCursor=this.$composition.keepTextAreaAtCursor,this.textarea.style.cssText=this.$composition.cssText,this.$composition=null},this.setTheme=function(e,t){function o(r){if(n.$themeId!=e)return t&&t();if(!r.cssClass)return;i.importCssString(r.cssText,r.cssClass,n.container.ownerDocument),n.theme&&i.removeCssClass(n.container,n.theme.cssClass);var s="padding"in r?r.padding:"padding"in(n.theme||{})?4:n.$padding;n.$padding&&s!=n.$padding&&n.setPadding(s),n.$theme=r.cssClass,n.theme=r,i.addCssClass(n.container,r.cssClass),i.setCssClass(n.container,"ace_dark",r.isDark),n.$size&&(n.$size.width=0,n.$updateSizeAsync()),n._dispatchEvent("themeLoaded",{theme:r}),t&&t()}var n=this;this.$themeId=e,n._dispatchEvent("themeChange",{theme:e});if(!e||typeof e=="string"){var r=e||this.$options.theme.initialValue;s.loadModule(["theme",r],o)}else o(e)},this.getTheme=function(){return this.$themeId},this.setStyle=function(e,t){i.setCssClass(this.container,e,t!==!1)},this.unsetStyle=function(e){i.removeCssClass(this.container,e)},this.setCursorStyle=function(e){this.scroller.style.cursor!=e&&(this.scroller.style.cursor=e)},this.setMouseCursor=function(e){this.scroller.style.cursor=e},this.destroy=function(){this.$textLayer.destroy(),this.$cursorLayer.destroy()}}).call(g.prototype),s.defineOptions(g.prototype,"renderer",{animatedScroll:{initialValue:!1},showInvisibles:{set:function(e){this.$textLayer.setShowInvisibles(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!1},showPrintMargin:{set:function(){this.$updatePrintMargin()},initialValue:!0},printMarginColumn:{set:function(){this.$updatePrintMargin()},initialValue:80},printMargin:{set:function(e){typeof e=="number"&&(this.$printMarginColumn=e),this.$showPrintMargin=!!e,this.$updatePrintMargin()},get:function(){return this.$showPrintMargin&&this.$printMarginColumn}},showGutter:{set:function(e){this.$gutter.style.display=e?"block":"none",this.$loop.schedule(this.CHANGE_FULL),this.onGutterResize()},initialValue:!0},fadeFoldWidgets:{set:function(e){i.setCssClass(this.$gutter,"ace_fade-fold-widgets",e)},initialValue:!1},showFoldWidgets:{set:function(e){this.$gutterLayer.setShowFoldWidgets(e)},initialValue:!0},showLineNumbers:{set:function(e){this.$gutterLayer.setShowLineNumbers(e),this.$loop.schedule(this.CHANGE_GUTTER)},initialValue:!0},displayIndentGuides:{set:function(e){this.$textLayer.setDisplayIndentGuides(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!0},highlightGutterLine:{set:function(e){if(!this.$gutterLineHighlight){this.$gutterLineHighlight=i.createElement("div"),this.$gutterLineHighlight.className="ace_gutter-active-line",this.$gutter.appendChild(this.$gutterLineHighlight);return}this.$gutterLineHighlight.style.display=e?"":"none",this.$cursorLayer.$pixelPos&&this.$updateGutterLineHighlight()},initialValue:!1,value:!0},hScrollBarAlwaysVisible:{set:function(e){(!this.$hScrollBarAlwaysVisible||!this.$horizScroll)&&this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},vScrollBarAlwaysVisible:{set:function(e){(!this.$vScrollBarAlwaysVisible||!this.$vScroll)&&this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},fontSize:{set:function(e){typeof e=="number"&&(e+="px"),this.container.style.fontSize=e,this.updateFontSize()},initialValue:12},fontFamily:{set:function(e){this.container.style.fontFamily=e,this.updateFontSize()}},maxLines:{set:function(e){this.updateFull()}},minLines:{set:function(e){this.updateFull()}},maxPixelHeight:{set:function(e){this.updateFull()},initialValue:0},scrollPastEnd:{set:function(e){e=+e||0;if(this.$scrollPastEnd==e)return;this.$scrollPastEnd=e,this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:0,handlesSet:!0},fixedWidthGutter:{set:function(e){this.$gutterLayer.$fixedWidth=!!e,this.$loop.schedule(this.CHANGE_GUTTER)}},theme:{set:function(e){this.setTheme(e)},get:function(){return this.$themeId||this.theme},initialValue:"./theme/textmate",handlesSet:!0}}),t.VirtualRenderer=g}),ace.define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/net","ace/lib/event_emitter","ace/config"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/net"),s=e("../lib/event_emitter").EventEmitter,o=e("../config"),u=function(t,n,r,i){this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.onMessage=this.onMessage.bind(this),e.nameToUrl&&!e.toUrl&&(e.toUrl=e.nameToUrl);if(o.get("packaged")||!e.toUrl)i=i||o.moduleUrl(n,"worker");else{var s=this.$normalizePath;i=i||s(e.toUrl("ace/worker/worker.js",null,"_"));var u={};t.forEach(function(t){u[t]=s(e.toUrl(t,null,"_").replace(/(\.js)?(\?.*)?$/,""))})}try{this.$worker=new Worker(i)}catch(a){if(!(a instanceof window.DOMException))throw a;var f=this.$workerBlob(i),l=window.URL||window.webkitURL,c=l.createObjectURL(f);this.$worker=new Worker(c),l.revokeObjectURL(c)}this.$worker.postMessage({init:!0,tlns:u,module:n,classname:r}),this.callbackId=1,this.callbacks={},this.$worker.onmessage=this.onMessage};(function(){r.implement(this,s),this.onMessage=function(e){var t=e.data;switch(t.type){case"event":this._signal(t.name,{data:t.data});break;case"call":var n=this.callbacks[t.id];n&&(n(t.data),delete this.callbacks[t.id]);break;case"error":this.reportError(t.data);break;case"log":window.console&&console.log&&console.log.apply(console,t.data)}},this.reportError=function(e){window.console&&console.error&&console.error(e)},this.$normalizePath=function(e){return i.qualifyURL(e)},this.terminate=function(){this._signal("terminate",{}),this.deltaQueue=null,this.$worker.terminate(),this.$worker=null,this.$doc&&this.$doc.off("change",this.changeListener),this.$doc=null},this.send=function(e,t){this.$worker.postMessage({command:e,args:t})},this.call=function(e,t,n){if(n){var r=this.callbackId++;this.callbacks[r]=n,t.push(r)}this.send(e,t)},this.emit=function(e,t){try{this.$worker.postMessage({event:e,data:{data:t.data}})}catch(n){console.error(n.stack)}},this.attachToDocument=function(e){this.$doc&&this.terminate(),this.$doc=e,this.call("setValue",[e.getValue()]),e.on("change",this.changeListener)},this.changeListener=function(e){this.deltaQueue||(this.deltaQueue=[],setTimeout(this.$sendDeltaQueue,0)),e.action=="insert"?this.deltaQueue.push(e.start,e.lines):this.deltaQueue.push(e.start,e.end)},this.$sendDeltaQueue=function(){var e=this.deltaQueue;if(!e)return;this.deltaQueue=null,e.length>50&&e.length>this.$doc.getLength()>>1?this.call("setValue",[this.$doc.getValue()]):this.emit("change",{data:e})},this.$workerBlob=function(e){var t="importScripts('"+i.qualifyURL(e)+"');";try{return new Blob([t],{type:"application/javascript"})}catch(n){var r=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder,s=new r;return s.append(t),s.getBlob("application/javascript")}}}).call(u.prototype);var a=function(e,t,n){this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.callbackId=1,this.callbacks={},this.messageBuffer=[];var r=null,i=!1,u=Object.create(s),a=this;this.$worker={},this.$worker.terminate=function(){},this.$worker.postMessage=function(e){a.messageBuffer.push(e),r&&(i?setTimeout(f):f())},this.setEmitSync=function(e){i=e};var f=function(){var e=a.messageBuffer.shift();e.command?r[e.command].apply(r,e.args):e.event&&u._signal(e.event,e.data)};u.postMessage=function(e){a.onMessage({data:e})},u.callback=function(e,t){this.postMessage({type:"call",id:t,data:e})},u.emit=function(e,t){this.postMessage({type:"event",name:e,data:t})},o.loadModule(["worker",t],function(e){r=new e[n](u);while(a.messageBuffer.length)f()})};a.prototype=u.prototype,t.UIWorkerClient=a,t.WorkerClient=u}),ace.define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./range").Range,i=e("./lib/event_emitter").EventEmitter,s=e("./lib/oop"),o=function(e,t,n,r,i,s){var o=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=i,this.othersClass=s,this.$onUpdate=this.onUpdate.bind(this),this.doc.on("change",this.$onUpdate),this.$others=r,this.$onCursorChange=function(){setTimeout(function(){o.onCursorChange()})},this.$pos=n;var u=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=u.length,this.setup(),e.selection.on("changeCursor",this.$onCursorChange)};(function(){s.implement(this,i),this.setup=function(){var e=this,t=this.doc,n=this.session;this.selectionBefore=n.selection.toJSON(),n.selection.inMultiSelectMode&&n.selection.toSingleRange(),this.pos=t.createAnchor(this.$pos.row,this.$pos.column);var i=this.pos;i.$insertRight=!0,i.detach(),i.markerId=n.addMarker(new r(i.row,i.column,i.row,i.column+this.length),this.mainClass,null,!1),this.others=[],this.$others.forEach(function(n){var r=t.createAnchor(n.row,n.column);r.$insertRight=!0,r.detach(),e.others.push(r)}),n.setUndoSelect(!1)},this.showOtherMarkers=function(){if(this.othersActive)return;var e=this.session,t=this;this.othersActive=!0,this.others.forEach(function(n){n.markerId=e.addMarker(new r(n.row,n.column,n.row,n.column+t.length),t.othersClass,null,!1)})},this.hideOtherMarkers=function(){if(!this.othersActive)return;this.othersActive=!1;for(var e=0;e=this.pos.column&&t.start.column<=this.pos.column+this.length+1,s=t.start.column-this.pos.column;this.updateAnchors(e),i&&(this.length+=n);if(i&&!this.session.$fromUndo)if(e.action==="insert")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.insertMergedLines(a,e.lines)}else if(e.action==="remove")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.remove(new r(a.row,a.column,a.row,a.column-n))}this.$updating=!1,this.updateMarkers()},this.updateAnchors=function(e){this.pos.onChange(e);for(var t=this.others.length;t--;)this.others[t].onChange(e);this.updateMarkers()},this.updateMarkers=function(){if(this.$updating)return;var e=this,t=this.session,n=function(n,i){t.removeMarker(n.markerId),n.markerId=t.addMarker(new r(n.row,n.column,n.row,n.column+e.length),i,null,!1)};n(this.pos,this.mainClass);for(var i=this.others.length;i--;)n(this.others[i],this.othersClass)},this.onCursorChange=function(e){if(this.$updating||!this.session)return;var t=this.session.selection.getCursor();t.row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit("cursorEnter",e)):(this.hideOtherMarkers(),this._emit("cursorLeave",e))},this.detach=function(){this.session.removeMarker(this.pos&&this.pos.markerId),this.hideOtherMarkers(),this.doc.removeEventListener("change",this.$onUpdate),this.session.selection.removeEventListener("changeCursor",this.$onCursorChange),this.session.setUndoSelect(!0),this.session=null},this.cancel=function(){if(this.$undoStackDepth===-1)return;var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth;for(var n=0;n1&&!this.inMultiSelectMode&&(this._signal("multiSelect"),this.inMultiSelectMode=!0,this.session.$undoSelect=!1,this.rangeList.attach(this.session)),t||this.fromOrientedRange(e)},this.toSingleRange=function(e){e=e||this.ranges[0];var t=this.rangeList.removeAll();t.length&&this.$onRemoveRange(t),e&&this.fromOrientedRange(e)},this.substractPoint=function(e){var t=this.rangeList.substractPoint(e);if(t)return this.$onRemoveRange(t),t[0]},this.mergeOverlappingRanges=function(){var e=this.rangeList.merge();e.length?this.$onRemoveRange(e):this.ranges[0]&&this.fromOrientedRange(this.ranges[0])},this.$onAddRange=function(e){this.rangeCount=this.rangeList.ranges.length,this.ranges.unshift(e),this._signal("addRange",{range:e})},this.$onRemoveRange=function(e){this.rangeCount=this.rangeList.ranges.length;if(this.rangeCount==1&&this.inMultiSelectMode){var t=this.rangeList.ranges.pop();e.push(t),this.rangeCount=0}for(var n=e.length;n--;){var r=this.ranges.indexOf(e[n]);this.ranges.splice(r,1)}this._signal("removeRange",{ranges:e}),this.rangeCount===0&&this.inMultiSelectMode&&(this.inMultiSelectMode=!1,this._signal("singleSelect"),this.session.$undoSelect=!0,this.rangeList.detach(this.session)),t=t||this.ranges[0],t&&!t.isEqual(this.getRange())&&this.fromOrientedRange(t)},this.$initRangeList=function(){if(this.rangeList)return;this.rangeList=new r,this.ranges=[],this.rangeCount=0},this.getAllRanges=function(){return this.rangeCount?this.rangeList.ranges.concat():[this.getRange()]},this.splitIntoLines=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var n=this.getRange(),r=this.isBackwards(),s=n.start.row,o=n.end.row;if(s==o){if(r)var u=n.end,a=n.start;else var u=n.start,a=n.end;this.addRange(i.fromPoints(a,a)),this.addRange(i.fromPoints(u,u));return}var f=[],l=this.getLineRange(s,!0);l.start.column=n.start.column,f.push(l);for(var c=s+1;c1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var r=this.session.documentToScreenPosition(this.selectionLead),s=this.session.documentToScreenPosition(this.selectionAnchor),o=this.rectangularRangeBlock(r,s);o.forEach(this.addRange,this)}},this.rectangularRangeBlock=function(e,t,n){var r=[],s=e.column0)d--;if(d>0){var m=0;while(r[m].isEmpty())m++}for(var g=d;g>=m;g--)r[g].isEmpty()&&r.splice(g,1)}return r}}.call(s.prototype);var d=e("./editor").Editor;(function(){this.updateSelectionMarkers=function(){this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.addSelectionMarker=function(e){e.cursor||(e.cursor=e.end);var t=this.getSelectionStyle();return e.marker=this.session.addMarker(e,"ace_selection",t),this.session.$selectionMarkers.push(e),this.session.selectionMarkerCount=this.session.$selectionMarkers.length,e},this.removeSelectionMarker=function(e){if(!e.marker)return;this.session.removeMarker(e.marker);var t=this.session.$selectionMarkers.indexOf(e);t!=-1&&this.session.$selectionMarkers.splice(t,1),this.session.selectionMarkerCount=this.session.$selectionMarkers.length},this.removeSelectionMarkers=function(e){var t=this.session.$selectionMarkers;for(var n=e.length;n--;){var r=e[n];if(!r.marker)continue;this.session.removeMarker(r.marker);var i=t.indexOf(r);i!=-1&&t.splice(i,1)}this.session.selectionMarkerCount=t.length},this.$onAddRange=function(e){this.addSelectionMarker(e.range),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onRemoveRange=function(e){this.removeSelectionMarkers(e.ranges),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelect=function(e){if(this.inMultiSelectMode)return;this.inMultiSelectMode=!0,this.setStyle("ace_multiselect"),this.keyBinding.addKeyboardHandler(f.keyboardHandler),this.commands.setDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onSingleSelect=function(e){if(this.session.multiSelect.inVirtualMode)return;this.inMultiSelectMode=!1,this.unsetStyle("ace_multiselect"),this.keyBinding.removeKeyboardHandler(f.keyboardHandler),this.commands.removeDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers(),this._emit("changeSelection")},this.$onMultiSelectExec=function(e){var t=e.command,n=e.editor;if(!n.multiSelect)return;if(!t.multiSelectAction){var r=t.exec(n,e.args||{});n.multiSelect.addRange(n.multiSelect.toOrientedRange()),n.multiSelect.mergeOverlappingRanges()}else t.multiSelectAction=="forEach"?r=n.forEachSelection(t,e.args):t.multiSelectAction=="forEachLine"?r=n.forEachSelection(t,e.args,!0):t.multiSelectAction=="single"?(n.exitMultiSelectMode(),r=t.exec(n,e.args||{})):r=t.multiSelectAction(n,e.args||{});return r},this.forEachSelection=function(e,t,n){if(this.inVirtualSelectionMode)return;var r=n&&n.keepOrder,i=n==1||n&&n.$byLines,o=this.session,u=this.selection,a=u.rangeList,f=(r?u:a).ranges,l;if(!f.length)return e.exec?e.exec(this,t||{}):e(this,t||{});var c=u._eventRegistry;u._eventRegistry={};var h=new s(o);this.inVirtualSelectionMode=!0;for(var p=f.length;p--;){if(i)while(p>0&&f[p].start.row==f[p-1].end.row)p--;h.fromOrientedRange(f[p]),h.index=p,this.selection=o.selection=h;var d=e.exec?e.exec(this,t||{}):e(this,t||{});!l&&d!==undefined&&(l=d),h.toOrientedRange(f[p])}h.detach(),this.selection=o.selection=u,this.inVirtualSelectionMode=!1,u._eventRegistry=c,u.mergeOverlappingRanges();var v=this.renderer.$scrollAnimation;return this.onCursorChange(),this.onSelectionChange(),v&&v.from==v.to&&this.renderer.animateScrolling(v.from),l},this.exitMultiSelectMode=function(){if(!this.inMultiSelectMode||this.inVirtualSelectionMode)return;this.multiSelect.toSingleRange()},this.getSelectedText=function(){var e="";if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var t=this.multiSelect.rangeList.ranges,n=[];for(var r=0;r0);u<0&&(u=0),f>=c&&(f=c-1)}var p=this.session.removeFullLines(u,f);p=this.$reAlignText(p,l),this.session.insert({row:u,column:0},p.join("\n")+"\n"),l||(o.start.column=0,o.end.column=p[p.length-1].length),this.selection.setRange(o)}else{s.forEach(function(e){t.substractPoint(e.cursor)});var d=0,v=Infinity,m=n.map(function(t){var n=t.cursor,r=e.getLine(n.row),i=r.substr(n.column).search(/\S/g);return i==-1&&(i=0),n.column>d&&(d=n.column),io?e.insert(r,a.stringRepeat(" ",s-o)):e.remove(new i(r.row,r.column,r.row,r.column-s+o)),t.start.column=t.end.column=d,t.start.row=t.end.row=r.row,t.cursor=t.end}),t.fromOrientedRange(n[0]),this.renderer.updateCursor(),this.renderer.updateBackMarkers()}},this.$reAlignText=function(e,t){function u(e){return a.stringRepeat(" ",e)}function f(e){return e[2]?u(i)+e[2]+u(s-e[2].length+o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function l(e){return e[2]?u(i+s-e[2].length)+e[2]+u(o," ")+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function c(e){return e[2]?u(i)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}var n=!0,r=!0,i,s,o;return e.map(function(e){var t=e.match(/(\s*)(.*?)(\s*)([=:].*)/);return t?i==null?(i=t[1].length,s=t[2].length,o=t[3].length,t):(i+s+o!=t[1].length+t[2].length+t[3].length&&(r=!1),i!=t[1].length&&(n=!1),i>t[1].length&&(i=t[1].length),st[3].length&&(o=t[3].length),t):[e]}).map(t?f:n?r?l:f:c)}}).call(d.prototype),t.onSessionChange=function(e){var t=e.session;t&&!t.multiSelect&&(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t&&t.multiSelect;var n=e.oldSession;n&&(n.multiSelect.off("addRange",this.$onAddRange),n.multiSelect.off("removeRange",this.$onRemoveRange),n.multiSelect.off("multiSelect",this.$onMultiSelect),n.multiSelect.off("singleSelect",this.$onSingleSelect),n.multiSelect.lead.off("change",this.$checkMultiselectChange),n.multiSelect.anchor.off("change",this.$checkMultiselectChange)),t&&(t.multiSelect.on("addRange",this.$onAddRange),t.multiSelect.on("removeRange",this.$onRemoveRange),t.multiSelect.on("multiSelect",this.$onMultiSelect),t.multiSelect.on("singleSelect",this.$onSingleSelect),t.multiSelect.lead.on("change",this.$checkMultiselectChange),t.multiSelect.anchor.on("change",this.$checkMultiselectChange)),t&&this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=m,e("./config").defineOptions(d.prototype,"editor",{enableMultiselect:{set:function(e){m(this),e?(this.on("changeSession",this.$multiselectOnSessionChange),this.on("mousedown",o)):(this.off("changeSession",this.$multiselectOnSessionChange),this.off("mousedown",o))},value:!0},enableBlockSelect:{set:function(e){this.$blockSelectEnabled=e},value:!0}})}),ace.define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../../range").Range,i=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?"start":t=="markbeginend"&&this.foldingStopMarker&&this.foldingStopMarker.test(r)?"end":""},this.getFoldWidgetRange=function(e,t,n){return null},this.indentationBlock=function(e,t,n){var i=/\S/,s=e.getLine(t),o=s.search(i);if(o==-1)return;var u=n||s.length,a=e.getLength(),f=t,l=t;while(++tf){var h=e.getLine(l).length;return new r(f,u,l,h)}},this.openingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i+1},u=e.$findClosingBracket(t,o,s);if(!u)return;var a=e.foldWidgets[u.row];return a==null&&(a=e.getFoldWidget(u.row)),a=="start"&&u.row>o.row&&(u.row--,u.column=e.getLine(u.row).length),r.fromPoints(o,u)},this.closingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i},u=e.$findOpeningBracket(t,o);if(!u)return;return u.column++,o.column--,r.fromPoints(u,o)}}).call(i.prototype)}),ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}),ace.define("ace/line_widgets",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e){this.session=e,this.session.widgetManager=this,this.session.getRowLength=this.getRowLength,this.session.$getWidgetScreenLength=this.$getWidgetScreenLength,this.updateOnChange=this.updateOnChange.bind(this),this.renderWidgets=this.renderWidgets.bind(this),this.measureWidgets=this.measureWidgets.bind(this),this.session._changedWidgets=[],this.$onChangeEditor=this.$onChangeEditor.bind(this),this.session.on("change",this.updateOnChange),this.session.on("changeFold",this.updateOnFold),this.session.on("changeEditor",this.$onChangeEditor)}var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./range").Range;(function(){this.getRowLength=function(e){var t;return this.lineWidgets?t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0:t=0,!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.$getWidgetScreenLength=function(){var e=0;return this.lineWidgets.forEach(function(t){t&&t.rowCount&&!t.hidden&&(e+=t.rowCount)}),e},this.$onChangeEditor=function(e){this.attach(e.editor)},this.attach=function(e){e&&e.widgetManager&&e.widgetManager!=this&&e.widgetManager.detach();if(this.editor==e)return;this.detach(),this.editor=e,e&&(e.widgetManager=this,e.renderer.on("beforeRender",this.measureWidgets),e.renderer.on("afterRender",this.renderWidgets))},this.detach=function(e){var t=this.editor;if(!t)return;this.editor=null,t.widgetManager=null,t.renderer.off("beforeRender",this.measureWidgets),t.renderer.off("afterRender",this.renderWidgets);var n=this.session.lineWidgets;n&&n.forEach(function(e){e&&e.el&&e.el.parentNode&&(e._inDocument=!1,e.el.parentNode.removeChild(e.el))})},this.updateOnFold=function(e,t){var n=t.lineWidgets;if(!n||!e.action)return;var r=e.data,i=r.start.row,s=r.end.row,o=e.action=="add";for(var u=i+1;u0&&!r[i])i--;this.firstRow=n.firstRow,this.lastRow=n.lastRow,t.$cursorLayer.config=n;for(var o=i;o<=s;o++){var u=r[o];if(!u||!u.el)continue;if(u.hidden){u.el.style.top=-100-(u.pixelHeight||0)+"px";continue}u._inDocument||(u._inDocument=!0,t.container.appendChild(u.el));var a=t.$cursorLayer.getPixelPosition({row:o,column:0},!0).top;u.coverLine||(a+=n.lineHeight*this.session.getRowLineCount(u.row)),u.el.style.top=a-n.offset+"px";var f=u.coverGutter?0:t.gutterWidth;u.fixedWidth||(f-=t.scrollLeft),u.el.style.left=f+"px",u.fullWidth&&u.screenWidth&&(u.el.style.minWidth=n.width+2*n.padding+"px"),u.fixedWidth?u.el.style.right=t.scrollBar.getWidth()+"px":u.el.style.right=""}}}).call(o.prototype),t.LineWidgets=o}),ace.define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e,t,n){var r=0,i=e.length-1;while(r<=i){var s=r+i>>1,o=n(t,e[s]);if(o>0)r=s+1;else{if(!(o<0))return s;i=s-1}}return-(r+1)}function u(e,t,n){var r=e.getAnnotations().sort(s.comparePoints);if(!r.length)return;var i=o(r,{row:t,column:-1},s.comparePoints);i<0&&(i=-i-1),i>=r.length?i=n>0?0:r.length-1:i===0&&n<0&&(i=r.length-1);var u=r[i];if(!u||!n)return;if(u.row===t){do u=r[i+=n];while(u&&u.row===t);if(!u)return r.slice()}var a=[];t=u.row;do a[n<0?"unshift":"push"](u),u=r[i+=n];while(u&&u.row==t);return a.length&&a}var r=e("../line_widgets").LineWidgets,i=e("../lib/dom"),s=e("../range").Range;t.showErrorMarker=function(e,t){var n=e.session;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var s=e.getCursorPosition(),o=s.row,a=n.widgetManager.getWidgetsAtRow(o).filter(function(e){return e.type=="errorMarker"})[0];a?a.destroy():o-=t;var f=u(n,o,t),l;if(f){var c=f[0];s.column=(c.pos&&typeof c.column!="number"?c.pos.sc:c.column)||0,s.row=c.row,l=e.renderer.$gutterLayer.$annotations[s.row]}else{if(a)return;l={text:["Looks good!"],className:"ace_ok"}}e.session.unfold(s.row),e.selection.moveToPosition(s);var h={row:s.row,fixedWidth:!0,coverGutter:!0,el:i.createElement("div"),type:"errorMarker"},p=h.el.appendChild(i.createElement("div")),d=h.el.appendChild(i.createElement("div"));d.className="error_widget_arrow "+l.className;var v=e.renderer.$cursorLayer.getPixelPosition(s).left;d.style.left=v+e.renderer.gutterWidth-5+"px",h.el.className="error_widget_wrapper",p.className="error_widget "+l.className,p.innerHTML=l.text.join(" "),p.appendChild(i.createElement("div"));var m=function(e,t,n){if(t===0&&(n==="esc"||n==="return"))return h.destroy(),{command:"null"}};h.destroy=function(){if(e.$mouseHandler.isMousePressed)return;e.keyBinding.removeKeyboardHandler(m),n.widgetManager.removeLineWidget(h),e.off("changeSelection",h.destroy),e.off("changeSession",h.destroy),e.off("mouseup",h.destroy),e.off("change",h.destroy)},e.keyBinding.addKeyboardHandler(m),e.on("changeSelection",h.destroy),e.on("changeSession",h.destroy),e.on("mouseup",h.destroy),e.on("change",h.destroy),e.session.widgetManager.addLineWidget(h),h.el.onmousedown=e.focus.bind(e),e.renderer.scrollCursorIntoView(null,.5,{bottom:h.el.offsetHeight})},i.importCssString(" .error_widget_wrapper { background: inherit; color: inherit; border:none } .error_widget { border-top: solid 2px; border-bottom: solid 2px; margin: 5px 0; padding: 10px 40px; white-space: pre-wrap; } .error_widget.ace_error, .error_widget_arrow.ace_error{ border-color: #ff5a5a } .error_widget.ace_warning, .error_widget_arrow.ace_warning{ border-color: #F1D817 } .error_widget.ace_info, .error_widget_arrow.ace_info{ border-color: #5a5a5a } .error_widget.ace_ok, .error_widget_arrow.ace_ok{ border-color: #5aaa5a } .error_widget_arrow { position: absolute; border: solid 5px; border-top-color: transparent!important; border-right-color: transparent!important; border-left-color: transparent!important; top: -5px; }","")}),ace.define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"],function(e,t,n){"use strict";e("./lib/fixoldbrowsers");var r=e("./lib/dom"),i=e("./lib/event"),s=e("./editor").Editor,o=e("./edit_session").EditSession,u=e("./undomanager").UndoManager,a=e("./virtual_renderer").VirtualRenderer;e("./worker/worker_client"),e("./keyboard/hash_handler"),e("./placeholder"),e("./multi_select"),e("./mode/folding/fold_mode"),e("./theme/textmate"),e("./ext/error_marker"),t.config=e("./config"),t.require=e,t.edit=function(e){if(typeof e=="string"){var n=e;e=document.getElementById(n);if(!e)throw new Error("ace.edit can't find div #"+n)}if(e&&e.env&&e.env.editor instanceof s)return e.env.editor;var o="";if(e&&/input|textarea/i.test(e.tagName)){var u=e;o=u.value,e=r.createElement("pre"),u.parentNode.replaceChild(e,u)}else e&&(o=r.getInnerText(e),e.innerHTML="");var f=t.createEditSession(o),l=new s(new a(e));l.setSession(f);var c={document:f,editor:l,onResize:l.resize.bind(l,null)};return u&&(c.textarea=u),i.addListener(window,"resize",c.onResize),l.on("destroy",function(){i.removeListener(window,"resize",c.onResize),c.editor.container.env=null}),l.container.env=l.env=c,l},t.createEditSession=function(e,t){var n=new o(e,t);return n.setUndoManager(new u),n},t.EditSession=o,t.UndoManager=u,t.version="1.2.3"});
+ (function() {
+ ace.require(["ace/ace"], function(a) {
+ a && a.config.init(true);
+ if (!window.ace)
+ window.ace = a;
+ for (var key in a) if (a.hasOwnProperty(key))
+ window.ace[key] = a[key];
+ });
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-beautify.js b/library/ace/ext-beautify.js
new file mode 100644
index 000000000..659262c8c
--- /dev/null
+++ b/library/ace/ext-beautify.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/beautify/php_rules",["require","exports","module","ace/token_iterator"],function(e,t,n){"use strict";var r=e("ace/token_iterator").TokenIterator;t.newLines=[{type:"support.php_tag",value:""},{type:"paren.lparen",value:"{",indent:!0},{type:"paren.rparen",breakBefore:!0,value:"}",indent:!1},{type:"paren.rparen",breakBefore:!0,value:"})",indent:!1,dontBreak:!0},{type:"comment"},{type:"text",value:";"},{type:"text",value:":",context:"php"},{type:"keyword",value:"case",indent:!0,dontBreak:!0},{type:"keyword",value:"default",indent:!0,dontBreak:!0},{type:"keyword",value:"break",indent:!1,dontBreak:!0},{type:"punctuation.doctype.end",value:">"},{type:"meta.tag.punctuation.end",value:">"},{type:"meta.tag.punctuation.begin",value:"<",blockTag:!0,indent:!0,dontBreak:!0},{type:"meta.tag.punctuation.begin",value:"",indent:!1,breakBefore:!0,dontBreak:!0},{type:"punctuation.operator",value:";"}],t.spaces=[{type:"xml-pe",prepend:!0},{type:"entity.other.attribute-name",prepend:!0},{type:"storage.type",value:"var",append:!0},{type:"storage.type",value:"function",append:!0},{type:"keyword.operator",value:"="},{type:"keyword",value:"as",prepend:!0,append:!0},{type:"keyword",value:"function",append:!0},{type:"support.function",next:/[^\(]/,append:!0},{type:"keyword",value:"or",append:!0,prepend:!0},{type:"keyword",value:"and",append:!0,prepend:!0},{type:"keyword",value:"case",append:!0},{type:"keyword.operator",value:"||",append:!0,prepend:!0},{type:"keyword.operator",value:"&&",append:!0,prepend:!0}],t.singleTags=["!doctype","area","base","br","hr","input","img","link","meta"],t.transform=function(e,n,r){var i=e.getCurrentToken(),s=t.newLines,o=t.spaces,u=t.singleTags,a="",f=0,l=!1,c,h,p={},d,v={},m=!1,g="";while(i!==null){console.log(i);if(!i){i=e.stepForward();continue}i.type=="support.php_tag"&&i.value!="?>"?r="php":i.type=="support.php_tag"&&i.value=="?>"?r="html":i.type=="meta.tag.name.style"&&r!="css"?r="css":i.type=="meta.tag.name.style"&&r=="css"?r="html":i.type=="meta.tag.name.script"&&r!="js"?r="js":i.type=="meta.tag.name.script"&&r=="js"&&(r="html"),v=e.stepForward(),v&&v.type.indexOf("meta.tag.name")==0&&(d=v.value),p.type=="support.php_tag"&&p.value=="="&&(l=!0),i.type=="meta.tag.name"&&(i.value=i.value.toLowerCase()),i.type=="text"&&(i.value=i.value.trim());if(!i.value){i=v;continue}g=i.value;for(var y in o)i.type==o[y].type&&(!o[y].value||i.value==o[y].value)&&v&&(!o[y].next||o[y].next.test(v.value))&&(o[y].prepend&&(g=" "+i.value),o[y].append&&(g+=" "));i.type.indexOf("meta.tag.name")==0&&(c=i.value),m=!1;for(y in s)if(i.type==s[y].type&&(!s[y].value||i.value==s[y].value)&&(!s[y].blockTag||u.indexOf(d)===-1)&&(!s[y].context||s[y].context===r)){s[y].indent===!1&&f--;if(s[y].breakBefore&&(!s[y].prev||s[y].prev.test(p.value))){a+="\n",m=!0;for(y=0;y"&&(l=!1),h=c,p=i,i=v;if(i===null)break}return a}}),ace.define("ace/ext/beautify",["require","exports","module","ace/token_iterator","ace/ext/beautify/php_rules"],function(e,t,n){"use strict";var r=e("ace/token_iterator").TokenIterator,i=e("./beautify/php_rules").transform;t.beautify=function(e){var t=new r(e,0,0),n=t.getCurrentToken(),s=e.$modeId.split("/").pop(),o=i(t,s);e.doc.setValue(o)},t.commands=[{name:"beautify",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]});
+ (function() {
+ ace.require(["ace/ext/beautify"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-chromevox.js b/library/ace/ext-chromevox.js
new file mode 100644
index 000000000..afaad86e7
--- /dev/null
+++ b/library/ace/ext-chromevox.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/chromevox",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function gt(){return typeof cvox!="undefined"&&cvox&&cvox.Api}function wt(e){if(gt())mt(e);else{yt++;if(yt>=bt)return;window.setTimeout(wt,500,e)}}var r={};r.SpeechProperty,r.Cursor,r.Token,r.Annotation;var i={rate:.8,pitch:.4,volume:.9},s={rate:1,pitch:.5,volume:.9},o={rate:.8,pitch:.8,volume:.9},u={rate:.8,pitch:.3,volume:.9},a={rate:.8,pitch:.7,volume:.9},f={rate:.8,pitch:.8,volume:.9},l={punctuationEcho:"none",relativePitch:-0.6},c="ALERT_NONMODAL",h="ALERT_MODAL",p="INVALID_KEYPRESS",d="insertMode",v="start",m=[{substr:";",newSubstr:" semicolon "},{substr:":",newSubstr:" colon "}],g={SPEAK_ANNOT:"annots",SPEAK_ALL_ANNOTS:"all_annots",TOGGLE_LOCATION:"toggle_location",SPEAK_MODE:"mode",SPEAK_ROW_COL:"row_col",TOGGLE_DISPLACEMENT:"toggle_displacement",FOCUS_TEXT:"focus_text"},y="CONTROL + SHIFT ";r.editor=null;var b=null,w={},E=!1,S=!1,x=!1,T=null,N={},C={},k=function(e){return y+String.fromCharCode(e)},L=function(){var e=r.editor.keyBinding.getKeyboardHandler();return e.$id==="ace/keyboard/vim"},A=function(e){return r.editor.getSession().getTokenAt(e.row,e.column+1)},O=function(e){return r.editor.getSession().getLine(e.row)},M=function(e){w[e.row]&&cvox.Api.playEarcon(c),E?(cvox.Api.stop(),W(e),R(A(e)),I(e.row,1)):I(e.row,0)},_=function(e){var t=O(e),n=t.substr(e.column-1);e.column===0&&(n=" "+t);var r=/^\W(\w+)/,i=r.exec(n);return i!==null},D={constant:{prop:i},entity:{prop:o},keyword:{prop:u},storage:{prop:a},variable:{prop:f},meta:{prop:s,replace:[{substr:"",newSubstr:" closing tag "},{substr:"/>",newSubstr:" close tag "},{substr:"<",newSubstr:" tag start "},{substr:">",newSubstr:" tag end "}]}},P={prop:P},H=function(e,t){var n=e;for(var r=0;r0&&cvox.Api.playEarcon(c),Y(t)},et=function(e){var t=e.type+" "+e.text+" on "+nt(e.row,e.column);t=t.replace(";","semicolon"),cvox.Api.speak(t,1)},tt=function(e){var t=w[e];for(var n in t)et(t[n])},nt=function(e,t){return"row "+(e+1)+" column "+(t+1)},rt=function(){cvox.Api.speak(nt(b.row,b.column))},it=function(){for(var e in w)tt(e)},st=function(){if(!L())return;switch(r.editor.keyBinding.$data.state){case d:cvox.Api.speak("Insert mode");break;case v:cvox.Api.speak("Command mode")}},ot=function(){E=!E,E?cvox.Api.speak("Speak location on row change enabled."):cvox.Api.speak("Speak location on row change disabled.")},ut=function(){S=!S,S?cvox.Api.speak("Speak displacement on column changes."):cvox.Api.speak("Speak current character or word on column changes.")},at=function(e){if(e.ctrlKey&&e.shiftKey){var t=N[e.keyCode];t&&t.func()}},ft=function(e,t){if(!L())return;var n=t.keyBinding.$data.state;if(n===T)return;switch(n){case d:cvox.Api.playEarcon(h),cvox.Api.setKeyEcho(!0);break;case v:cvox.Api.playEarcon(h),cvox.Api.setKeyEcho(!1)}T=n},lt=function(e){var t=e.detail.customCommand,n=C[t];n&&(n.func(),r.editor.focus())},ct=function(){var e=dt.map(function(e){return{desc:e.desc+k(e.keyCode),cmd:e.cmd}}),t=document.querySelector("body");t.setAttribute("contextMenuActions",JSON.stringify(e)),t.addEventListener("ATCustomEvent",lt,!0)},ht=function(e){e.match?I(b.row,0):cvox.Api.playEarcon(p)},pt=function(){r.editor.focus()},dt=[{keyCode:49,func:function(){tt(b.row)},cmd:g.SPEAK_ANNOT,desc:"Speak annotations on line"},{keyCode:50,func:it,cmd:g.SPEAK_ALL_ANNOTS,desc:"Speak all annotations"},{keyCode:51,func:st,cmd:g.SPEAK_MODE,desc:"Speak Vim mode"},{keyCode:52,func:ot,cmd:g.TOGGLE_LOCATION,desc:"Toggle speak row location"},{keyCode:53,func:rt,cmd:g.SPEAK_ROW_COL,desc:"Speak row and column"},{keyCode:54,func:ut,cmd:g.TOGGLE_DISPLACEMENT,desc:"Toggle speak displacement"},{keyCode:55,func:pt,cmd:g.FOCUS_TEXT,desc:"Focus text"}],vt=function(e,t){r.editor=t,t.getSession().selection.on("changeCursor",J),t.getSession().selection.on("changeSelection",K),t.getSession().on("change",Q),t.getSession().on("changeAnnotation",Z),t.on("changeStatus",ft),t.on("findSearchBox",ht),t.container.addEventListener("keydown",at),b=t.selection.getCursor()},mt=function(e){vt(null,e),dt.forEach(function(e){N[e.keyCode]=e,C[e.cmd]=e}),e.on("focus",vt),L()&&cvox.Api.setKeyEcho(!1),ct()},yt=0,bt=15,Et=e("../editor").Editor;e("../config").defineOptions(Et.prototype,"editor",{enableChromevoxEnhancements:{set:function(e){e&&wt(this)},value:!0}})});
+ (function() {
+ ace.require(["ace/ext/chromevox"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-elastic_tabstops_lite.js b/library/ace/ext-elastic_tabstops_lite.js
new file mode 100644
index 000000000..bae2275a4
--- /dev/null
+++ b/library/ace/ext-elastic_tabstops_lite.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";var r=function(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){r&&(n.indexOf(e.start.row)==-1&&n.push(e.start.row),e.end.row!=e.start.row&&n.push(e.end.row))}};(function(){this.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+" "),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},this.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;rt&&(t=i)}var s=[];for(var o=0;o=t.length?t.length:e.length,r=[];for(var i=0;i"a"})),[e]}},{regex:/}/,onMatch:function(e,t,n){return[n.length?n.shift():e]}},{regex:/\$(?:\d+|\w+)/,onMatch:e},{regex:/\$\{[\dA-Z_a-z]+/,onMatch:function(t,n,r){var i=e(t.substr(1),n,r);return r.unshift(i[0]),i},next:"snippetVar"},{regex:/\n/,token:"newline",merge:!1}],snippetVar:[{regex:"\\|"+t("\\|")+"*\\|",onMatch:function(e,t,n){n[0].choices=e.slice(1,-1).split(",")},next:"start"},{regex:"/("+t("/")+"+)/(?:("+t("/")+"*)/)(\\w*):?",onMatch:function(e,t,n){var r=n[0];return r.fmtString=e,e=this.splitRegex.exec(e),r.guard=e[1],r.fmt=e[2],r.flag=e[3],""},next:"start"},{regex:"`"+t("`")+"*`",onMatch:function(e,t,n){return n[0].code=e.splice(1,-1),""},next:"start"},{regex:"\\?",onMatch:function(e,t,n){n[0]&&(n[0].expectIf=!0)},next:"start"},{regex:"([^:}\\\\]|\\\\.)*:?",token:"",next:"start"}],formatString:[{regex:"/("+t("/")+"+)/",token:"regex"},{regex:"",onMatch:function(e,t,n){n.inFormatString=!0},next:"start"}]}),c.prototype.getTokenizer=function(){return c.$tokenizer},c.$tokenizer},this.tokenizeTmSnippet=function(e,t){return this.getTokenizer().getLineTokens(e,t).tokens.map(function(e){return e.value||e})},this.$getDefaultValue=function(e,t){if(/^[A-Z]\d+$/.test(t)){var n=t.substr(1);return(this.variables[t[0]+"__"]||{})[n]}if(/^\d+$/.test(t))return(this.variables.__||{})[t];t=t.replace(/^TM_/,"");if(!e)return;var r=e.session;switch(t){case"CURRENT_WORD":var i=r.getWordRange();case"SELECTION":case"SELECTED_TEXT":return r.getTextRange(i);case"CURRENT_LINE":return r.getLine(e.getCursorPosition().row);case"PREV_LINE":return r.getLine(e.getCursorPosition().row-1);case"LINE_INDEX":return e.getCursorPosition().column;case"LINE_NUMBER":return e.getCursorPosition().row+1;case"SOFT_TABS":return r.getUseSoftTabs()?"YES":"NO";case"TAB_SIZE":return r.getTabSize();case"FILENAME":case"FILEPATH":return"";case"FULLNAME":return"Ace"}},this.variables={},this.getVariableValue=function(e,t){return this.variables.hasOwnProperty(t)?this.variables[t](e,t)||"":this.$getDefaultValue(e,t)||""},this.tmStrFormat=function(e,t,n){var r=t.flag||"",i=t.guard;i=new RegExp(i,r.replace(/[^gi]/,""));var s=this.tokenizeTmSnippet(t.fmt,"formatString"),o=this,u=e.replace(i,function(){o.variables.__=arguments;var e=o.resolveVariables(s,n),t="E";for(var r=0;r=0&&s.splice(o,1)}}var n=this.snippetMap,r=this.snippetNameMap;e.content?i(e):Array.isArray(e)&&e.forEach(i)},this.parseSnippetFile=function(e){e=e.replace(/\r/g,"");var t=[],n={},r=/^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm,i;while(i=r.exec(e)){if(i[1])try{n=JSON.parse(i[1]),t.push(n)}catch(s){}if(i[4])n.content=i[4].replace(/^\t/gm,""),t.push(n),n={};else{var o=i[2],u=i[3];if(o=="regex"){var a=/\/((?:[^\/\\]|\\.)*)|$/g;n.guard=a.exec(u)[1],n.trigger=a.exec(u)[1],n.endTrigger=a.exec(u)[1],n.endGuard=a.exec(u)[1]}else o=="snippet"?(n.tabTrigger=u.match(/^\S*/)[0],n.name||(n.name=u)):n[o]=u}}return t},this.getSnippetByName=function(e,t){var n=this.snippetNameMap,r;return this.getActiveScopes(t).some(function(t){var i=n[t];return i&&(r=i[e]),!!r},this),r}}).call(c.prototype);var h=function(e){if(e.tabstopManager)return e.tabstopManager;e.tabstopManager=this,this.$onChange=this.onChange.bind(this),this.$onChangeSelection=s.delayedCall(this.onChangeSelection.bind(this)).schedule,this.$onChangeSession=this.onChangeSession.bind(this),this.$onAfterExec=this.onAfterExec.bind(this),this.attach(e)};(function(){this.attach=function(e){this.index=0,this.ranges=[],this.tabstops=[],this.$openTabstops=null,this.selectedTabstop=null,this.editor=e,this.editor.on("change",this.$onChange),this.editor.on("changeSelection",this.$onChangeSelection),this.editor.on("changeSession",this.$onChangeSession),this.editor.commands.on("afterExec",this.$onAfterExec),this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.detach=function(){this.tabstops.forEach(this.removeTabstopMarkers,this),this.ranges=null,this.tabstops=null,this.selectedTabstop=null,this.editor.removeListener("change",this.$onChange),this.editor.removeListener("changeSelection",this.$onChangeSelection),this.editor.removeListener("changeSession",this.$onChangeSession),this.editor.commands.removeListener("afterExec",this.$onAfterExec),this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.tabstopManager=null,this.editor=null},this.onChange=function(e){var t=e,n=e.action[0]=="r",r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=i.column-r.column;n&&(u=-u,a=-a);if(!this.$inChange&&n){var f=this.selectedTabstop,c=f&&!f.some(function(e){return l(e.start,r)<=0&&l(e.end,i)>=0});if(c)return this.detach()}var h=this.ranges;for(var p=0;p0){this.removeRange(d),p--;continue}d.start.row==s&&d.start.column>r.column&&(d.start.column+=a),d.end.row==s&&d.end.column>=r.column&&(d.end.column+=a),d.start.row>=s&&(d.start.row+=u),d.end.row>=s&&(d.end.row+=u),l(d.start,d.end)>0&&this.removeRange(d)}h.length||this.detach()},this.updateLinkedFields=function(){var e=this.selectedTabstop;if(!e||!e.hasLinkedRanges)return;this.$inChange=!0;var n=this.editor.session,r=n.getTextRange(e.firstNonLinked);for(var i=e.length;i--;){var s=e[i];if(!s.linked)continue;var o=t.snippetManager.tmStrFormat(r,s.original);n.replace(s,o)}this.$inChange=!1},this.onAfterExec=function(e){e.command&&!e.command.readOnly&&this.updateLinkedFields()},this.onChangeSelection=function(){if(!this.editor)return;var e=this.editor.selection.lead,t=this.editor.selection.anchor,n=this.editor.selection.isEmpty();for(var r=this.ranges.length;r--;){if(this.ranges[r].linked)continue;var i=this.ranges[r].contains(e.row,e.column),s=n||this.ranges[r].contains(t.row,t.column);if(i&&s)return}this.detach()},this.onChangeSession=function(){this.detach()},this.tabNext=function(e){var t=this.tabstops.length,n=this.index+(e||1);n=Math.min(Math.max(n,1),t),n==t&&(n=0),this.selectTabstop(n),n===0&&this.detach()},this.selectTabstop=function(e){this.$openTabstops=null;var t=this.tabstops[this.index];t&&this.addTabstopMarkers(t),this.index=e,t=this.tabstops[this.index];if(!t||!t.length)return;this.selectedTabstop=t;if(!this.editor.inVirtualSelectionMode){var n=this.editor.multiSelect;n.toSingleRange(t.firstNonLinked.clone());for(var r=t.length;r--;){if(t.hasLinkedRanges&&t[r].linked)continue;n.addRange(t[r].clone(),!0)}n.ranges[0]&&n.addRange(n.ranges[0].clone())}else this.editor.selection.setRange(t.firstNonLinked);this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.addTabstops=function(e,t,n){this.$openTabstops||(this.$openTabstops=[]);if(!e[0]){var r=o.fromPoints(n,n);v(r.start,t),v(r.end,t),e[0]=[r],e[0].index=0}var i=this.index,s=[i+1,0],u=this.ranges;e.forEach(function(e,n){var r=this.$openTabstops[n]||e;for(var i=e.length;i--;){var a=e[i],f=o.fromPoints(a.start,a.end||a.start);d(f.start,t),d(f.end,t),f.original=a,f.tabstop=r,u.push(f),r!=e?r.unshift(f):r[i]=f,a.fmtString?(f.linked=!0,r.hasLinkedRanges=!0):r.firstNonLinked||(r.firstNonLinked=f)}r.firstNonLinked||(r.hasLinkedRanges=!1),r===e&&(s.push(r),this.$openTabstops[n]=r),this.addTabstopMarkers(r)},this),s.length>2&&(this.tabstops.length&&s.push(s.splice(2,1)[0]),this.tabstops.splice.apply(this.tabstops,s))},this.addTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){e.markerId||(e.markerId=t.addMarker(e,"ace_snippet-marker","text"))})},this.removeTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){t.removeMarker(e.markerId),e.markerId=null})},this.removeRange=function(e){var t=e.tabstop.indexOf(e);e.tabstop.splice(t,1),t=this.ranges.indexOf(e),this.ranges.splice(t,1),this.editor.session.removeMarker(e.markerId),e.tabstop.length||(t=this.tabstops.indexOf(e.tabstop),t!=-1&&this.tabstops.splice(t,1),this.tabstops.length||this.detach())},this.keyboardHandler=new a,this.keyboardHandler.bindKeys({Tab:function(e){if(t.snippetManager&&t.snippetManager.expandWithTab(e))return;e.tabstopManager.tabNext(1)},"Shift-Tab":function(e){e.tabstopManager.tabNext(-1)},Esc:function(e){e.tabstopManager.detach()},Return:function(e){return!1}})}).call(h.prototype);var p={};p.onChange=u.prototype.onChange,p.setPosition=function(e,t){this.pos.row=e,this.pos.column=t},p.update=function(e,t,n){this.$insertRight=n,this.pos=e,this.onChange(t)};var d=function(e,t){e.row==0&&(e.column+=t.column),e.row+=t.row},v=function(e,t){e.row==t.row&&(e.column-=t.column),e.row-=t.row};e("./lib/dom").importCssString(".ace_snippet-marker { -moz-box-sizing: border-box; box-sizing: border-box; background: rgba(194, 193, 208, 0.09); border: 1px dotted rgba(211, 208, 235, 0.62); position: absolute;}"),t.snippetManager=new c;var m=e("./editor").Editor;(function(){this.insertSnippet=function(e,n){return t.snippetManager.insertSnippet(this,e,n)},this.expandSnippet=function(e){return t.snippetManager.expandWithTab(this,e)}}).call(m.prototype)}),ace.define("ace/ext/emmet",["require","exports","module","ace/keyboard/hash_handler","ace/editor","ace/snippets","ace/range","resources","resources","range","tabStops","resources","utils","actions","ace/config","ace/config"],function(e,t,n){"use strict";function f(){}var r=e("ace/keyboard/hash_handler").HashHandler,i=e("ace/editor").Editor,s=e("ace/snippets").snippetManager,o=e("ace/range").Range,u,a;f.prototype={setupContext:function(e){this.ace=e,this.indentation=e.session.getTabString(),u||(u=window.emmet),u.require("resources").setVariable("indentation",this.indentation),this.$syntax=null,this.$syntax=this.getSyntax()},getSelectionRange:function(){var e=this.ace.getSelectionRange(),t=this.ace.session.doc;return{start:t.positionToIndex(e.start),end:t.positionToIndex(e.end)}},createSelection:function(e,t){var n=this.ace.session.doc;this.ace.selection.setRange({start:n.indexToPosition(e),end:n.indexToPosition(t)})},getCurrentLineRange:function(){var e=this.ace,t=e.getCursorPosition().row,n=e.session.getLine(t).length,r=e.session.doc.positionToIndex({row:t,column:0});return{start:r,end:r+n}},getCaretPos:function(){var e=this.ace.getCursorPosition();return this.ace.session.doc.positionToIndex(e)},setCaretPos:function(e){var t=this.ace.session.doc.indexToPosition(e);this.ace.selection.moveToPosition(t)},getCurrentLine:function(){var e=this.ace.getCursorPosition().row;return this.ace.session.getLine(e)},replaceContent:function(e,t,n,r){n==null&&(n=t==null?this.getContent().length:t),t==null&&(t=0);var i=this.ace,u=i.session.doc,a=o.fromPoints(u.indexToPosition(t),u.indexToPosition(n));i.session.remove(a),a.end=a.start,e=this.$updateTabstops(e),s.insertSnippet(i,e)},getContent:function(){return this.ace.getValue()},getSyntax:function(){if(this.$syntax)return this.$syntax;var e=this.ace.session.$modeId.split("/").pop();if(e=="html"||e=="php"){var t=this.ace.getCursorPosition(),n=this.ace.session.getState(t.row);typeof n!="string"&&(n=n[0]),n&&(n=n.split("-"),n.length>1?e=n[0]:e=="php"&&(e="html"))}return e},getProfileName:function(){switch(this.getSyntax()){case"css":return"css";case"xml":case"xsl":return"xml";case"html":var e=u.require("resources").getVariable("profile");return e||(e=this.ace.session.getLines(0,2).join("").search(/]+XHTML/i)!=-1?"xhtml":"html"),e;default:var t=this.ace.session.$mode;return t.emmetConfig&&t.emmetConfig.profile||"xhtml"}},prompt:function(e){return prompt(e)},getSelection:function(){return this.ace.session.getTextRange()},getFilePath:function(){return""},$updateTabstops:function(e){var t=1e3,n=0,r=null,i=u.require("range"),s=u.require("tabStops"),o=u.require("resources").getVocabulary("user"),a={tabstop:function(e){var o=parseInt(e.group,10),u=o===0;u?o=++n:o+=t;var f=e.placeholder;f&&(f=s.processText(f,a));var l="${"+o+(f?":"+f:"")+"}";return u&&(r=i.create(e.start,l)),l},escape:function(e){return e=="$"?"\\$":e=="\\"?"\\\\":e}};return e=s.processText(e,a),o.variables.insert_final_tabstop&&!/\$\{0\}$/.test(e)?e+="${0}":r&&(e=u.require("utils").replaceSubstring(e,"${0}",r)),e}};var l={expand_abbreviation:{mac:"ctrl+alt+e",win:"alt+e"},match_pair_outward:{mac:"ctrl+d",win:"ctrl+,"},match_pair_inward:{mac:"ctrl+j",win:"ctrl+shift+0"},matching_pair:{mac:"ctrl+alt+j",win:"alt+j"},next_edit_point:"alt+right",prev_edit_point:"alt+left",toggle_comment:{mac:"command+/",win:"ctrl+/"},split_join_tag:{mac:"shift+command+'",win:"shift+ctrl+`"},remove_tag:{mac:"command+'",win:"shift+ctrl+;"},evaluate_math_expression:{mac:"shift+command+y",win:"shift+ctrl+y"},increment_number_by_1:"ctrl+up",decrement_number_by_1:"ctrl+down",increment_number_by_01:"alt+up",decrement_number_by_01:"alt+down",increment_number_by_10:{mac:"alt+command+up",win:"shift+alt+up"},decrement_number_by_10:{mac:"alt+command+down",win:"shift+alt+down"},select_next_item:{mac:"shift+command+.",win:"shift+ctrl+."},select_previous_item:{mac:"shift+command+,",win:"shift+ctrl+,"},reflect_css_value:{mac:"shift+command+r",win:"shift+ctrl+r"},encode_decode_data_url:{mac:"shift+ctrl+d",win:"ctrl+'"},expand_abbreviation_with_tab:"Tab",wrap_with_abbreviation:{mac:"shift+ctrl+a",win:"shift+ctrl+a"}},c=new f;t.commands=new r,t.runEmmetCommand=function v(e){try{c.setupContext(e);var t=u.require("actions");if(this.action=="expand_abbreviation_with_tab"){if(!e.selection.isEmpty())return!1;var n=e.selection.lead,r=e.session.getTokenAt(n.row,n.column);if(r&&/\btag\b/.test(r.type))return!1}if(this.action=="wrap_with_abbreviation")return setTimeout(function(){t.run("wrap_with_abbreviation",c)},0);var i=t.run(this.action,c)}catch(s){if(!u)return d(v.bind(this,e)),!0;e._signal("changeStatus",typeof s=="string"?s:s.message),console.log(s),i=!1}return i};for(var h in l)t.commands.addCommand({name:"emmet:"+h,action:h,bindKey:l[h],exec:t.runEmmetCommand,multiSelectAction:"forEach"});t.updateCommands=function(e,n){n?e.keyBinding.addKeyboardHandler(t.commands):e.keyBinding.removeKeyboardHandler(t.commands)},t.isSupportedMode=function(e){if(!e)return!1;if(e.emmetConfig)return!0;var t=e.$id||e;return/css|less|scss|sass|stylus|html|php|twig|ejs|handlebars/.test(t)},t.isAvailable=function(e,n){if(/(evaluate_math_expression|expand_abbreviation)$/.test(n))return!0;var r=e.session.$mode,i=t.isSupportedMode(r);if(i&&r.$modes)try{c.setupContext(e),/js|php/.test(c.getSyntax())&&(i=!1)}catch(s){}return i};var p=function(e,n){var r=n;if(!r)return;var i=t.isSupportedMode(r.session.$mode);e.enableEmmet===!1&&(i=!1),i&&d(),t.updateCommands(r,i)},d=function(t){typeof a=="string"&&e("ace/config").loadModule(a,function(){a=null,t&&t()})};t.AceEmmetEditor=f,e("ace/config").defineOptions(i.prototype,"editor",{enableEmmet:{set:function(e){this[e?"on":"removeListener"]("changeMode",p),p({enableEmmet:!!e},this)},value:!0}}),t.setCore=function(e){typeof e=="string"?a=e:u=e}});
+ (function() {
+ ace.require(["ace/ext/emmet"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-error_marker.js b/library/ace/ext-error_marker.js
new file mode 100644
index 000000000..dfefa20ab
--- /dev/null
+++ b/library/ace/ext-error_marker.js
@@ -0,0 +1,5 @@
+;
+ (function() {
+ ace.require(["ace/ext/error_marker"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-keybinding_menu.js b/library/ace/ext-keybinding_menu.js
new file mode 100644
index 000000000..f73cf44ce
--- /dev/null
+++ b/library/ace/ext-keybinding_menu.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../../lib/dom"),i="#ace_settingsmenu, #kbshortcutmenu {background-color: #F7F7F7;color: black;box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);padding: 1em 0.5em 2em 1em;overflow: auto;position: absolute;margin: 0;bottom: 0;right: 0;top: 0;z-index: 9991;cursor: default;}.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);background-color: rgba(255, 255, 255, 0.6);color: black;}.ace_optionsMenuEntry:hover {background-color: rgba(100, 100, 100, 0.1);-webkit-transition: all 0.5s;transition: all 0.3s}.ace_closeButton {background: rgba(245, 146, 146, 0.5);border: 1px solid #F48A8A;border-radius: 50%;padding: 7px;position: absolute;right: -8px;top: -8px;z-index: 1000;}.ace_closeButton{background: rgba(245, 146, 146, 0.9);}.ace_optionsMenuKey {color: darkslateblue;font-weight: bold;}.ace_optionsMenuCommand {color: darkcyan;font-weight: normal;}";r.importCssString(i),n.exports.overlayPage=function(t,n,i,s,o,u){function l(e){e.keyCode===27&&a.click()}i=i?"top: "+i+";":"",o=o?"bottom: "+o+";":"",s=s?"right: "+s+";":"",u=u?"left: "+u+";":"";var a=document.createElement("div"),f=document.createElement("div");a.style.cssText="margin: 0; padding: 0; position: fixed; top:0; bottom:0; left:0; right:0;z-index: 9990; background-color: rgba(0, 0, 0, 0.3);",a.addEventListener("click",function(){document.removeEventListener("keydown",l),a.parentNode.removeChild(a),t.focus(),a=null}),document.addEventListener("keydown",l),f.style.cssText=i+s+o+u,f.addEventListener("click",function(e){e.stopPropagation()});var c=r.createElement("div");c.style.position="relative";var h=r.createElement("div");h.className="ace_closeButton",h.addEventListener("click",function(){a.click()}),c.appendChild(h),f.appendChild(c),f.appendChild(n),a.appendChild(f),document.body.appendChild(a),t.blur()}}),ace.define("ace/ext/menu_tools/get_editor_keyboard_shortcuts",["require","exports","module","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../../lib/keys");n.exports.getEditorKeybordShortcuts=function(e){var t=r.KEY_MODS,n=[],i={};return e.keyBinding.$handlers.forEach(function(e){var t=e.commandKeyBinding;for(var r in t){var s=r.replace(/(^|-)\w/g,function(e){return e.toUpperCase()}),o=t[r];Array.isArray(o)||(o=[o]),o.forEach(function(e){typeof e!="string"&&(e=e.name),i[e]?i[e].key+="|"+s:(i[e]={key:s,command:e},n.push(i[e]))})}}),n}}),ace.define("ace/ext/keybinding_menu",["require","exports","module","ace/editor","ace/ext/menu_tools/overlay_page","ace/ext/menu_tools/get_editor_keyboard_shortcuts"],function(e,t,n){"use strict";function i(t){if(!document.getElementById("kbshortcutmenu")){var n=e("./menu_tools/overlay_page").overlayPage,r=e("./menu_tools/get_editor_keyboard_shortcuts").getEditorKeybordShortcuts,i=r(t),s=document.createElement("div"),o=i.reduce(function(e,t){return e+'"},"");s.id="kbshortcutmenu",s.innerHTML="Keyboard Shortcuts "+o+"",n(t,s,"0","0","0",null)}}var r=e("ace/editor").Editor;n.exports.init=function(e){r.prototype.showKeyboardShortcuts=function(){i(this)},e.commands.addCommands([{name:"showKeyboardShortcuts",bindKey:{win:"Ctrl-Alt-h",mac:"Command-Alt-h"},exec:function(e,t){e.showKeyboardShortcuts()}}])}});
+ (function() {
+ ace.require(["ace/ext/keybinding_menu"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-language_tools.js b/library/ace/ext-language_tools.js
new file mode 100644
index 000000000..0a754c2bd
--- /dev/null
+++ b/library/ace/ext-language_tools.js
@@ -0,0 +1,5 @@
+ace.define("ace/snippets",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/lib/lang","ace/range","ace/anchor","ace/keyboard/hash_handler","ace/tokenizer","ace/lib/dom","ace/editor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=e("./lib/lang"),o=e("./range").Range,u=e("./anchor").Anchor,a=e("./keyboard/hash_handler").HashHandler,f=e("./tokenizer").Tokenizer,l=o.comparePoints,c=function(){this.snippetMap={},this.snippetNameMap={}};(function(){r.implement(this,i),this.getTokenizer=function(){function e(e,t,n){return e=e.substr(1),/^\d+$/.test(e)&&!n.inFormatString?[{tabstopId:parseInt(e,10)}]:[{text:e}]}function t(e){return"(?:[^\\\\"+e+"]|\\\\.)"}return c.$tokenizer=new f({start:[{regex:/:/,onMatch:function(e,t,n){return n.length&&n[0].expectIf?(n[0].expectIf=!1,n[0].elseBranch=n[0],[n[0]]):":"}},{regex:/\\./,onMatch:function(e,t,n){var r=e[1];return r=="}"&&n.length?e=r:"`$\\".indexOf(r)!=-1?e=r:n.inFormatString&&(r=="n"?e="\n":r=="t"?e="\n":"ulULE".indexOf(r)!=-1&&(e={changeCase:r,local:r>"a"})),[e]}},{regex:/}/,onMatch:function(e,t,n){return[n.length?n.shift():e]}},{regex:/\$(?:\d+|\w+)/,onMatch:e},{regex:/\$\{[\dA-Z_a-z]+/,onMatch:function(t,n,r){var i=e(t.substr(1),n,r);return r.unshift(i[0]),i},next:"snippetVar"},{regex:/\n/,token:"newline",merge:!1}],snippetVar:[{regex:"\\|"+t("\\|")+"*\\|",onMatch:function(e,t,n){n[0].choices=e.slice(1,-1).split(",")},next:"start"},{regex:"/("+t("/")+"+)/(?:("+t("/")+"*)/)(\\w*):?",onMatch:function(e,t,n){var r=n[0];return r.fmtString=e,e=this.splitRegex.exec(e),r.guard=e[1],r.fmt=e[2],r.flag=e[3],""},next:"start"},{regex:"`"+t("`")+"*`",onMatch:function(e,t,n){return n[0].code=e.splice(1,-1),""},next:"start"},{regex:"\\?",onMatch:function(e,t,n){n[0]&&(n[0].expectIf=!0)},next:"start"},{regex:"([^:}\\\\]|\\\\.)*:?",token:"",next:"start"}],formatString:[{regex:"/("+t("/")+"+)/",token:"regex"},{regex:"",onMatch:function(e,t,n){n.inFormatString=!0},next:"start"}]}),c.prototype.getTokenizer=function(){return c.$tokenizer},c.$tokenizer},this.tokenizeTmSnippet=function(e,t){return this.getTokenizer().getLineTokens(e,t).tokens.map(function(e){return e.value||e})},this.$getDefaultValue=function(e,t){if(/^[A-Z]\d+$/.test(t)){var n=t.substr(1);return(this.variables[t[0]+"__"]||{})[n]}if(/^\d+$/.test(t))return(this.variables.__||{})[t];t=t.replace(/^TM_/,"");if(!e)return;var r=e.session;switch(t){case"CURRENT_WORD":var i=r.getWordRange();case"SELECTION":case"SELECTED_TEXT":return r.getTextRange(i);case"CURRENT_LINE":return r.getLine(e.getCursorPosition().row);case"PREV_LINE":return r.getLine(e.getCursorPosition().row-1);case"LINE_INDEX":return e.getCursorPosition().column;case"LINE_NUMBER":return e.getCursorPosition().row+1;case"SOFT_TABS":return r.getUseSoftTabs()?"YES":"NO";case"TAB_SIZE":return r.getTabSize();case"FILENAME":case"FILEPATH":return"";case"FULLNAME":return"Ace"}},this.variables={},this.getVariableValue=function(e,t){return this.variables.hasOwnProperty(t)?this.variables[t](e,t)||"":this.$getDefaultValue(e,t)||""},this.tmStrFormat=function(e,t,n){var r=t.flag||"",i=t.guard;i=new RegExp(i,r.replace(/[^gi]/,""));var s=this.tokenizeTmSnippet(t.fmt,"formatString"),o=this,u=e.replace(i,function(){o.variables.__=arguments;var e=o.resolveVariables(s,n),t="E";for(var r=0;r=0&&s.splice(o,1)}}var n=this.snippetMap,r=this.snippetNameMap;e.content?i(e):Array.isArray(e)&&e.forEach(i)},this.parseSnippetFile=function(e){e=e.replace(/\r/g,"");var t=[],n={},r=/^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm,i;while(i=r.exec(e)){if(i[1])try{n=JSON.parse(i[1]),t.push(n)}catch(s){}if(i[4])n.content=i[4].replace(/^\t/gm,""),t.push(n),n={};else{var o=i[2],u=i[3];if(o=="regex"){var a=/\/((?:[^\/\\]|\\.)*)|$/g;n.guard=a.exec(u)[1],n.trigger=a.exec(u)[1],n.endTrigger=a.exec(u)[1],n.endGuard=a.exec(u)[1]}else o=="snippet"?(n.tabTrigger=u.match(/^\S*/)[0],n.name||(n.name=u)):n[o]=u}}return t},this.getSnippetByName=function(e,t){var n=this.snippetNameMap,r;return this.getActiveScopes(t).some(function(t){var i=n[t];return i&&(r=i[e]),!!r},this),r}}).call(c.prototype);var h=function(e){if(e.tabstopManager)return e.tabstopManager;e.tabstopManager=this,this.$onChange=this.onChange.bind(this),this.$onChangeSelection=s.delayedCall(this.onChangeSelection.bind(this)).schedule,this.$onChangeSession=this.onChangeSession.bind(this),this.$onAfterExec=this.onAfterExec.bind(this),this.attach(e)};(function(){this.attach=function(e){this.index=0,this.ranges=[],this.tabstops=[],this.$openTabstops=null,this.selectedTabstop=null,this.editor=e,this.editor.on("change",this.$onChange),this.editor.on("changeSelection",this.$onChangeSelection),this.editor.on("changeSession",this.$onChangeSession),this.editor.commands.on("afterExec",this.$onAfterExec),this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.detach=function(){this.tabstops.forEach(this.removeTabstopMarkers,this),this.ranges=null,this.tabstops=null,this.selectedTabstop=null,this.editor.removeListener("change",this.$onChange),this.editor.removeListener("changeSelection",this.$onChangeSelection),this.editor.removeListener("changeSession",this.$onChangeSession),this.editor.commands.removeListener("afterExec",this.$onAfterExec),this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.tabstopManager=null,this.editor=null},this.onChange=function(e){var t=e,n=e.action[0]=="r",r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=i.column-r.column;n&&(u=-u,a=-a);if(!this.$inChange&&n){var f=this.selectedTabstop,c=f&&!f.some(function(e){return l(e.start,r)<=0&&l(e.end,i)>=0});if(c)return this.detach()}var h=this.ranges;for(var p=0;p0){this.removeRange(d),p--;continue}d.start.row==s&&d.start.column>r.column&&(d.start.column+=a),d.end.row==s&&d.end.column>=r.column&&(d.end.column+=a),d.start.row>=s&&(d.start.row+=u),d.end.row>=s&&(d.end.row+=u),l(d.start,d.end)>0&&this.removeRange(d)}h.length||this.detach()},this.updateLinkedFields=function(){var e=this.selectedTabstop;if(!e||!e.hasLinkedRanges)return;this.$inChange=!0;var n=this.editor.session,r=n.getTextRange(e.firstNonLinked);for(var i=e.length;i--;){var s=e[i];if(!s.linked)continue;var o=t.snippetManager.tmStrFormat(r,s.original);n.replace(s,o)}this.$inChange=!1},this.onAfterExec=function(e){e.command&&!e.command.readOnly&&this.updateLinkedFields()},this.onChangeSelection=function(){if(!this.editor)return;var e=this.editor.selection.lead,t=this.editor.selection.anchor,n=this.editor.selection.isEmpty();for(var r=this.ranges.length;r--;){if(this.ranges[r].linked)continue;var i=this.ranges[r].contains(e.row,e.column),s=n||this.ranges[r].contains(t.row,t.column);if(i&&s)return}this.detach()},this.onChangeSession=function(){this.detach()},this.tabNext=function(e){var t=this.tabstops.length,n=this.index+(e||1);n=Math.min(Math.max(n,1),t),n==t&&(n=0),this.selectTabstop(n),n===0&&this.detach()},this.selectTabstop=function(e){this.$openTabstops=null;var t=this.tabstops[this.index];t&&this.addTabstopMarkers(t),this.index=e,t=this.tabstops[this.index];if(!t||!t.length)return;this.selectedTabstop=t;if(!this.editor.inVirtualSelectionMode){var n=this.editor.multiSelect;n.toSingleRange(t.firstNonLinked.clone());for(var r=t.length;r--;){if(t.hasLinkedRanges&&t[r].linked)continue;n.addRange(t[r].clone(),!0)}n.ranges[0]&&n.addRange(n.ranges[0].clone())}else this.editor.selection.setRange(t.firstNonLinked);this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.addTabstops=function(e,t,n){this.$openTabstops||(this.$openTabstops=[]);if(!e[0]){var r=o.fromPoints(n,n);v(r.start,t),v(r.end,t),e[0]=[r],e[0].index=0}var i=this.index,s=[i+1,0],u=this.ranges;e.forEach(function(e,n){var r=this.$openTabstops[n]||e;for(var i=e.length;i--;){var a=e[i],f=o.fromPoints(a.start,a.end||a.start);d(f.start,t),d(f.end,t),f.original=a,f.tabstop=r,u.push(f),r!=e?r.unshift(f):r[i]=f,a.fmtString?(f.linked=!0,r.hasLinkedRanges=!0):r.firstNonLinked||(r.firstNonLinked=f)}r.firstNonLinked||(r.hasLinkedRanges=!1),r===e&&(s.push(r),this.$openTabstops[n]=r),this.addTabstopMarkers(r)},this),s.length>2&&(this.tabstops.length&&s.push(s.splice(2,1)[0]),this.tabstops.splice.apply(this.tabstops,s))},this.addTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){e.markerId||(e.markerId=t.addMarker(e,"ace_snippet-marker","text"))})},this.removeTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){t.removeMarker(e.markerId),e.markerId=null})},this.removeRange=function(e){var t=e.tabstop.indexOf(e);e.tabstop.splice(t,1),t=this.ranges.indexOf(e),this.ranges.splice(t,1),this.editor.session.removeMarker(e.markerId),e.tabstop.length||(t=this.tabstops.indexOf(e.tabstop),t!=-1&&this.tabstops.splice(t,1),this.tabstops.length||this.detach())},this.keyboardHandler=new a,this.keyboardHandler.bindKeys({Tab:function(e){if(t.snippetManager&&t.snippetManager.expandWithTab(e))return;e.tabstopManager.tabNext(1)},"Shift-Tab":function(e){e.tabstopManager.tabNext(-1)},Esc:function(e){e.tabstopManager.detach()},Return:function(e){return!1}})}).call(h.prototype);var p={};p.onChange=u.prototype.onChange,p.setPosition=function(e,t){this.pos.row=e,this.pos.column=t},p.update=function(e,t,n){this.$insertRight=n,this.pos=e,this.onChange(t)};var d=function(e,t){e.row==0&&(e.column+=t.column),e.row+=t.row},v=function(e,t){e.row==t.row&&(e.column-=t.column),e.row-=t.row};e("./lib/dom").importCssString(".ace_snippet-marker { -moz-box-sizing: border-box; box-sizing: border-box; background: rgba(194, 193, 208, 0.09); border: 1px dotted rgba(211, 208, 235, 0.62); position: absolute;}"),t.snippetManager=new c;var m=e("./editor").Editor;(function(){this.insertSnippet=function(e,n){return t.snippetManager.insertSnippet(this,e,n)},this.expandSnippet=function(e){return t.snippetManager.expandWithTab(this,e)}}).call(m.prototype)}),ace.define("ace/autocomplete/popup",["require","exports","module","ace/virtual_renderer","ace/editor","ace/range","ace/lib/event","ace/lib/lang","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../virtual_renderer").VirtualRenderer,i=e("../editor").Editor,s=e("../range").Range,o=e("../lib/event"),u=e("../lib/lang"),a=e("../lib/dom"),f=function(e){var t=new r(e);t.$maxLines=4;var n=new i(t);return n.setHighlightActiveLine(!1),n.setShowPrintMargin(!1),n.renderer.setShowGutter(!1),n.renderer.setHighlightGutterLine(!1),n.$mouseHandler.$focusWaitTimout=0,n.$highlightTagPending=!0,n},l=function(e){var t=a.createElement("div"),n=new f(t);e&&e.appendChild(t),t.style.display="none",n.renderer.content.style.cursor="default",n.renderer.setStyle("ace_autocomplete"),n.setOption("displayIndentGuides",!1),n.setOption("dragDelay",150);var r=function(){};n.focus=r,n.$isFocused=!0,n.renderer.$cursorLayer.restartTimer=r,n.renderer.$cursorLayer.element.style.opacity=0,n.renderer.$maxLines=8,n.renderer.$keepTextAreaAtCursor=!1,n.setHighlightActiveLine(!1),n.session.highlight(""),n.session.$searchHighlight.clazz="ace_highlight-marker",n.on("mousedown",function(e){var t=e.getDocumentPosition();n.selection.moveToPosition(t),c.start.row=c.end.row=t.row,e.stop()});var i,l=new s(-1,0,-1,Infinity),c=new s(-1,0,-1,Infinity);c.id=n.session.addMarker(c,"ace_active-line","fullLine"),n.setSelectOnHover=function(e){e?l.id&&(n.session.removeMarker(l.id),l.id=null):l.id=n.session.addMarker(l,"ace_line-hover","fullLine")},n.setSelectOnHover(!1),n.on("mousemove",function(e){if(!i){i=e;return}if(i.x==e.x&&i.y==e.y)return;i=e,i.scrollTop=n.renderer.scrollTop;var t=i.getDocumentPosition().row;l.start.row!=t&&(l.id||n.setRow(t),p(t))}),n.renderer.on("beforeRender",function(){if(i&&l.start.row!=-1){i.$pos=null;var e=i.getDocumentPosition().row;l.id||n.setRow(e),p(e,!0)}}),n.renderer.on("afterRender",function(){var e=n.getRow(),t=n.renderer.$textLayer,r=t.element.childNodes[e-t.config.firstRow];if(r==t.selectedNode)return;t.selectedNode&&a.removeCssClass(t.selectedNode,"ace_selected"),t.selectedNode=r,r&&a.addCssClass(r,"ace_selected")});var h=function(){p(-1)},p=function(e,t){e!==l.start.row&&(l.start.row=l.end.row=e,t||n.session._emit("changeBackMarker"),n._emit("changeHoverMarker"))};n.getHoveredRow=function(){return l.start.row},o.addListener(n.container,"mouseout",h),n.on("hide",h),n.on("changeSelection",h),n.session.doc.getLength=function(){return n.data.length},n.session.doc.getLine=function(e){var t=n.data[e];return typeof t=="string"?t:t&&t.value||""};var d=n.session.bgTokenizer;return d.$tokenizeRow=function(e){var t=n.data[e],r=[];if(!t)return r;typeof t=="string"&&(t={value:t}),t.caption||(t.caption=t.value||t.name);var i=-1,s,o;for(var u=0;ua-2&&(f=f.substr(0,a-t.caption.length-3)+"\u2026"),r.push({type:"rightAlignedText",value:f})}return r},d.$updateOnChange=r,d.start=r,n.session.$computeWidth=function(){return this.screenWidth=0},n.$blockScrolling=Infinity,n.isOpen=!1,n.isTopdown=!1,n.data=[],n.setData=function(e){n.setValue(u.stringRepeat("\n",e.length),-1),n.data=e||[],n.setRow(0)},n.getData=function(e){return n.data[e]},n.getRow=function(){return c.start.row},n.setRow=function(e){e=Math.max(0,Math.min(this.data.length,e)),c.start.row!=e&&(n.selection.clearSelection(),c.start.row=c.end.row=e||0,n.session._emit("changeBackMarker"),n.moveCursorTo(e||0,0),n.isOpen&&n._signal("select"))},n.on("changeSelection",function(){n.isOpen&&n.setRow(n.selection.lead.row),n.renderer.scrollCursorIntoView()}),n.hide=function(){this.container.style.display="none",this._signal("hide"),n.isOpen=!1},n.show=function(e,t,r){var s=this.container,o=window.innerHeight,u=window.innerWidth,a=this.renderer,f=a.$maxLines*t*1.4,l=e.top+this.$borderSize,c=l>o/2&&!r;c&&l+t+f>o?(a.$maxPixelHeight=l-2*this.$borderSize,s.style.top="",s.style.bottom=o-l+"px",n.isTopdown=!1):(l+=t,a.$maxPixelHeight=o-l-.2*t,s.style.top=l+"px",s.style.bottom="",n.isTopdown=!0),s.style.display="",this.renderer.$textLayer.checkForSizeChanges();var h=e.left;h+s.offsetWidth>u&&(h=u-s.offsetWidth),s.style.left=h+"px",this._signal("show"),i=null,n.isOpen=!0},n.getTextLeftOffset=function(){return this.$borderSize+this.renderer.$padding+this.$imageSize},n.$imageSize=0,n.$borderSize=1,n};a.importCssString(".ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line { background-color: #CAD6FA; z-index: 1;}.ace_editor.ace_autocomplete .ace_line-hover { border: 1px solid #abbffe; margin-top: -1px; background: rgba(233,233,253,0.4);}.ace_editor.ace_autocomplete .ace_line-hover { position: absolute; z-index: 2;}.ace_editor.ace_autocomplete .ace_scroller { background: none; border: none; box-shadow: none;}.ace_rightAlignedText { color: gray; display: inline-block; position: absolute; right: 4px; text-align: right; z-index: -1;}.ace_editor.ace_autocomplete .ace_completion-highlight{ color: #000; text-shadow: 0 0 0.01em;}.ace_editor.ace_autocomplete { width: 280px; z-index: 200000; background: #fbfbfb; color: #444; border: 1px lightgray solid; position: fixed; box-shadow: 2px 3px 5px rgba(0,0,0,.2); line-height: 1.4;}"),t.AcePopup=l}),ace.define("ace/autocomplete/util",["require","exports","module"],function(e,t,n){"use strict";t.parForEach=function(e,t,n){var r=0,i=e.length;i===0&&n();for(var s=0;s=0;s--){if(!n.test(e[s]))break;i.push(e[s])}return i.reverse().join("")},t.retrieveFollowingIdentifier=function(e,t,n){n=n||r;var i=[];for(var s=t;s=n?-1:t+1;break;case"start":t=0;break;case"end":t=n}this.popup.setRow(t)},this.insertMatch=function(e,t){e||(e=this.popup.getData(this.popup.getRow()));if(!e)return!1;if(e.completer&&e.completer.insertMatch)e.completer.insertMatch(this.editor,e);else{if(this.completions.filterText){var n=this.editor.selection.getAllRanges();for(var r=0,i;i=n[r];r++)i.start.column-=this.completions.filterText.length,this.editor.session.remove(i)}e.snippet?f.insertSnippet(this.editor,e.snippet):this.editor.execCommand("insertstring",e.value||e)}this.detach()},this.commands={Up:function(e){e.completer.goTo("up")},Down:function(e){e.completer.goTo("down")},"Ctrl-Up|Ctrl-Home":function(e){e.completer.goTo("start")},"Ctrl-Down|Ctrl-End":function(e){e.completer.goTo("end")},Esc:function(e){e.completer.detach()},Return:function(e){return e.completer.insertMatch()},"Shift-Return":function(e){e.completer.insertMatch(null,{deleteSuffix:!0})},Tab:function(e){var t=e.completer.insertMatch();if(!!t||!!e.tabstopManager)return t;e.completer.goTo("down")},PageUp:function(e){e.completer.popup.gotoPageUp()},PageDown:function(e){e.completer.popup.gotoPageDown()}},this.gatherCompletions=function(e,t){var n=e.getSession(),r=e.getCursorPosition(),i=n.getLine(r.row),o=s.getCompletionPrefix(e);this.base=n.doc.createAnchor(r.row,r.column-o.length),this.base.$insertRight=!0;var u=[],a=e.completers.length;return e.completers.forEach(function(i,s){i.getCompletions(e,n,r,o,function(r,i){!r&&i&&(u=u.concat(i));var s=e.getCursorPosition(),f=n.getLine(s.row);t(null,{prefix:o,matches:u,finished:--a===0})})}),!0},this.showPopup=function(e){this.editor&&this.detach(),this.activated=!0,this.editor=e,e.completer!=this&&(e.completer&&e.completer.detach(),e.completer=this),e.on("changeSelection",this.changeListener),e.on("blur",this.blurListener),e.on("mousedown",this.mousedownListener),e.on("mousewheel",this.mousewheelListener),this.updateCompletions()},this.updateCompletions=function(e){if(e&&this.base&&this.completions){var t=this.editor.getCursorPosition(),n=this.editor.session.getTextRange({start:this.base,end:t});if(n==this.completions.filterText)return;this.completions.setFilter(n);if(!this.completions.filtered.length)return this.detach();if(this.completions.filtered.length==1&&this.completions.filtered[0].value==n&&!this.completions.filtered[0].snippet)return this.detach();this.openPopup(this.editor,n,e);return}var r=this.gatherCompletionsId;this.gatherCompletions(this.editor,function(t,n){var i=function(){if(!n.finished)return;return this.detach()}.bind(this),s=n.prefix,o=n&&n.matches;if(!o||!o.length)return i();if(s.indexOf(n.prefix)!==0||r!=this.gatherCompletionsId)return;this.completions=new c(o),this.exactMatch&&(this.completions.exactMatch=!0),this.completions.setFilter(s);var u=this.completions.filtered;if(!u.length)return i();if(u.length==1&&u[0].value==s&&!u[0].snippet)return i();if(this.autoInsert&&u.length==1&&n.finished)return this.insertMatch(u[0]);this.openPopup(this.editor,s,e)}.bind(this))},this.cancelContextMenu=function(){this.editor.$mouseHandler.cancelContextMenu()},this.updateDocTooltip=function(){var e=this.popup,t=e.data,n=t&&(t[e.getHoveredRow()]||t[e.getRow()]),r=null;if(!n||!this.editor||!this.popup.isOpen)return this.hideDocTooltip();this.editor.completers.some(function(e){return e.getDocTooltip&&(r=e.getDocTooltip(n)),r}),r||(r=n),typeof r=="string"&&(r={docText:r});if(!r||!r.docHTML&&!r.docText)return this.hideDocTooltip();this.showDocTooltip(r)},this.showDocTooltip=function(e){this.tooltipNode||(this.tooltipNode=a.createElement("div"),this.tooltipNode.className="ace_tooltip ace_doc-tooltip",this.tooltipNode.style.margin=0,this.tooltipNode.style.pointerEvents="auto",this.tooltipNode.tabIndex=-1,this.tooltipNode.onblur=this.blurListener.bind(this));var t=this.tooltipNode;e.docHTML?t.innerHTML=e.docHTML:e.docText&&(t.textContent=e.docText),t.parentNode||document.body.appendChild(t);var n=this.popup,r=n.container.getBoundingClientRect();t.style.top=n.container.style.top,t.style.bottom=n.container.style.bottom,window.innerWidth-r.right<320?(t.style.right=window.innerWidth-r.left+"px",t.style.left=""):(t.style.left=r.right+1+"px",t.style.right=""),t.style.display="block"},this.hideDocTooltip=function(){this.tooltipTimer.cancel();if(!this.tooltipNode)return;var e=this.tooltipNode;!this.editor.isFocused()&&document.activeElement==e&&this.editor.focus(),this.tooltipNode=null,e.parentNode&&e.parentNode.removeChild(e)}}).call(l.prototype),l.startCommand={name:"startAutocomplete",exec:function(e){e.completer||(e.completer=new l),e.completer.autoInsert=!1,e.completer.autoSelect=!0,e.completer.showPopup(e),e.completer.cancelContextMenu()},bindKey:"Ctrl-Space|Ctrl-Shift-Space|Alt-Space"};var c=function(e,t){this.all=e,this.filtered=e,this.filterText=t||"",this.exactMatch=!1};(function(){this.setFilter=function(e){if(e.length>this.filterText&&e.lastIndexOf(this.filterText,0)===0)var t=this.filtered;else var t=this.all;this.filterText=e,t=this.filterCompletions(t,this.filterText),t=t.sort(function(e,t){return t.exactMatch-e.exactMatch||t.score-e.score});var n=null;t=t.filter(function(e){var t=e.snippet||e.caption||e.value;return t===n?!1:(n=t,!0)}),this.filtered=t},this.filterCompletions=function(e,t){var n=[],r=t.toUpperCase(),i=t.toLowerCase();e:for(var s=0,o;o=e[s];s++){var u=o.value||o.caption||o.snippet;if(!u)continue;var a=-1,f=0,l=0,c,h;if(this.exactMatch){if(t!==u.substr(0,t.length))continue e}else for(var p=0;p=0?v<0||d0&&(a===-1&&(l+=10),l+=h),f|=1<",o.escapeHTML(e.caption),""," ",o.escapeHTML(e.snippet)].join(""))}},c=[l,a,f];t.setCompleters=function(e){c.length=0,e&&c.push.apply(c,e)},t.addCompleter=function(e){c.push(e)},t.textCompleter=a,t.keyWordCompleter=f,t.snippetCompleter=l;var h={name:"expandSnippet",exec:function(e){return r.expandWithTab(e)},bindKey:"Tab"},p=function(e,t){d(t.session.$mode)},d=function(e){var t=e.$id;r.files||(r.files={}),v(t),e.modes&&e.modes.forEach(d)},v=function(e){if(!e||r.files[e])return;var t=e.replace("mode","snippets");r.files[e]={},s.loadModule(t,function(t){t&&(r.files[e]=t,!t.snippets&&t.snippetText&&(t.snippets=r.parseSnippetFile(t.snippetText)),r.register(t.snippets||[],t.scope),t.includeScopes&&(r.snippetMap[t.scope].includeScopes=t.includeScopes,t.includeScopes.forEach(function(e){v("ace/mode/"+e)})))})},m=function(e){var t=e.editor,n=t.completer&&t.completer.activated;if(e.command.name==="backspace")n&&!u.getCompletionPrefix(t)&&t.completer.detach();else if(e.command.name==="insertstring"){var r=u.getCompletionPrefix(t);r&&!n&&(t.completer||(t.completer=new i),t.completer.autoInsert=!1,t.completer.showPopup(t))}},g=e("../editor").Editor;e("../config").defineOptions(g.prototype,"editor",{enableBasicAutocompletion:{set:function(e){e?(this.completers||(this.completers=Array.isArray(e)?e:c),this.commands.addCommand(i.startCommand)):this.commands.removeCommand(i.startCommand)},value:!1},enableLiveAutocompletion:{set:function(e){e?(this.completers||(this.completers=Array.isArray(e)?e:c),this.commands.on("afterExec",m)):this.commands.removeListener("afterExec",m)},value:!1},enableSnippets:{set:function(e){e?(this.commands.addCommand(h),this.on("changeMode",p),p(null,this)):(this.commands.removeCommand(h),this.off("changeMode",p))},value:!1}})});
+ (function() {
+ ace.require(["ace/ext/language_tools"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-linking.js b/library/ace/ext-linking.js
new file mode 100644
index 000000000..69f87918f
--- /dev/null
+++ b/library/ace/ext-linking.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function i(e){var t=e.editor,n=e.getAccelKey();if(n){var t=e.editor,r=e.getDocumentPosition(),i=t.session,s=i.getTokenAt(r.row,r.column);t._emit("linkHover",{position:r,token:s})}}function s(e){var t=e.getAccelKey(),n=e.getButton();if(n==0&&t){var r=e.editor,i=e.getDocumentPosition(),s=r.session,o=s.getTokenAt(i.row,i.column);r._emit("linkClick",{position:i,token:o})}}var r=e("ace/editor").Editor;e("../config").defineOptions(r.prototype,"editor",{enableLinking:{set:function(e){e?(this.on("click",s),this.on("mousemove",i)):(this.off("click",s),this.off("mousemove",i))},value:!1}})});
+ (function() {
+ ace.require(["ace/ext/linking"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-modelist.js b/library/ace/ext-modelist.js
new file mode 100644
index 000000000..84164bdfd
--- /dev/null
+++ b/library/ace/ext-modelist.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i \s+/g,">"),l=function(e,t,n){var i=r.createElement("div");i.innerHTML=f,this.element=i.firstChild,this.$init(),this.setEditor(e)};(function(){this.setEditor=function(e){e.searchBox=this,e.container.appendChild(this.element),this.editor=e},this.$initElements=function(e){this.searchBox=e.querySelector(".ace_search_form"),this.replaceBox=e.querySelector(".ace_replace_form"),this.searchOptions=e.querySelector(".ace_search_options"),this.regExpOption=e.querySelector("[action=toggleRegexpMode]"),this.caseSensitiveOption=e.querySelector("[action=toggleCaseSensitive]"),this.wholeWordOption=e.querySelector("[action=toggleWholeWords]"),this.searchInput=this.searchBox.querySelector(".ace_search_field"),this.replaceInput=this.replaceBox.querySelector(".ace_search_field")},this.$init=function(){var e=this.element;this.$initElements(e);var t=this;s.addListener(e,"mousedown",function(e){setTimeout(function(){t.activeInput.focus()},0),s.stopPropagation(e)}),s.addListener(e,"click",function(e){var n=e.target||e.srcElement,r=n.getAttribute("action");r&&t[r]?t[r]():t.$searchBarKb.commands[r]&&t.$searchBarKb.commands[r].exec(t),s.stopPropagation(e)}),s.addCommandKeyListener(e,function(e,n,r){var i=a.keyCodeToString(r),o=t.$searchBarKb.findKeyCommand(n,i);o&&o.exec&&(o.exec(t),s.stopEvent(e))}),this.$onChange=i.delayedCall(function(){t.find(!1,!1)}),s.addListener(this.searchInput,"input",function(){t.$onChange.schedule(20)}),s.addListener(this.searchInput,"focus",function(){t.activeInput=t.searchInput,t.searchInput.value&&t.highlight()}),s.addListener(this.replaceInput,"focus",function(){t.activeInput=t.replaceInput,t.searchInput.value&&t.highlight()})},this.$closeSearchBarKb=new u([{bindKey:"Esc",name:"closeSearchBar",exec:function(e){e.searchBox.hide()}}]),this.$searchBarKb=new u,this.$searchBarKb.bindKeys({"Ctrl-f|Command-f":function(e){var t=e.isReplace=!e.isReplace;e.replaceBox.style.display=t?"":"none",e.searchInput.focus()},"Ctrl-H|Command-Option-F":function(e){e.replaceBox.style.display="",e.replaceInput.focus()},"Ctrl-G|Command-G":function(e){e.findNext()},"Ctrl-Shift-G|Command-Shift-G":function(e){e.findPrev()},esc:function(e){setTimeout(function(){e.hide()})},Return:function(e){e.activeInput==e.replaceInput&&e.replace(),e.findNext()},"Shift-Return":function(e){e.activeInput==e.replaceInput&&e.replace(),e.findPrev()},"Alt-Return":function(e){e.activeInput==e.replaceInput&&e.replaceAll(),e.findAll()},Tab:function(e){(e.activeInput==e.replaceInput?e.searchInput:e.replaceInput).focus()}}),this.$searchBarKb.addCommands([{name:"toggleRegexpMode",bindKey:{win:"Alt-R|Alt-/",mac:"Ctrl-Alt-R|Ctrl-Alt-/"},exec:function(e){e.regExpOption.checked=!e.regExpOption.checked,e.$syncOptions()}},{name:"toggleCaseSensitive",bindKey:{win:"Alt-C|Alt-I",mac:"Ctrl-Alt-R|Ctrl-Alt-I"},exec:function(e){e.caseSensitiveOption.checked=!e.caseSensitiveOption.checked,e.$syncOptions()}},{name:"toggleWholeWords",bindKey:{win:"Alt-B|Alt-W",mac:"Ctrl-Alt-B|Ctrl-Alt-W"},exec:function(e){e.wholeWordOption.checked=!e.wholeWordOption.checked,e.$syncOptions()}}]),this.$syncOptions=function(){r.setCssClass(this.regExpOption,"checked",this.regExpOption.checked),r.setCssClass(this.wholeWordOption,"checked",this.wholeWordOption.checked),r.setCssClass(this.caseSensitiveOption,"checked",this.caseSensitiveOption.checked),this.find(!1,!1)},this.highlight=function(e){this.editor.session.highlight(e||this.editor.$search.$options.re),this.editor.renderer.updateBackMarkers()},this.find=function(e,t,n){var i=this.editor.find(this.searchInput.value,{skipCurrent:e,backwards:t,wrap:!0,regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked,preventScroll:n}),s=!i&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",s),this.editor._emit("findSearchBox",{match:!s}),this.highlight()},this.findNext=function(){this.find(!0,!1)},this.findPrev=function(){this.find(!0,!0)},this.findAll=function(){var e=this.editor.findAll(this.searchInput.value,{regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked}),t=!e&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",t),this.editor._emit("findSearchBox",{match:!t}),this.highlight(),this.hide()},this.replace=function(){this.editor.getReadOnly()||this.editor.replace(this.replaceInput.value)},this.replaceAndFindNext=function(){this.editor.getReadOnly()||(this.editor.replace(this.replaceInput.value),this.findNext())},this.replaceAll=function(){this.editor.getReadOnly()||this.editor.replaceAll(this.replaceInput.value)},this.hide=function(){this.element.style.display="none",this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb),this.editor.focus()},this.show=function(e,t){this.element.style.display="",this.replaceBox.style.display=t?"":"none",this.isReplace=t,e&&(this.searchInput.value=e),this.find(!1,!1,!0),this.searchInput.focus(),this.searchInput.select(),this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb)},this.isFocused=function(){var e=document.activeElement;return e==this.searchInput||e==this.replaceInput}}).call(l.prototype),t.SearchBox=l,t.Search=function(e,t){var n=e.searchBox||new l(e);n.show(e.session.getTextRange(),t)}}),ace.define("ace/ext/old_ie",["require","exports","module","ace/lib/useragent","ace/tokenizer","ace/ext/searchbox","ace/mode/text"],function(require,exports,module){"use strict";function patch(obj,name,regexp,replacement){eval("obj['"+name+"']="+obj[name].toString().replace(regexp,replacement))}var MAX_TOKEN_COUNT=1e3,useragent=require("../lib/useragent"),TokenizerModule=require("../tokenizer");useragent.isIE&&useragent.isIE<10&&window.top.document.compatMode==="BackCompat"&&(useragent.isOldIE=!0);if(typeof document!="undefined"&&!document.documentElement.querySelector){useragent.isOldIE=!0;var qs=function(e,t){if(t.charAt(0)==".")var n=t.slice(1);else var r=t.match(/(\w+)=(\w+)/),i=r&&r[1],s=r&&r[2];for(var o=0;o \s+/g,">"),l=function(e,t,n){var i=r.createElement("div");i.innerHTML=f,this.element=i.firstChild,this.$init(),this.setEditor(e)};(function(){this.setEditor=function(e){e.searchBox=this,e.container.appendChild(this.element),this.editor=e},this.$initElements=function(e){this.searchBox=e.querySelector(".ace_search_form"),this.replaceBox=e.querySelector(".ace_replace_form"),this.searchOptions=e.querySelector(".ace_search_options"),this.regExpOption=e.querySelector("[action=toggleRegexpMode]"),this.caseSensitiveOption=e.querySelector("[action=toggleCaseSensitive]"),this.wholeWordOption=e.querySelector("[action=toggleWholeWords]"),this.searchInput=this.searchBox.querySelector(".ace_search_field"),this.replaceInput=this.replaceBox.querySelector(".ace_search_field")},this.$init=function(){var e=this.element;this.$initElements(e);var t=this;s.addListener(e,"mousedown",function(e){setTimeout(function(){t.activeInput.focus()},0),s.stopPropagation(e)}),s.addListener(e,"click",function(e){var n=e.target||e.srcElement,r=n.getAttribute("action");r&&t[r]?t[r]():t.$searchBarKb.commands[r]&&t.$searchBarKb.commands[r].exec(t),s.stopPropagation(e)}),s.addCommandKeyListener(e,function(e,n,r){var i=a.keyCodeToString(r),o=t.$searchBarKb.findKeyCommand(n,i);o&&o.exec&&(o.exec(t),s.stopEvent(e))}),this.$onChange=i.delayedCall(function(){t.find(!1,!1)}),s.addListener(this.searchInput,"input",function(){t.$onChange.schedule(20)}),s.addListener(this.searchInput,"focus",function(){t.activeInput=t.searchInput,t.searchInput.value&&t.highlight()}),s.addListener(this.replaceInput,"focus",function(){t.activeInput=t.replaceInput,t.searchInput.value&&t.highlight()})},this.$closeSearchBarKb=new u([{bindKey:"Esc",name:"closeSearchBar",exec:function(e){e.searchBox.hide()}}]),this.$searchBarKb=new u,this.$searchBarKb.bindKeys({"Ctrl-f|Command-f":function(e){var t=e.isReplace=!e.isReplace;e.replaceBox.style.display=t?"":"none",e.searchInput.focus()},"Ctrl-H|Command-Option-F":function(e){e.replaceBox.style.display="",e.replaceInput.focus()},"Ctrl-G|Command-G":function(e){e.findNext()},"Ctrl-Shift-G|Command-Shift-G":function(e){e.findPrev()},esc:function(e){setTimeout(function(){e.hide()})},Return:function(e){e.activeInput==e.replaceInput&&e.replace(),e.findNext()},"Shift-Return":function(e){e.activeInput==e.replaceInput&&e.replace(),e.findPrev()},"Alt-Return":function(e){e.activeInput==e.replaceInput&&e.replaceAll(),e.findAll()},Tab:function(e){(e.activeInput==e.replaceInput?e.searchInput:e.replaceInput).focus()}}),this.$searchBarKb.addCommands([{name:"toggleRegexpMode",bindKey:{win:"Alt-R|Alt-/",mac:"Ctrl-Alt-R|Ctrl-Alt-/"},exec:function(e){e.regExpOption.checked=!e.regExpOption.checked,e.$syncOptions()}},{name:"toggleCaseSensitive",bindKey:{win:"Alt-C|Alt-I",mac:"Ctrl-Alt-R|Ctrl-Alt-I"},exec:function(e){e.caseSensitiveOption.checked=!e.caseSensitiveOption.checked,e.$syncOptions()}},{name:"toggleWholeWords",bindKey:{win:"Alt-B|Alt-W",mac:"Ctrl-Alt-B|Ctrl-Alt-W"},exec:function(e){e.wholeWordOption.checked=!e.wholeWordOption.checked,e.$syncOptions()}}]),this.$syncOptions=function(){r.setCssClass(this.regExpOption,"checked",this.regExpOption.checked),r.setCssClass(this.wholeWordOption,"checked",this.wholeWordOption.checked),r.setCssClass(this.caseSensitiveOption,"checked",this.caseSensitiveOption.checked),this.find(!1,!1)},this.highlight=function(e){this.editor.session.highlight(e||this.editor.$search.$options.re),this.editor.renderer.updateBackMarkers()},this.find=function(e,t,n){var i=this.editor.find(this.searchInput.value,{skipCurrent:e,backwards:t,wrap:!0,regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked,preventScroll:n}),s=!i&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",s),this.editor._emit("findSearchBox",{match:!s}),this.highlight()},this.findNext=function(){this.find(!0,!1)},this.findPrev=function(){this.find(!0,!0)},this.findAll=function(){var e=this.editor.findAll(this.searchInput.value,{regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked}),t=!e&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",t),this.editor._emit("findSearchBox",{match:!t}),this.highlight(),this.hide()},this.replace=function(){this.editor.getReadOnly()||this.editor.replace(this.replaceInput.value)},this.replaceAndFindNext=function(){this.editor.getReadOnly()||(this.editor.replace(this.replaceInput.value),this.findNext())},this.replaceAll=function(){this.editor.getReadOnly()||this.editor.replaceAll(this.replaceInput.value)},this.hide=function(){this.element.style.display="none",this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb),this.editor.focus()},this.show=function(e,t){this.element.style.display="",this.replaceBox.style.display=t?"":"none",this.isReplace=t,e&&(this.searchInput.value=e),this.find(!1,!1,!0),this.searchInput.focus(),this.searchInput.select(),this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb)},this.isFocused=function(){var e=document.activeElement;return e==this.searchInput||e==this.replaceInput}}).call(l.prototype),t.SearchBox=l,t.Search=function(e,t){var n=e.searchBox||new l(e);n.show(e.session.getTextRange(),t)}});
+ (function() {
+ ace.require(["ace/ext/searchbox"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-settings_menu.js b/library/ace/ext-settings_menu.js
new file mode 100644
index 000000000..a005f7617
--- /dev/null
+++ b/library/ace/ext-settings_menu.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/menu_tools/element_generator",["require","exports","module"],function(e,t,n){"use strict";n.exports.createOption=function(t){var n,r=document.createElement("option");for(n in t)t.hasOwnProperty(n)&&(n==="selected"?r.setAttribute(n,t[n]):r[n]=t[n]);return r},n.exports.createCheckbox=function(t,n,r){var i=document.createElement("input");return i.setAttribute("type","checkbox"),i.setAttribute("id",t),i.setAttribute("name",t),i.setAttribute("value",n),i.setAttribute("class",r),n&&i.setAttribute("checked","checked"),i},n.exports.createInput=function(t,n,r){var i=document.createElement("input");return i.setAttribute("type","text"),i.setAttribute("id",t),i.setAttribute("name",t),i.setAttribute("value",n),i.setAttribute("class",r),i},n.exports.createLabel=function(t,n){var r=document.createElement("label");return r.setAttribute("for",n),r.textContent=t,r},n.exports.createSelection=function(t,r,i){var s=document.createElement("select");return s.setAttribute("id",t),s.setAttribute("name",t),s.setAttribute("class",i),r.forEach(function(e){s.appendChild(n.exports.createOption(e))}),s}}),ace.define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i 0!";if(e==this.$splits)return;if(e>this.$splits){while(this.$splitse)t=this.$editors[this.$splits-1],this.$container.removeChild(t.container),this.$splits--;this.resize()},this.getSplits=function(){return this.$splits},this.getEditor=function(e){return this.$editors[e]},this.getCurrentEditor=function(){return this.$cEditor},this.focus=function(){this.$cEditor.focus()},this.blur=function(){this.$cEditor.blur()},this.setTheme=function(e){this.$editors.forEach(function(t){t.setTheme(e)})},this.setKeyboardHandler=function(e){this.$editors.forEach(function(t){t.setKeyboardHandler(e)})},this.forEach=function(e,t){this.$editors.forEach(e,t)},this.$fontSize="",this.setFontSize=function(e){this.$fontSize=e,this.forEach(function(t){t.setFontSize(e)})},this.$cloneSession=function(e){var t=new a(e.getDocument(),e.getMode()),n=e.getUndoManager();if(n){var r=new l(n,t);t.setUndoManager(r)}return t.$informUndoManager=i.delayedCall(function(){t.$deltas=[]}),t.setTabSize(e.getTabSize()),t.setUseSoftTabs(e.getUseSoftTabs()),t.setOverwrite(e.getOverwrite()),t.setBreakpoints(e.getBreakpoints()),t.setUseWrapMode(e.getUseWrapMode()),t.setUseWorker(e.getUseWorker()),t.setWrapLimitRange(e.$wrapLimitRange.min,e.$wrapLimitRange.max),t.$foldData=e.$cloneFoldData(),t},this.setSession=function(e,t){var n;t==null?n=this.$cEditor:n=this.$editors[t];var r=this.$editors.some(function(t){return t.session===e});return r&&(e=this.$cloneSession(e)),n.setSession(e),e},this.getOrientation=function(){return this.$orientation},this.setOrientation=function(e){if(this.$orientation==e)return;this.$orientation=e,this.resize()},this.resize=function(){var e=this.$container.clientWidth,t=this.$container.clientHeight,n;if(this.$orientation==this.BESIDE){var r=e/this.$splits;for(var i=0;i"),o||l.push(" "),f.$renderLine(l,h,!0,!1),l.push("\n");var p="";return f.destroy(),{css:s+n.cssText,html:p,session:u}},n.exports=f,n.exports.highlight=f});
+ (function() {
+ ace.require(["ace/ext/static_highlight"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-statusbar.js b/library/ace/ext-statusbar.js
new file mode 100644
index 000000000..a5ab7ed95
--- /dev/null
+++ b/library/ace/ext-statusbar.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/statusbar",["require","exports","module","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";var r=e("ace/lib/dom"),i=e("ace/lib/lang"),s=function(e,t){this.element=r.createElement("div"),this.element.className="ace_status-indicator",this.element.style.cssText="display: inline-block;",t.appendChild(this.element);var n=i.delayedCall(function(){this.updateStatus(e)}.bind(this)).schedule.bind(null,100);e.on("changeStatus",n),e.on("changeSelection",n),e.on("keyboardActivity",n)};(function(){this.updateStatus=function(e){function n(e,n){e&&t.push(e,n||"|")}var t=[];n(e.keyBinding.getStatusText(e)),e.commands.recording&&n("REC");var r=e.selection,i=r.lead;if(!r.isEmpty()){var s=e.getSelectionRange();n("("+(s.end.row-s.start.row)+":"+(s.end.column-s.start.column)+")"," ")}n(i.row+":"+i.column," "),r.rangeCount&&n("["+r.rangeCount+"]"," "),t.pop(),this.element.textContent=t.join("")}}).call(s.prototype),t.StatusBar=s});
+ (function() {
+ ace.require(["ace/ext/statusbar"], function() {});
+ })();
+
\ No newline at end of file
diff --git a/library/ace/ext-textarea.js b/library/ace/ext-textarea.js
new file mode 100644
index 000000000..a53935bad
--- /dev/null
+++ b/library/ace/ext-textarea.js
@@ -0,0 +1,5 @@
+ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}),ace.define("ace/ext/textarea",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/net","ace/ace","ace/theme/textmate"],function(e,t,n){"use strict";function a(e,t){for(var n in t)e.style[n]=t[n]}function f(e,t){if(e.type!="textarea")throw new Error("Textarea required!");var n=e.parentNode,i=document.createElement("div"),s=function(){var t="position:relative;";["margin-top","margin-left","margin-right","margin-bottom"].forEach(function(n){t+=n+":"+u(e,i,n)+";"});var n=u(e,i,"width")||e.clientWidth+"px",r=u(e,i,"height")||e.clientHeight+"px";t+="height:"+r+";width:"+n+";",t+="display:inline-block;",i.setAttribute("style",t)};r.addListener(window,"resize",s),s(),n.insertBefore(i,e.nextSibling);while(n!==document){if(n.tagName.toUpperCase()==="FORM"){var o=n.onsubmit;n.onsubmit=function(n){e.value=t(),o&&o.call(this,n)};break}n=n.parentNode}return i}function l(t,n,r){s.loadScript(t,function(){e([n],r)})}function c(e,t,n,r,i,s){function a(e){return e==="true"||e==1}var o=e.getSession(),u=e.renderer;return s=s||l,e.setDisplaySettings=function(t){t==null&&(t=n.style.display=="none"),t?(n.style.display="block",n.hideButton.focus(),e.on("focus",function r(){e.removeListener("focus",r),n.style.display="none"})):e.focus()},e.$setOption=e.setOption,e.$getOption=e.getOption,e.setOption=function(t,n){switch(t){case"mode":e.$setOption("mode","ace/mode/"+n);break;case"theme":e.$setOption("theme","ace/theme/"+n);break;case"keybindings":switch(n){case"vim":e.setKeyboardHandler("ace/keyboard/vim");break;case"emacs":e.setKeyboardHandler("ace/keyboard/emacs");break;default:e.setKeyboardHandler(null)}break;case"softWrap":case"fontSize":e.$setOption(t,n);break;default:e.$setOption(t,a(n))}},e.getOption=function(t){switch(t){case"mode":return e.$getOption("mode").substr("ace/mode/".length);case"theme":return e.$getOption("theme").substr("ace/theme/".length);case"keybindings":var n=e.getKeyboardHandler();switch(n&&n.$id){case"ace/keyboard/vim":return"vim";case"ace/keyboard/emacs":return"emacs";default:return"ace"}break;default:return e.$getOption(t)}},e.setOptions(i),e}function h(e,n,i){function f(e,t,n,r){if(!n){e.push(" ");return}e.push("");for(var i in n)e.push("",n[i]," ");e.push(" ")}var s=null,o={mode:"Mode:",wrap:"Soft Wrap:",theme:"Theme:",fontSize:"Font Size:",showGutter:"Display Gutter:",keybindings:"Keyboard",showPrintMargin:"Show Print Margin:",useSoftTabs:"Use Soft Tabs:",showInvisibles:"Show Invisibles"},u={mode:{text:"Plain",javascript:"JavaScript",xml:"XML",html:"HTML",css:"CSS",scss:"SCSS",python:"Python",php:"PHP",java:"Java",ruby:"Ruby",c_cpp:"C/C++",coffee:"CoffeeScript",json:"json",perl:"Perl",clojure:"Clojure",ocaml:"OCaml",csharp:"C#",haxe:"haXe",svg:"SVG",textile:"Textile",groovy:"Groovy",liquid:"Liquid",Scala:"Scala"},theme:{clouds:"Clouds",clouds_midnight:"Clouds Midnight",cobalt:"Cobalt",crimson_editor:"Crimson Editor",dawn:"Dawn",eclipse:"Eclipse",idle_fingers:"Idle Fingers",kr_theme:"Kr Theme",merbivore:"Merbivore",merbivore_soft:"Merbivore Soft",mono_industrial:"Mono Industrial",monokai:"Monokai",pastel_on_dark:"Pastel On Dark",solarized_dark:"Solarized Dark",solarized_light:"Solarized Light",textmate:"Textmate",twilight:"Twilight",vibrant_ink:"Vibrant Ink"},showGutter:s,fontSize:{"10px":"10px","11px":"11px","12px":"12px","14px":"14px","16px":"16px"},wrap:{off:"Off",40:"40",80:"80",free:"Free"},keybindings:{ace:"ace",vim:"vim",emacs:"emacs"},showPrintMargin:s,useSoftTabs:s,showInvisibles:s},a=[];a.push("Setting Value ");for(var l in t.defaultOptions)a.push("",o[l]," "),a.push(""),f(a,l,u[l],i.getOption(l)),a.push(" ");a.push("
"),e.innerHTML=a.join("");var c=function(e){var t=e.currentTarget;i.setOption(t.title,t.value)},h=function(e){var t=e.currentTarget;i.setOption(t.title,t.checked)},p=e.getElementsByTagName("select");for(var d=0;d0&&!(s%l)&&!(f%l)&&(r[l]=(r[l]||0)+1),n[f]=(n[f]||0)+1}s=f}while(up.score&&(p={score:v,length:u})}if(p.score&&p.score>1.4)var m=p.length;if(i>d+1){if(m==1||di+1)return{ch:" ",length:m}},t.detectIndentation=function(e){var n=e.getLines(0,1e3),r=t.$detectIndentation(n)||{};return r.ch&&e.setUseSoftTabs(r.ch==" "),r.length&&e.setTabSize(r.length),r},t.trimTrailingSpace=function(e,t){var n=e.getDocument(),r=n.getAllLines(),i=t?-1:0;for(var s=0,o=r.length;si&&n.removeInLine(s,a,u.length)}},t.convertIndentation=function(e,t,n){var i=e.getTabString()[0],s=e.getTabSize();n||(n=s),t||(t=i);var o=t==" "?t:r.stringRepeat(t,n),u=e.doc,a=u.getAllLines(),f={},l={};for(var c=0,h=a.length;c30&&this.$data.shift()},append:function(e){var t=this.$data.length-1,n=this.$data[t]||"";e&&(n+=e),n&&(this.$data[t]=n)},get:function(e){return e=e||1,this.$data.slice(this.$data.length-e,this.$data.length).reverse().join("\n")},pop:function(){return this.$data.length>1&&this.$data.pop(),this.get()},rotate:function(){return this.$data.unshift(this.$data.pop()),this.get()}}})
\ No newline at end of file
diff --git a/library/ace/keybinding-vim.js b/library/ace/keybinding-vim.js
new file mode 100644
index 000000000..53c9301d5
--- /dev/null
+++ b/library/ace/keybinding-vim.js
@@ -0,0 +1 @@
+ace.define("ace/keyboard/vim",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/dom","ace/lib/oop","ace/lib/keys","ace/lib/event","ace/search","ace/lib/useragent","ace/search_highlight","ace/commands/multi_select_commands","ace/mode/text","ace/multi_select"],function(e,t,n){"use strict";function r(){function t(e){return typeof e!="object"?e+"":"line"in e?e.line+":"+e.ch:"anchor"in e?t(e.anchor)+"->"+t(e.head):Array.isArray(e)?"["+e.map(function(e){return t(e)})+"]":JSON.stringify(e)}var e="";for(var n=0;n"):!1}function M(e){var t=e.state.vim;return t.onPasteFn||(t.onPasteFn=function(){t.insertMode||(e.setCursor(St(e.getCursor(),0,1)),yt.enterInsertMode(e,{},t))}),t.onPasteFn}function H(e,t){var n=[];for(var r=e;r=e.firstLine()&&t<=e.lastLine()}function U(e){return/^[a-z]$/.test(e)}function z(e){return"()[]{}".indexOf(e)!=-1}function W(e){return _.test(e)}function X(e){return/^[A-Z]$/.test(e)}function V(e){return/^\s*$/.test(e)}function $(e,t){for(var n=0;n"){var n=t.length-11,r=e.slice(0,n),i=t.slice(0,n);return r==i&&e.length>n?"full":i.indexOf(r)==0?"partial":!1}return e==t?"full":t.indexOf(e)==0?"partial":!1}function Ct(e){var t=/^.*(<[\w\-]+>)$/.exec(e),n=t?t[1]:e.slice(-1);if(n.length>1)switch(n){case"":n="\n";break;case"":n=" ";break;default:}return n}function kt(e,t,n){return function(){for(var r=0;r2&&(t=Mt.apply(undefined,Array.prototype.slice.call(arguments,1))),Ot(e,t)?e:t}function _t(e,t){return arguments.length>2&&(t=_t.apply(undefined,Array.prototype.slice.call(arguments,1))),Ot(e,t)?t:e}function Dt(e,t,n){var r=Ot(e,t),i=Ot(t,n);return r&&i}function Pt(e,t){return e.getLine(t).length}function Ht(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function Bt(e){return e.replace(/([.?*+$\[\]\/\\(){}|\-])/g,"\\$1")}function jt(e,t,n){var r=Pt(e,t),i=(new Array(n-r+1)).join(" ");e.setCursor(E(t,r)),e.replaceRange(i,e.getCursor())}function Ft(e,t){var n=[],r=e.listSelections(),i=Lt(e.clipPos(t)),s=!At(t,i),o=e.getCursor("head"),u=qt(r,o),a=At(r[u].head,r[u].anchor),f=r.length-1,l=f-u>u?f:0,c=r[l].anchor,h=Math.min(c.line,i.line),p=Math.max(c.line,i.line),d=c.ch,v=i.ch,m=r[l].head.ch-d,g=v-d;m>0&&g<=0?(d++,s||v--):m<0&&g>=0?(d--,a||v++):m<0&&g==-1&&(d--,v++);for(var y=h;y<=p;y++){var b={anchor:new E(y,d),head:new E(y,v)};n.push(b)}return u=i.line==p?n.length-1:0,e.setSelections(n),t.ch=v,c.ch=d,c}function It(e,t,n){var r=[];for(var i=0;ia&&(i.line=a),i.ch=Pt(e,i.line)}else i.ch=0,s.ch=Pt(e,s.line);return{ranges:[{anchor:s,head:i}],primary:0}}if(n=="block"){var f=Math.min(s.line,i.line),l=Math.min(s.ch,i.ch),c=Math.max(s.line,i.line),h=Math.max(s.ch,i.ch)+1,p=c-f+1,d=i.line==f?0:p-1,v=[];for(var m=0;m0&&s&&V(s);s=i.pop())n.line--,n.ch=0;s?(n.line--,n.ch=Pt(e,n.line)):n.ch=0}}function Kt(e,t,n){t.ch=0,n.ch=0,n.line++}function Qt(e){if(!e)return 0;var t=e.search(/\S/);return t==-1?e.length:t}function Gt(e,t,n,r,i){var s=Vt(e),o=e.getLine(s.line),u=s.ch,a=i?D[0]:P[0];while(!a(o.charAt(u))){u++;if(u>=o.length)return null}r?a=P[0]:(a=D[0],a(o.charAt(u))||(a=D[1]));var f=u,l=u;while(a(o.charAt(f))&&f=0)l--;l++;if(t){var c=f;while(/\s/.test(o.charAt(f))&&f0)l--;l||(l=h)}}return{start:E(s.line,l),end:E(s.line,f)}}function Yt(e,t,n){At(t,n)||nt.jumpList.add(e,t,n)}function Zt(e,t){nt.lastChararacterSearch.increment=e,nt.lastChararacterSearch.forward=t.forward,nt.lastChararacterSearch.selectedCharacter=t.selectedCharacter}function nn(e,t,n,r){var i=Lt(e.getCursor()),s=n?1:-1,o=n?e.lineCount():-1,u=i.ch,a=i.line,f=e.getLine(a),l={lineText:f,nextCh:f.charAt(u),lastCh:null,index:u,symb:r,reverseSymb:(n?{")":"(","}":"{"}:{"(":")","{":"}"})[r],forward:n,depth:0,curMoveThrough:!1},c=en[r];if(!c)return i;var h=tn[c].init,p=tn[c].isComplete;h&&h(l);while(a!==o&&t){l.index+=s,l.nextCh=l.lineText.charAt(l.index);if(!l.nextCh){a+=s,l.lineText=e.getLine(a)||"";if(s>0)l.index=0;else{var d=l.lineText.length;l.index=d>0?d-1:0}l.nextCh=l.lineText.charAt(l.index)}p(l)&&(i.line=a,i.ch=l.index,t--)}return l.nextCh||l.curMoveThrough?E(a,l.index):i}function rn(e,t,n,r,i){var s=t.line,o=t.ch,u=e.getLine(s),a=n?1:-1,f=r?P:D;if(i&&u==""){s+=a,u=e.getLine(s);if(!R(e,s))return null;o=n?0:u.length}for(;;){if(i&&u=="")return{from:0,to:0,line:s};var l=a>0?u.length:-1,c=l,h=l;while(o!=l){var p=!1;for(var d=0;d0?0:u.length}throw new Error("The impossible happened.")}function sn(e,t,n,r,i,s){var o=Lt(t),u=[];(r&&!i||!r&&i)&&n++;var a=!r||!i;for(var f=0;f0?1:-1;var n=e.ace.session.getFoldLine(t);n&&t+r>n.start.row&&t+r0?n.end.row:n.start.row)-t)}var s=t.line,o=e.firstLine(),u=e.lastLine(),a,f,l=s;if(r){while(o<=l&&l<=u&&n>0)p(l),h(l,r)&&n--,l+=r;return new E(l,0)}var d=e.state.vim;if(d.visualLine&&h(s,1,!0)){var v=d.sel.anchor;h(v.line,-1,!0)&&(!i||v.line!=s)&&(s+=1)}var m=c(s);for(l=s;l<=u&&n;l++)h(l,1,!0)&&(!i||c(l)!=m)&&n--;f=new E(l,0),l>u&&!m?m=!0:i=!1;for(l=s;l>o;l--)if(!i||c(l)==m||l==s)if(h(l,-1,!0))break;return a=new E(l,0),{start:a,end:f}}function cn(e,t,n,r){var i=t,s,o,u={"(":/[()]/,")":/[()]/,"[":/[[\]]/,"]":/[[\]]/,"{":/[{}]/,"}":/[{}]/}[n],a={"(":"(",")":"(","[":"[","]":"[","{":"{","}":"{"}[n],f=e.getLine(i.line).charAt(i.ch),l=f===a?1:0;s=e.scanForBracket(E(i.line,i.ch+l),-1,null,{bracketRegex:u}),o=e.scanForBracket(E(i.line,i.ch+l),1,null,{bracketRegex:u});if(!s||!o)return{start:i,end:i};s=s.pos,o=o.pos;if(s.line==o.line&&s.ch>o.ch||s.line>o.line){var c=s;s=o,o=c}return r?o.ch+=1:s.ch+=1,{start:s,end:o}}function hn(e,t,n,r){var i=Lt(t),s=e.getLine(i.line),o=s.split(""),u,a,f,l,c=o.indexOf(n);i.ch-1&&!u;f--)o[f]==n&&(u=f+1);if(u&&!a)for(f=u,l=o.length;f'+t+"",{bottom:!0,duration:5e3}):alert(t)}function Nn(e,t){var n="";return e&&(n+=''+e+" "),n+=' ',t&&(n+='',n+=t,n+=" "),n}function kn(e,t){var n=(t.prefix||"")+" "+(t.desc||""),r=Nn(t.prefix,t.desc);vn(e,r,n,t.onClose,t)}function Ln(e,t){if(e instanceof RegExp&&t instanceof RegExp){var n=["global","multiline","ignoreCase","source"];for(var r=0;r=t&&e<=n:e==t}function Hn(e){var t=e.ace.renderer;return{top:t.getFirstFullyVisibleRow(),bottom:t.getLastFullyVisibleRow()}}function In(e,t,n,r,i,s,o,u,a){function c(){e.operation(function(){while(!f)h(),p();d()})}function h(){var t=e.getRange(s.from(),s.to()),n=t.replace(o,u);s.replace(n)}function p(){while(s.findNext()&&Pn(s.from(),r,i)){if(!n&&l&&s.from().line==l.line)continue;e.scrollIntoView(s.from(),30),e.setSelection(s.from(),s.to()),l=s.from(),f=!1;return}f=!0}function d(t){t&&t(),e.focus();if(l){e.setCursor(l);var n=e.state.vim;n.exMode=!1,n.lastHPos=n.lastHSPos=l.ch}a&&a()}function m(t,n,r){v.e_stop(t);var i=v.keyName(t);switch(i){case"Y":h(),p();break;case"N":p();break;case"A":var s=a;a=undefined,e.operation(c),a=s;break;case"L":h();case"Q":case"Esc":case"Ctrl-C":case"Ctrl-[":d(r)}return f&&d(r),!0}e.state.vim.exMode=!0;var f=!1,l=s.from();p();if(f){Tn(e,"No matches for "+o.source);return}if(!t){c(),a&&a();return}kn(e,{prefix:"replace with "+u+" (y/n/a/q/l)",onKeyDown:m})}function qn(e){var t=e.state.vim,n=nt.macroModeState,r=nt.registerController.getRegister("."),i=n.isPlaying,s=n.lastInsertModeChanges,o=[];if(!i){var u=s.inVisualBlock?t.lastSelection.visualBlock.height:1,a=s.changes,o=[],f=0;while(f1&&(Zn(e,t,t.insertModeRepeat-1,!0),t.lastEditInputState.repeatOverride=t.insertModeRepeat),delete t.insertModeRepeat,t.insertMode=!1,e.setCursor(e.getCursor().line,e.getCursor().ch-1),e.setOption("keyMap","vim"),e.setOption("disableInput",!0),e.toggleOverwrite(!1),r.setText(s.changes.join("")),v.signal(e,"vim-mode-change",{mode:"normal"}),n.isRecording&&Xn(n)}function Rn(e){b.unshift(e)}function Un(e,t,n,r,i){var s={keys:e,type:t};s[t]=n,s[t+"Args"]=r;for(var o in i)s[o]=i[o];Rn(s)}function zn(e,t,n,r){var i=nt.registerController.getRegister(r);if(r==":"){i.keyBuffer[0]&&Fn.processCommand(e,i.keyBuffer[0]),n.isPlaying=!1;return}var s=i.keyBuffer,o=0;n.isPlaying=!0,n.replaySearchQueries=i.searchQueries.slice(0);for(var u=0;u|<\w+>|./.exec(a),l=f[0],a=a.substring(f.index+l.length),v.Vim.handleKey(e,l,"macro");if(t.insertMode){var c=i.insertModeChanges[o++].changes;nt.macroModeState.lastInsertModeChanges.changes=c,er(e,c,1),qn(e)}}}n.isPlaying=!1}function Wn(e,t){if(e.isPlaying)return;var n=e.latestRegister,r=nt.registerController.getRegister(n);r&&r.pushText(t)}function Xn(e){if(e.isPlaying)return;var t=e.latestRegister,n=nt.registerController.getRegister(t);n&&n.pushInsertModeChanges&&n.pushInsertModeChanges(e.lastInsertModeChanges)}function Vn(e,t){if(e.isPlaying)return;var n=e.latestRegister,r=nt.registerController.getRegister(n);r&&r.pushSearchQuery&&r.pushSearchQuery(t)}function $n(e,t){var n=nt.macroModeState,r=n.lastInsertModeChanges;if(!n.isPlaying)while(t){r.expectCursorActivityForChange=!0;if(t.origin=="+input"||t.origin=="paste"||t.origin===undefined){var i=t.text.join("\n");r.changes.push(i)}t=t.next}}function Jn(e){var t=e.state.vim;if(t.insertMode){var n=nt.macroModeState;if(n.isPlaying)return;var r=n.lastInsertModeChanges;r.expectCursorActivityForChange?r.expectCursorActivityForChange=!1:r.changes=[]}else e.curOp.isVimOp||Qn(e,t);t.visualMode&&Kn(e)}function Kn(e){var t=e.state.vim,n=wt(e,Lt(t.sel.head)),r=St(n,0,1);t.fakeCursor&&t.fakeCursor.clear(),t.fakeCursor=e.markText(n,r,{className:"cm-animate-fat-cursor"})}function Qn(e,t){var n=e.getCursor("anchor"),r=e.getCursor("head");t.visualMode&&!e.somethingSelected()?$t(e,!1):!t.visualMode&&!t.insertMode&&e.somethingSelected()&&(t.visualMode=!0,t.visualLine=!1,v.signal(e,"vim-mode-change",{mode:"visual"}));if(t.visualMode){var i=Ot(r,n)?0:-1,s=Ot(r,n)?-1:0;r=St(r,0,i),n=St(n,0,s),t.sel={anchor:n,head:r},an(e,t,"<",Mt(r,n)),an(e,t,">",_t(r,n))}else t.insertMode||(t.lastHPos=e.getCursor().ch)}function Gn(e){this.keyName=e}function Yn(e){function i(){return n.changes.push(new Gn(r)),!0}var t=nt.macroModeState,n=t.lastInsertModeChanges,r=v.keyName(e);if(!r)return;(r.indexOf("Delete")!=-1||r.indexOf("Backspace")!=-1)&&v.lookupKey(r,"vim-insert",i)}function Zn(e,t,n,r){function u(){s?ht.processAction(e,t,t.lastEditActionCommand):ht.evalInput(e,t)}function a(n){if(i.lastInsertModeChanges.changes.length>0){n=t.lastEditActionCommand?n:1;var r=i.lastInsertModeChanges;er(e,r.changes,n)}}var i=nt.macroModeState;i.isPlaying=!0;var s=!!t.lastEditActionCommand,o=t.inputState;t.inputState=t.lastEditInputState;if(s&&t.lastEditActionCommand.interlaceInsertRepeat)for(var f=0;f1&&t[0]=="n"&&(t=t.replace("numpad","")),t=tr[t]||t;var r="";return n.ctrlKey&&(r+="C-"),n.altKey&&(r+="A-"),n.shiftKey&&(r+="S-"),r+=t,r.length>1&&(r="<"+r+">"),r}function ir(e){var t=new e.constructor;return Object.keys(e).forEach(function(n){var r=e[n];Array.isArray(r)?r=r.slice():r&&typeof r=="object"&&r.constructor!=Object&&(r=ir(r)),t[n]=r}),e.sel&&(t.sel={head:e.sel.head&&Lt(e.sel.head),anchor:e.sel.anchor&&Lt(e.sel.anchor)}),t}function sr(e,t,n){var r=!1,i=S.maybeInitVimState_(e),s=i.visualBlock||i.wasInVisualBlock;i.wasInVisualBlock&&!e.ace.inMultiSelectMode?i.wasInVisualBlock=!1:e.ace.inMultiSelectMode&&i.visualBlock&&(i.wasInVisualBlock=!0);if(t==""&&!i.insertMode&&!i.visualMode&&e.ace.inMultiSelectMode)e.ace.exitMultiSelectMode();else if(s||!e.ace.inMultiSelectMode||e.ace.inVirtualSelectionMode)r=S.handleKey(e,t,n);else{var o=ir(i);e.operation(function(){e.ace.forEachSelection(function(){var i=e.ace.selection;e.state.vim.lastHPos=i.$desiredColumn==null?i.lead.column:i.$desiredColumn;var s=e.getCursor("head"),u=e.getCursor("anchor"),a=Ot(s,u)?0:-1,f=Ot(s,u)?-1:0;s=St(s,0,a),u=St(u,0,f),e.state.vim.sel.head=s,e.state.vim.sel.anchor=u,r=rr(e,t,n),i.$desiredColumn=e.state.vim.lastHPos==-1?null:e.state.vim.lastHPos,e.virtualSelectionMode()&&(e.state.vim=ir(o))}),e.curOp.cursorActivity&&!r&&(e.curOp.cursorActivity=!1)},!0)}return r}function ar(e,t){t.off("beforeEndOperation",ar);var n=t.state.cm.vimCmd;n&&t.execCommand(n.exec?n:n.name,n.args),t.curOp=t.prevOp}var i=e("../range").Range,s=e("../lib/event_emitter").EventEmitter,o=e("../lib/dom"),u=e("../lib/oop"),a=e("../lib/keys"),f=e("../lib/event"),l=e("../search").Search,c=e("../lib/useragent"),h=e("../search_highlight").SearchHighlight,p=e("../commands/multi_select_commands"),d=e("../mode/text").Mode.prototype.tokenRe;e("../multi_select");var v=function(e){this.ace=e,this.state={},this.marks={},this.$uid=0,this.onChange=this.onChange.bind(this),this.onSelectionChange=this.onSelectionChange.bind(this),this.onBeforeEndOperation=this.onBeforeEndOperation.bind(this),this.ace.on("change",this.onChange),this.ace.on("changeSelection",this.onSelectionChange),this.ace.on("beforeEndOperation",this.onBeforeEndOperation)};v.Pos=function(e,t){if(!(this instanceof E))return new E(e,t);this.line=e,this.ch=t},v.defineOption=function(e,t,n){},v.commands={redo:function(e){e.ace.redo()},undo:function(e){e.ace.undo()},newlineAndIndent:function(e){e.ace.insert("\n")}},v.keyMap={},v.addClass=v.rmClass=v.e_stop=function(){},v.keyName=function(e){if(e.key)return e.key;var t=a[e.keyCode]||"";return t.length==1&&(t=t.toUpperCase()),t=f.getModifierString(e).replace(/(^|-)\w/g,function(e){return e.toUpperCase()})+t,t},v.keyMap["default"]=function(e){return function(t){var n=t.ace.commands.commandKeyBinding[e.toLowerCase()];return n&&t.ace.execCommand(n)!==!1}},v.lookupKey=function fr(e,t,n){typeof t=="string"&&(t=v.keyMap[t]);var r=typeof t=="function"?t(e):t[e];if(r===!1)return"nothing";if(r==="...")return"multi";if(r!=null&&n(r))return"handled";if(t.fallthrough){if(!Array.isArray(t.fallthrough))return fr(e,t.fallthrough,n);for(var i=0;i0){a.row+=s,a.column+=a.row==r.row?o:0;continue}!t&&l<=0&&(a.row=n.row,a.column=n.column,l===0&&(a.bias=1))}};var e=function(e,t,n,r){this.cm=e,this.id=t,this.row=n,this.column=r,e.marks[this.id]=this};e.prototype.clear=function(){delete this.cm.marks[this.id]},e.prototype.find=function(){return g(this)},this.setBookmark=function(t,n){var r=new e(this,this.$uid++,t.line,t.ch);if(!n||!n.insertLeft)r.$insertRight=!0;return this.marks[r.id]=r,r},this.moveH=function(e,t){if(t=="char"){var n=this.ace.selection;n.clearSelection(),n.moveCursorBy(0,e)}},this.findPosV=function(e,t,n,r){if(n=="page"){var i=this.ace.renderer,s=i.layerConfig;t*=Math.floor(s.height/s.lineHeight),n="line"}if(n=="line"){var o=this.ace.session.documentToScreenPosition(e.line,e.ch);r!=null&&(o.column=r),o.row+=t,o.row=Math.min(Math.max(0,o.row),this.ace.session.getScreenLength()-1);var u=this.ace.session.screenToDocumentPosition(o.row,o.column);return g(u)}debugger},this.charCoords=function(e,t){if(t=="div"||!t){var n=this.ace.session.documentToScreenPosition(e.line,e.ch);return{left:n.column,top:n.row}}if(t=="local"){var r=this.ace.renderer,n=this.ace.session.documentToScreenPosition(e.line,e.ch),i=r.layerConfig.lineHeight,s=r.layerConfig.characterWidth,o=i*n.row;return{left:n.column*s,top:o,bottom:o+i}}},this.coordsChar=function(e,t){var n=this.ace.renderer;if(t=="local"){var r=Math.max(0,Math.floor(e.top/n.lineHeight)),i=Math.max(0,Math.floor(e.left/n.characterWidth)),s=n.session.screenToDocumentPosition(r,i);return g(s)}if(t=="div")throw"not implemented"},this.getSearchCursor=function(e,t,n){var r=!1,i=!1;e instanceof RegExp&&!e.global&&(r=!e.ignoreCase,e=e.source,i=!0);var s=new l;t.ch==undefined&&(t.ch=Number.MAX_VALUE);var o={row:t.line,column:t.ch},u=this,a=null;return{findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(t){s.setOptions({needle:e,caseSensitive:r,wrap:!1,backwards:t,regExp:i,start:a||o});var n=s.find(u.ace.session);return n&&n.isEmpty()&&u.getLine(n.start.row).length==n.start.column&&(s.$options.start=n,n=s.find(u.ace.session)),a=n,a},from:function(){return a&&g(a.start)},to:function(){return a&&g(a.end)},replace:function(e){a&&(a.end=u.ace.session.doc.replace(a,e))}}},this.scrollTo=function(e,t){var n=this.ace.renderer,r=n.layerConfig,i=r.maxHeight;i-=(n.$size.scrollerHeight-n.lineHeight)*n.$scrollPastEnd,t!=null&&this.ace.session.setScrollTop(Math.max(0,Math.min(t,i))),e!=null&&this.ace.session.setScrollLeft(Math.max(0,Math.min(e,r.width)))},this.scrollInfo=function(){return 0},this.scrollIntoView=function(e,t){if(e){var n=this.ace.renderer,r={top:0,bottom:t};n.scrollCursorIntoView(m(e),n.lineHeight*2/n.$size.scrollerHeight,r)}},this.getLine=function(e){return this.ace.session.getLine(e)},this.getRange=function(e,t){return this.ace.session.getTextRange(new i(e.line,e.ch,t.line,t.ch))},this.replaceRange=function(e,t,n){return n||(n=t),this.ace.session.replace(new i(t.line,t.ch,n.line,n.ch),e)},this.replaceSelections=function(e){var t=this.ace.selection;if(this.ace.inVirtualSelectionMode){this.ace.session.replace(t.getRange(),e[0]||"");return}t.inVirtualSelectionMode=!0;var n=t.rangeList.ranges;n.length||(n=[this.ace.multiSelect.getRange()]);for(var r=n.length;r--;)this.ace.session.replace(n[r],e[r]||"");t.inVirtualSelectionMode=!1},this.getSelection=function(){return this.ace.getSelectedText()},this.getSelections=function(){return this.listSelections().map(function(e){return this.getRange(e.anchor,e.head)},this)},this.getInputField=function(){return this.ace.textInput.getElement()},this.getWrapperElement=function(){return this.ace.containter};var t={indentWithTabs:"useSoftTabs",indentUnit:"tabSize",tabSize:"tabSize",firstLineNumber:"firstLineNumber",readOnly:"readOnly"};this.setOption=function(e,n){this.state[e]=n;switch(e){case"indentWithTabs":e=t[e],n=!n;break;default:e=t[e]}e&&this.ace.setOption(e,n)},this.getOption=function(e,n){var r=t[e];r&&(n=this.ace.getOption(r));switch(e){case"indentWithTabs":return e=t[e],!n}return r?n:this.state[e]},this.toggleOverwrite=function(e){return this.state.overwrite=e,this.ace.setOverwrite(e)},this.addOverlay=function(e){if(!this.$searchHighlight||!this.$searchHighlight.session){var t=new h(null,"ace_highlight-marker","text"),n=this.ace.session.addDynamicMarker(t);t.id=n.id,t.session=this.ace.session,t.destroy=function(e){t.session.off("change",t.updateOnChange),t.session.off("changeEditor",t.destroy),t.session.removeMarker(t.id),t.session=null},t.updateOnChange=function(e){var n=e.start.row;n==e.end.row?t.cache[n]=undefined:t.cache.splice(n,t.cache.length)},t.session.on("changeEditor",t.destroy),t.session.on("change",t.updateOnChange)}var r=new RegExp(e.query.source,"gmi");this.$searchHighlight=e.highlight=t,this.$searchHighlight.setRegexp(r),this.ace.renderer.updateBackMarkers()},this.removeOverlay=function(e){this.$searchHighlight&&this.$searchHighlight.session&&this.$searchHighlight.destroy()},this.getScrollInfo=function(){var e=this.ace.renderer,t=e.layerConfig;return{left:e.scrollLeft,top:e.scrollTop,height:t.maxHeight,width:t.width,clientHeight:t.height,clientWidth:t.width}},this.getValue=function(){return this.ace.getValue()},this.setValue=function(e){return this.ace.setValue(e)},this.getTokenTypeAt=function(e){var t=this.ace.session.getTokenAt(e.line,e.ch);return t&&/comment|string/.test(t.type)?"string":""},this.findMatchingBracket=function(e){var t=this.ace.session.findMatchingBracket(m(e));return{to:t&&g(t)}},this.indentLine=function(e,t){t===!0?this.ace.session.indentRows(e,e," "):t===!1&&this.ace.session.outdentRows(new i(e,0,e,0))},this.indexFromPos=function(e){return this.ace.session.doc.positionToIndex(m(e))},this.posFromIndex=function(e){return g(this.ace.session.doc.indexToPosition(e))},this.focus=function(e){return this.ace.focus()},this.blur=function(e){return this.ace.blur()},this.defaultTextHeight=function(e){return this.ace.renderer.layerConfig.lineHeight},this.scanForBracket=function(e,t,n,r){var i=r.bracketRegex.source;if(t==1)var s=this.ace.session.$findClosingBracket(i.slice(1,2),m(e),/paren|text/);else var s=this.ace.session.$findOpeningBracket(i.slice(-2,-1),{row:e.line,column:e.ch+1},/paren|text/);return s&&{pos:g(s)}},this.refresh=function(){return this.ace.resize(!0)},this.getMode=function(){return{name:this.getOption("mode")}}}.call(v.prototype);var y=v.StringStream=function(e,t){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0};y.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return this.pos==this.lineStart},peek:function(){return this.string.charAt(this.pos)||undefined},next:function(){if(this.post},eatSpace:function(){var e=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos)))++this.pos;return this.pos>e},skipToEnd:function(){this.pos=this.string.length},skipTo:function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},backUp:function(e){this.pos-=e},column:function(){throw"not implemented"},indentation:function(){throw"not implemented"},match:function(e,t,n){if(typeof e!="string"){var s=this.string.slice(this.pos).match(e);return s&&s.index>0?null:(s&&t!==!1&&(this.pos+=s[0].length),s)}var r=function(e){return n?e.toLowerCase():e},i=this.string.substr(this.pos,e.length);if(r(i)==r(e))return t!==!1&&(this.pos+=e.length),!0},current:function(){return this.string.slice(this.start,this.pos)},hideFirstChars:function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}}},v.defineExtension=function(e,t){v.prototype[e]=t},o.importCssString(".normal-mode .ace_cursor{ border: 1px solid red; background-color: red; opacity: 0.5;}.normal-mode .ace_hidden-cursors .ace_cursor{ background-color: transparent;}.ace_dialog { position: absolute; left: 0; right: 0; background: white; z-index: 15; padding: .1em .8em; overflow: hidden; color: #333;}.ace_dialog-top { border-bottom: 1px solid #eee; top: 0;}.ace_dialog-bottom { border-top: 1px solid #eee; bottom: 0;}.ace_dialog input { border: none; outline: none; background: transparent; width: 20em; color: inherit; font-family: monospace;}","vimMode"),function(){function e(e,t,n){var r=e.ace.container,i;return i=r.appendChild(document.createElement("div")),n?i.className="ace_dialog ace_dialog-bottom":i.className="ace_dialog ace_dialog-top",typeof t=="string"?i.innerHTML=t:i.appendChild(t),i}function t(e,t){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=t}v.defineExtension("openDialog",function(n,r,i){function a(e){if(typeof e=="string")f.value=e;else{if(o)return;o=!0,s.parentNode.removeChild(s),u.focus(),i.onClose&&i.onClose(s)}}if(this.virtualSelectionMode())return;i||(i={}),t(this,null);var s=e(this,n,i.bottom),o=!1,u=this,f=s.getElementsByTagName("input")[0],l;if(f)i.value&&(f.value=i.value,i.select!==!1&&f.select()),i.onInput&&v.on(f,"input",function(e){i.onInput(e,f.value,a)}),i.onKeyUp&&v.on(f,"keyup",function(e){i.onKeyUp(e,f.value,a)}),v.on(f,"keydown",function(e){if(i&&i.onKeyDown&&i.onKeyDown(e,f.value,a))return;if(e.keyCode==27||i.closeOnEnter!==!1&&e.keyCode==13)f.blur(),v.e_stop(e),a();e.keyCode==13&&r(f.value)}),i.closeOnBlur!==!1&&v.on(f,"blur",a),f.focus();else if(l=s.getElementsByTagName("button")[0])v.on(l,"click",function(){a(),u.focus()}),i.closeOnBlur!==!1&&v.on(l,"blur",a),l.focus();return a}),v.defineExtension("openNotification",function(n,r){function a(){if(s)return;s=!0,clearTimeout(o),i.parentNode.removeChild(i)}if(this.virtualSelectionMode())return;t(this,a);var i=e(this,n,r&&r.bottom),s=!1,o,u=r&&typeof r.duration!="undefined"?r.duration:5e3;return v.on(i,"click",function(e){v.e_preventDefault(e),a()}),u&&(o=setTimeout(a,u)),a})}();var b=[{keys:"",type:"keyToKey",toKeys:"h"},{keys:"",type:"keyToKey",toKeys:"l"},{keys:"",type:"keyToKey",toKeys:"k"},{keys:"",type:"keyToKey",toKeys:"j"},{keys:"",type:"keyToKey",toKeys:"l"},{keys:"",type:"keyToKey",toKeys:"h",context:"normal"},{keys:"",type:"keyToKey",toKeys:"W"},{keys:"",type:"keyToKey",toKeys:"B",context:"normal"},{keys:"",type:"keyToKey",toKeys:"w"},{keys:"",type:"keyToKey",toKeys:"b",context:"normal"},{keys:"",type:"keyToKey",toKeys:"j"},{keys:"",type:"keyToKey",toKeys:"k"},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:"",context:"insert"},{keys:"",type:"keyToKey",toKeys:"",context:"insert"},{keys:"s",type:"keyToKey",toKeys:"cl",context:"normal"},{keys:"s",type:"keyToKey",toKeys:"xi",context:"visual"},{keys:"S",type:"keyToKey",toKeys:"cc",context:"normal"},{keys:"S",type:"keyToKey",toKeys:"dcc",context:"visual"},{keys:"",type:"keyToKey",toKeys:"0"},{keys:"",type:"keyToKey",toKeys:"$"},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:"j^",context:"normal"},{keys:"H",type:"motion",motion:"moveToTopLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"M",type:"motion",motion:"moveToMiddleLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"L",type:"motion",motion:"moveToBottomLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"h",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!1}},{keys:"l",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!0}},{keys:"j",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,linewise:!0}},{keys:"k",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,linewise:!0}},{keys:"gj",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!0}},{keys:"gk",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!1}},{keys:"w",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1}},{keys:"W",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1,bigWord:!0}},{keys:"e",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,inclusive:!0}},{keys:"E",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"b",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1}},{keys:"B",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1,bigWord:!0}},{keys:"ge",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,inclusive:!0}},{keys:"gE",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"{",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!1,toJumplist:!0}},{keys:"}",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!0,toJumplist:!0}},{keys:"",type:"motion",motion:"moveByPage",motionArgs:{forward:!0}},{keys:"",type:"motion",motion:"moveByPage",motionArgs:{forward:!1}},{keys:"",type:"motion",motion:"moveByScroll",motionArgs:{forward:!0,explicitRepeat:!0}},{keys:"",type:"motion",motion:"moveByScroll",motionArgs:{forward:!1,explicitRepeat:!0}},{keys:"gg",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!1,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"G",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!0,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"0",type:"motion",motion:"moveToStartOfLine"},{keys:"^",type:"motion",motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"+",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0}},{keys:"-",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,toFirstChar:!0}},{keys:"_",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0,repeatOffset:-1}},{keys:"$",type:"motion",motion:"moveToEol",motionArgs:{inclusive:!0}},{keys:"%",type:"motion",motion:"moveToMatchedSymbol",motionArgs:{inclusive:!0,toJumplist:!0}},{keys:"f",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"F",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!1}},{keys:"t",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"T",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!1}},{keys:";",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!0}},{keys:",",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!1}},{keys:"'",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0,linewise:!0}},{keys:"`",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0}},{keys:"]`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0}},{keys:"[`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1}},{keys:"]'",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0,linewise:!0}},{keys:"['",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1,linewise:!0}},{keys:"]p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0,matchIndent:!0}},{keys:"[p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0,matchIndent:!0}},{keys:"]",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!0,toJumplist:!0}},{keys:"[",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!1,toJumplist:!0}},{keys:"|",type:"motion",motion:"moveToColumn"},{keys:"o",type:"motion",motion:"moveToOtherHighlightedEnd",context:"visual"},{keys:"O",type:"motion",motion:"moveToOtherHighlightedEnd",motionArgs:{sameLine:!0},context:"visual"},{keys:"d",type:"operator",operator:"delete"},{keys:"y",type:"operator",operator:"yank"},{keys:"c",type:"operator",operator:"change"},{keys:">",type:"operator",operator:"indent",operatorArgs:{indentRight:!0}},{keys:"<",type:"operator",operator:"indent",operatorArgs:{indentRight:!1}},{keys:"g~",type:"operator",operator:"changeCase"},{keys:"gu",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},isEdit:!0},{keys:"gU",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},isEdit:!0},{keys:"n",type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:!0}},{keys:"N",type:"motion",motion:"findNext",motionArgs:{forward:!1,toJumplist:!0}},{keys:"x",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!0},operatorMotionArgs:{visualLine:!1}},{keys:"X",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!1},operatorMotionArgs:{visualLine:!0}},{keys:"D",type:"operatorMotion",operator:"delete",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"D",type:"operator",operator:"delete",operatorArgs:{linewise:!0},context:"visual"},{keys:"Y",type:"operatorMotion",operator:"yank",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"Y",type:"operator",operator:"yank",operatorArgs:{linewise:!0},context:"visual"},{keys:"C",type:"operatorMotion",operator:"change",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"C",type:"operator",operator:"change",operatorArgs:{linewise:!0},context:"visual"},{keys:"~",type:"operatorMotion",operator:"changeCase",motion:"moveByCharacters",motionArgs:{forward:!0},operatorArgs:{shouldMoveCursor:!0},context:"normal"},{keys:"~",type:"operator",operator:"changeCase",context:"visual"},{keys:"",type:"operatorMotion",operator:"delete",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1},context:"insert"},{keys:"",type:"action",action:"jumpListWalk",actionArgs:{forward:!0}},{keys:"",type:"action",action:"jumpListWalk",actionArgs:{forward:!1}},{keys:"",type:"action",action:"scroll",actionArgs:{forward:!0,linewise:!0}},{keys:"",type:"action",action:"scroll",actionArgs:{forward:!1,linewise:!0}},{keys:"a",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"charAfter"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"eol"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"endOfSelectedArea"},context:"visual"},{keys:"i",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"inplace"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"firstNonBlank"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"startOfSelectedArea"},context:"visual"},{keys:"o",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!0},context:"normal"},{keys:"O",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!1},context:"normal"},{keys:"v",type:"action",action:"toggleVisualMode"},{keys:"V",type:"action",action:"toggleVisualMode",actionArgs:{linewise:!0}},{keys:"",type:"action",action:"toggleVisualMode",actionArgs:{blockwise:!0}},{keys:"gv",type:"action",action:"reselectLastSelection"},{keys:"J",type:"action",action:"joinLines",isEdit:!0},{keys:"p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0}},{keys:"P",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0}},{keys:"r",type:"action",action:"replace",isEdit:!0},{keys:"@",type:"action",action:"replayMacro"},{keys:"q",type:"action",action:"enterMacroRecordMode"},{keys:"R",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{replace:!0}},{keys:"u",type:"action",action:"undo",context:"normal"},{keys:"u",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},context:"visual",isEdit:!0},{keys:"U",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},context:"visual",isEdit:!0},{keys:"",type:"action",action:"redo"},{keys:"m",type:"action",action:"setMark"},{keys:'"',type:"action",action:"setRegister"},{keys:"zz",type:"action",action:"scrollToCursor",actionArgs:{position:"center"}},{keys:"z.",type:"action",action:"scrollToCursor",actionArgs:{position:"center"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"zt",type:"action",action:"scrollToCursor",actionArgs:{position:"top"}},{keys:"z",type:"action",action:"scrollToCursor",actionArgs:{position:"top"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"z-",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"}},{keys:"zb",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:".",type:"action",action:"repeatLastEdit"},{keys:"",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!0,backtrack:!1}},{keys:"",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!1,backtrack:!1}},{keys:"a",type:"motion",motion:"textObjectManipulation"},{keys:"i",type:"motion",motion:"textObjectManipulation",motionArgs:{textObjectInner:!0}},{keys:"/",type:"search",searchArgs:{forward:!0,querySrc:"prompt",toJumplist:!0}},{keys:"?",type:"search",searchArgs:{forward:!1,querySrc:"prompt",toJumplist:!0}},{keys:"*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"g*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:"g#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:":",type:"ex"}],w=[{name:"colorscheme",shortName:"colo"},{name:"map"},{name:"imap",shortName:"im"},{name:"nmap",shortName:"nm"},{name:"vmap",shortName:"vm"},{name:"unmap"},{name:"write",shortName:"w"},{name:"undo",shortName:"u"},{name:"redo",shortName:"red"},{name:"set",shortName:"se"},{name:"set",shortName:"se"},{name:"setlocal",shortName:"setl"},{name:"setglobal",shortName:"setg"},{name:"sort",shortName:"sor"},{name:"substitute",shortName:"s",possiblyAsync:!0},{name:"nohlsearch",shortName:"noh"},{name:"delmarks",shortName:"delm"},{name:"registers",shortName:"reg",excludeFromCommandHistory:!0},{name:"global",shortName:"g"}],E=v.Pos,S=function(){return st};v.defineOption("vimMode",!1,function(e,t,n){t&&e.getOption("keyMap")!="vim"?e.setOption("keyMap","vim"):!t&&n!=v.Init&&/^vim/.test(e.getOption("keyMap"))&&e.setOption("keyMap","default")});var L={Shift:"S",Ctrl:"C",Alt:"A",Cmd:"D",Mod:"A"},A={Enter:"CR",Backspace:"BS",Delete:"Del"},_=/[\d]/,D=[v.isWordChar,function(e){return e&&!v.isWordChar(e)&&!/\s/.test(e)}],P=[function(e){return/\S/.test(e)}],B=H(65,26),j=H(97,26),F=H(48,10),I=[].concat(B,j,F,["<",">"]),q=[].concat(B,j,F,["-",'"',".",":","/"]),J={};K("filetype",undefined,"string",["ft"],function(e,t){if(t===undefined)return;if(e===undefined){var n=t.getOption("mode");return n=="null"?"":n}var n=e==""?"null":e;t.setOption("mode",n)});var Y=function(){function s(s,o,u){function l(n){var r=++t%e,o=i[r];o&&o.clear(),i[r]=s.setBookmark(n)}var a=t%e,f=i[a];if(f){var c=f.find();c&&!At(c,o)&&l(o)}else l(o);l(u),n=t,r=t-e+1,r<0&&(r=0)}function o(s,o){t+=o,t>n?t=n:t0?1:-1,f,l=s.getCursor();do{t+=a,u=i[(e+t)%e];if(u&&(f=u.find())&&!At(l,f))break}while(tr)}return u}var e=100,t=-1,n=0,r=0,i=new Array(e);return{cachedCursor:undefined,add:s,move:o}},Z=function(e){return e?{changes:e.changes,expectCursorActivityForChange:e.expectCursorActivityForChange}:{changes:[],expectCursorActivityForChange:!1}};et.prototype={exitMacroRecordMode:function(){var e=nt.macroModeState;e.onRecordingDone&&e.onRecordingDone(),e.onRecordingDone=undefined,e.isRecording=!1},enterMacroRecordMode:function(e,t){var n=nt.registerController.getRegister(t);n&&(n.clear(),this.latestRegister=t,e.openDialog&&(this.onRecordingDone=e.openDialog("(recording)["+t+"]",null,{bottom:!0})),this.isRecording=!0)}};var nt,it,st={buildKeyMap:function(){},getRegisterController:function(){return nt.registerController},resetVimGlobalState_:rt,getVimGlobalState_:function(){return nt},maybeInitVimState_:tt,suppressErrorLogging:!1,InsertModeKey:Gn,map:function(e,t,n){Fn.map(e,t,n)},unmap:function(e,t){Fn.unmap(e,t||"normal")},setOption:Q,getOption:G,defineOption:K,defineEx:function(e,t,n){if(!t)t=e;else if(e.indexOf(t)!==0)throw new Error('(Vim.defineEx) "'+t+'" is not a prefix of "'+e+'", command not registered');jn[e]=n,Fn.commandMap_[t]={name:e,shortName:t,type:"api"}},handleKey:function(e,t,n){var r=this.findKey(e,t,n);if(typeof r=="function")return r()},findKey:function(e,t,n){function i(){var r=nt.macroModeState;if(r.isRecording){if(t=="q")return r.exitMacroRecordMode(),ut(e),!0;n!="mapping"&&Wn(r,t)}}function s(){if(t=="")return ut(e),r.visualMode?$t(e):r.insertMode&&qn(e),!0}function o(n){var r;while(n)r=/<\w+-.+?>|<\w+>|./.exec(n),t=r[0],n=n.substring(r.index+t.length),v.Vim.handleKey(e,t,"mapping")}function u(){if(s())return!0;var n=r.inputState.keyBuffer=r.inputState.keyBuffer+t,i=t.length==1,o=ht.matchCommand(n,b,r.inputState,"insert");while(n.length>1&&o.type!="full"){var n=r.inputState.keyBuffer=n.slice(1),u=ht.matchCommand(n,b,r.inputState,"insert");u.type!="none"&&(o=u)}if(o.type=="none")return ut(e),!1;if(o.type=="partial")return it&&window.clearTimeout(it),it=window.setTimeout(function(){r.insertMode&&r.inputState.keyBuffer&&ut(e)},G("insertModeEscKeysTimeout")),!i;it&&window.clearTimeout(it);if(i){var a=e.getCursor();e.replaceRange("",St(a,0,-(n.length-1)),a,"+input")}return ut(e),o.command}function a(){if(i()||s())return!0;var n=r.inputState.keyBuffer=r.inputState.keyBuffer+t;if(/^[1-9]\d*$/.test(n))return!0;var o=/^(\d*)(.*)$/.exec(n);if(!o)return ut(e),!1;var u=r.visualMode?"visual":"normal",a=ht.matchCommand(o[2]||o[1],b,r.inputState,u);if(a.type=="none")return ut(e),!1;if(a.type=="partial")return!0;r.inputState.keyBuffer="";var o=/^(\d*)(.*)$/.exec(n);return o[1]&&o[1]!="0"&&r.inputState.pushRepeatDigit(o[1]),a.command}var r=tt(e),f;return r.insertMode?f=u():f=a(),f===!1?undefined:f===!0?function(){return!0}:function(){if((f.operator||f.isEdit)&&e.getOption("readOnly"))return;return e.operation(function(){e.curOp.isVimOp=!0;try{f.type=="keyToKey"?o(f.toKeys):ht.processCommand(e,r,f)}catch(t){throw e.state.vim=undefined,tt(e),v.Vim.suppressErrorLogging||console.log(t),t}return!0})}},handleEx:function(e,t){Fn.processCommand(e,t)},defineMotion:dt,defineAction:bt,defineOperator:gt,mapCommand:Un,_mapCommand:Rn,defineRegister:ft,exitVisualMode:$t,exitInsertMode:qn};ot.prototype.pushRepeatDigit=function(e){this.operator?this.motionRepeat=this.motionRepeat.concat(e):this.prefixRepeat=this.prefixRepeat.concat(e)},ot.prototype.getRepeat=function(){var e=0;if(this.prefixRepeat.length>0||this.motionRepeat.length>0)e=1,this.prefixRepeat.length>0&&(e*=parseInt(this.prefixRepeat.join(""),10)),this.motionRepeat.length>0&&(e*=parseInt(this.motionRepeat.join(""),10));return e},at.prototype={setText:function(e,t,n){this.keyBuffer=[e||""],this.linewise=!!t,this.blockwise=!!n},pushText:function(e,t){t&&(this.linewise||this.keyBuffer.push("\n"),this.linewise=!0),this.keyBuffer.push(e)},pushInsertModeChanges:function(e){this.insertModeChanges.push(Z(e))},pushSearchQuery:function(e){this.searchQueries.push(e)},clear:function(){this.keyBuffer=[],this.insertModeChanges=[],this.searchQueries=[],this.linewise=!1},toString:function(){return this.keyBuffer.join("")}},lt.prototype={pushText:function(e,t,n,r,i){r&&n.charAt(0)=="\n"&&(n=n.slice(1)+"\n"),r&&n.charAt(n.length-1)!=="\n"&&(n+="\n");var s=this.isValidRegister(e)?this.getRegister(e):null;if(!s){switch(t){case"yank":this.registers[0]=new at(n,r,i);break;case"delete":case"change":n.indexOf("\n")==-1?this.registers["-"]=new at(n,r):(this.shiftNumericRegisters_(),this.registers[1]=new at(n,r))}this.unnamedRegister.setText(n,r,i);return}var o=X(e);o?s.pushText(n,r):s.setText(n,r,i),this.unnamedRegister.setText(s.toString(),r)},getRegister:function(e){return this.isValidRegister(e)?(e=e.toLowerCase(),this.registers[e]||(this.registers[e]=new at),this.registers[e]):this.unnamedRegister},isValidRegister:function(e){return e&&$(e,q)},shiftNumericRegisters_:function(){for(var e=9;e>=2;e--)this.registers[e]=this.getRegister(""+(e-1))}},ct.prototype={nextMatch:function(e,t){var n=this.historyBuffer,r=t?-1:1;this.initialPrefix===null&&(this.initialPrefix=e);for(var i=this.iterator+r;t?i>=0:i=n.length)return this.iterator=n.length,this.initialPrefix;if(i<0)return e},pushInput:function(e){var t=this.historyBuffer.indexOf(e);t>-1&&this.historyBuffer.splice(t,1),e.length&&this.historyBuffer.push(e)},reset:function(){this.initialPrefix=null,this.iterator=this.historyBuffer.length}};var ht={matchCommand:function(e,t,n,r){var i=Tt(e,t,r,n);if(!i.full&&!i.partial)return{type:"none"};if(!i.full&&i.partial)return{type:"partial"};var s;for(var o=0;o"&&(n.selectedCharacter=Ct(e)),{type:"full",command:s}},processCommand:function(e,t,n){t.inputState.repeatOverride=n.repeatOverride;switch(n.type){case"motion":this.processMotion(e,t,n);break;case"operator":this.processOperator(e,t,n);break;case"operatorMotion":this.processOperatorMotion(e,t,n);break;case"action":this.processAction(e,t,n);break;case"search":this.processSearch(e,t,n);break;case"ex":case"keyToEx":this.processEx(e,t,n);break;default:}},processMotion:function(e,t,n){t.inputState.motion=n.motion,t.inputState.motionArgs=Et(n.motionArgs),this.evalInput(e,t)},processOperator:function(e,t,n){var r=t.inputState;if(r.operator){if(r.operator==n.operator){r.motion="expandToLine",r.motionArgs={linewise:!0},this.evalInput(e,t);return}ut(e)}r.operator=n.operator,r.operatorArgs=Et(n.operatorArgs),t.visualMode&&this.evalInput(e,t)},processOperatorMotion:function(e,t,n){var r=t.visualMode,i=Et(n.operatorMotionArgs);i&&r&&i.visualLine&&(t.visualLine=!0),this.processOperator(e,t,n),r||this.processMotion(e,t,n)},processAction:function(e,t,n){var r=t.inputState,i=r.getRepeat(),s=!!i,o=Et(n.actionArgs)||{};r.selectedCharacter&&(o.selectedCharacter=r.selectedCharacter),n.operator&&this.processOperator(e,t,n),n.motion&&this.processMotion(e,t,n),(n.motion||n.operator)&&this.evalInput(e,t),o.repeat=i||1,o.repeatIsExplicit=s,o.registerName=r.registerName,ut(e),t.lastMotion=null,n.isEdit&&this.recordLastEdit(t,r,n),yt[n.action](e,o,t)},processSearch:function(e,t,n){function a(r,i,s){nt.searchHistoryController.pushInput(r),nt.searchHistoryController.reset();try{An(e,r,i,s)}catch(o){Tn(e,"Invalid regex: "+r),ut(e);return}ht.processMotion(e,t,{type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:n.searchArgs.toJumplist}})}function f(t){e.scrollTo(u.left,u.top),a(t,!0,!0);var n=nt.macroModeState;n.isRecording&&Vn(n,t)}function l(t,n,i){var s=v.keyName(t),o;s=="Up"||s=="Down"?(o=s=="Up"?!0:!1,n=nt.searchHistoryController.nextMatch(n,o)||"",i(n)):s!="Left"&&s!="Right"&&s!="Ctrl"&&s!="Alt"&&s!="Shift"&&nt.searchHistoryController.reset();var a;try{a=An(e,n,!0,!0)}catch(t){}a?e.scrollIntoView(_n(e,!r,a),30):(Dn(e),e.scrollTo(u.left,u.top))}function c(t,n,r){var i=v.keyName(t);i=="Esc"||i=="Ctrl-C"||i=="Ctrl-["||i=="Backspace"&&n==""?(nt.searchHistoryController.pushInput(n),nt.searchHistoryController.reset(),An(e,o),Dn(e),e.scrollTo(u.left,u.top),v.e_stop(t),ut(e),r(),e.focus()):i=="Ctrl-U"&&(v.e_stop(t),r(""))}if(!e.getSearchCursor)return;var r=n.searchArgs.forward,i=n.searchArgs.wholeWordOnly;dn(e).setReversed(!r);var s=r?"/":"?",o=dn(e).getQuery(),u=e.getScrollInfo();switch(n.searchArgs.querySrc){case"prompt":var h=nt.macroModeState;if(h.isPlaying){var p=h.replaySearchQueries.shift();a(p,!0,!1)}else kn(e,{onClose:f,prefix:s,desc:Cn,onKeyUp:l,onKeyDown:c});break;case"wordUnderCursor":var d=Gt(e,!1,!0,!1,!0),m=!0;d||(d=Gt(e,!1,!0,!1,!1),m=!1);if(!d)return;var p=e.getLine(d.start.line).substring(d.start.ch,d.end.ch);m&&i?p="\\b"+p+"\\b":p=Bt(p),nt.jumpList.cachedCursor=e.getCursor(),e.setCursor(d.start),a(p,!0,!1)}},processEx:function(e,t,n){function r(t){nt.exCommandHistoryController.pushInput(t),nt.exCommandHistoryController.reset(),Fn.processCommand(e,t)}function i(t,n,r){var i=v.keyName(t),s;if(i=="Esc"||i=="Ctrl-C"||i=="Ctrl-["||i=="Backspace"&&n=="")nt.exCommandHistoryController.pushInput(n),nt.exCommandHistoryController.reset(),v.e_stop(t),ut(e),r(),e.focus();i=="Up"||i=="Down"?(s=i=="Up"?!0:!1,n=nt.exCommandHistoryController.nextMatch(n,s)||"",r(n)):i=="Ctrl-U"?(v.e_stop(t),r("")):i!="Left"&&i!="Right"&&i!="Ctrl"&&i!="Alt"&&i!="Shift"&&nt.exCommandHistoryController.reset()}n.type=="keyToEx"?Fn.processCommand(e,n.exArgs.input):t.visualMode?kn(e,{onClose:r,prefix:":",value:"'<,'>",onKeyDown:i}):kn(e,{onClose:r,prefix:":",onKeyDown:i})},evalInput:function(e,t){var n=t.inputState,r=n.motion,i=n.motionArgs||{},s=n.operator,o=n.operatorArgs||{},u=n.registerName,a=t.sel,f=Lt(t.visualMode?wt(e,a.head):e.getCursor("head")),l=Lt(t.visualMode?wt(e,a.anchor):e.getCursor("anchor")),c=Lt(f),h=Lt(l),p,d,v;s&&this.recordLastEdit(t,n),n.repeatOverride!==undefined?v=n.repeatOverride:v=n.getRepeat();if(v>0&&i.explicitRepeat)i.repeatIsExplicit=!0;else if(i.noRepeat||!i.explicitRepeat&&v===0)v=1,i.repeatIsExplicit=!1;n.selectedCharacter&&(i.selectedCharacter=o.selectedCharacter=n.selectedCharacter),i.repeat=v,ut(e);if(r){var m=pt[r](e,f,i,t);t.lastMotion=pt[r];if(!m)return;if(i.toJumplist){!s&&e.ace.curOp!=null&&(e.ace.curOp.command.scrollIntoView="center-animate");var g=nt.jumpList,y=g.cachedCursor;y?(Yt(e,y,m),delete g.cachedCursor):Yt(e,f,m)}m instanceof Array?(d=m[0],p=m[1]):p=m,p||(p=Lt(f));if(t.visualMode){if(!t.visualBlock||p.ch!==Infinity)p=wt(e,p,t.visualBlock);d&&(d=wt(e,d,!0)),d=d||h,a.anchor=d,a.head=p,Wt(e),an(e,t,"<",Ot(d,p)?d:p),an(e,t,">",Ot(d,p)?p:d)}else s||(p=wt(e,p),e.setCursor(p.line,p.ch))}if(s){if(o.lastSel){d=h;var b=o.lastSel,w=Math.abs(b.head.line-b.anchor.line),S=Math.abs(b.head.ch-b.anchor.ch);b.visualLine?p=E(h.line+w,h.ch):b.visualBlock?p=E(h.line+w,h.ch+S):b.head.line==b.anchor.line?p=E(h.line,h.ch+S):p=E(h.line+w,h.ch),t.visualMode=!0,t.visualLine=b.visualLine,t.visualBlock=b.visualBlock,a=t.sel={anchor:d,head:p},Wt(e)}else t.visualMode&&(o.lastSel={anchor:Lt(a.anchor),head:Lt(a.head),visualBlock:t.visualBlock,visualLine:t.visualLine});var x,T,N,C,k;if(t.visualMode){x=Mt(a.head,a.anchor),T=_t(a.head,a.anchor),N=t.visualLine||o.linewise,C=t.visualBlock?"block":N?"line":"char",k=Xt(e,{anchor:x,head:T},C);if(N){var L=k.ranges;if(C=="block")for(var A=0;Af&&i.line==f)return;var l=e.ace.session.getFoldLine(u);return l&&(n.forward?u>l.start.row&&(u=l.end.row+1):u=l.start.row),n.toFirstChar&&(s=Qt(e.getLine(u)),r.lastHPos=s),r.lastHSPos=e.charCoords(E(u,s),"div").left,E(u,s)},moveByDisplayLines:function(e,t,n,r){var i=t;switch(r.lastMotion){case this.moveByDisplayLines:case this.moveByScroll:case this.moveByLines:case this.moveToColumn:case this.moveToEol:break;default:r.lastHSPos=e.charCoords(i,"div").left}var s=n.repeat,o=e.findPosV(i,n.forward?s:-s,"line",r.lastHSPos);if(o.hitSide)if(n.forward)var u=e.charCoords(o,"div"),a={top:u.top+8,left:r.lastHSPos},o=e.coordsChar(a,"div");else{var f=e.charCoords(E(e.firstLine(),0),"div");f.left=r.lastHSPos,o=e.coordsChar(f,"div")}return r.lastHPos=o.ch,o},moveByPage:function(e,t,n){var r=t,i=n.repeat;return e.findPosV(r,n.forward?i:-i,"page")},moveByParagraph:function(e,t,n){var r=n.forward?1:-1;return ln(e,t,n.repeat,r)},moveByScroll:function(e,t,n,r){var i=e.getScrollInfo(),s=null,o=n.repeat;o||(o=i.clientHeight/(2*e.defaultTextHeight()));var u=e.charCoords(t,"local");n.repeat=o;var s=pt.moveByDisplayLines(e,t,n,r);if(!s)return null;var a=e.charCoords(s,"local");return e.scrollTo(null,i.top+a.top-u.top),s},moveByWords:function(e,t,n){return sn(e,t,n.repeat,!!n.forward,!!n.wordEnd,!!n.bigWord)},moveTillCharacter:function(e,t,n){var r=n.repeat,i=on(e,r,n.forward,n.selectedCharacter),s=n.forward?-1:1;return Zt(s,n),i?(i.ch+=s,i):null},moveToCharacter:function(e,t,n){var r=n.repeat;return Zt(0,n),on(e,r,n.forward,n.selectedCharacter)||t},moveToSymbol:function(e,t,n){var r=n.repeat;return nn(e,r,n.forward,n.selectedCharacter)||t},moveToColumn:function(e,t,n,r){var i=n.repeat;return r.lastHPos=i-1,r.lastHSPos=e.charCoords(t,"div").left,un(e,i)},moveToEol:function(e,t,n,r){var i=t;r.lastHPos=Infinity;var s=E(i.line+n.repeat-1,Infinity),o=e.clipPos(s);return o.ch--,r.lastHSPos=e.charCoords(o,"div").left,s},moveToFirstNonWhiteSpaceCharacter:function(e,t){var n=t;return E(n.line,Qt(e.getLine(n.line)))},moveToMatchedSymbol:function(e,t){var n=t,r=n.line,i=n.ch,s=e.getLine(r),o;do{o=s.charAt(i++);if(o&&z(o)){var u=e.getTokenTypeAt(E(r,i));if(u!=="string"&&u!=="comment")break}}while(o);if(o){var a=e.findMatchingBracket(E(r,i));return a.to}return n},moveToStartOfLine:function(e,t){return E(t.line,0)},moveToLineOrEdgeOfDocument:function(e,t,n){var r=n.forward?e.lastLine():e.firstLine();return n.repeatIsExplicit&&(r=n.repeat-e.getOption("firstLineNumber")),E(r,Qt(e.getLine(r)))},textObjectManipulation:function(e,t,n,r){var i={"(":")",")":"(","{":"}","}":"{","[":"]","]":"["},s={"'":!0,'"':!0},o=n.selectedCharacter;o=="b"?o="(":o=="B"&&(o="{");var u=!n.textObjectInner,a;if(i[o])a=cn(e,t,o,u);else if(s[o])a=hn(e,t,o,u);else if(o==="W")a=Gt(e,u,!0,!0);else if(o==="w")a=Gt(e,u,!0,!1);else{if(o!=="p")return null;a=ln(e,t,n.repeat,0,u),n.linewise=!0;if(r.visualMode)r.visualLine||(r.visualLine=!0);else{var f=r.inputState.operatorArgs;f&&(f.linewise=!0),a.end.line--}}return e.state.vim.visualMode?zt(e,a.start,a.end):[a.start,a.end]},repeatLastCharacterSearch:function(e,t,n){var r=nt.lastChararacterSearch,i=n.repeat,s=n.forward===r.forward,o=(r.increment?1:0)*(s?-1:1);e.moveH(-o,"char"),n.inclusive=s?!0:!1;var u=on(e,i,s,r.selectedCharacter);return u?(u.ch+=o,u):(e.moveH(o,"char"),t)}},mt={change:function(e,t,n){var r,i,s=e.state.vim;nt.macroModeState.lastInsertModeChanges.inVisualBlock=s.visualBlock;if(!s.visualMode){var o=n[0].anchor,u=n[0].head;i=e.getRange(o,u);var a=s.lastEditInputState||{};if(a.motion=="moveByWords"&&!V(i)){var f=/\s+$/.exec(i);f&&a.motionArgs&&a.motionArgs.forward&&(u=St(u,0,-f[0].length),i=i.slice(0,-f[0].length))}var l=new E(o.line-1,Number.MAX_VALUE),c=e.firstLine()==e.lastLine();u.line>e.lastLine()&&t.linewise&&!c?e.replaceRange("",l,u):e.replaceRange("",o,u),t.linewise&&(c||(e.setCursor(l),v.commands.newlineAndIndent(e)),o.ch=Number.MAX_VALUE),r=o}else{i=e.getSelection();var h=vt("",n.length);e.replaceSelections(h),r=Mt(n[0].head,n[0].anchor)}nt.registerController.pushText(t.registerName,"change",i,t.linewise,n.length>1),yt.enterInsertMode(e,{head:r},e.state.vim)},"delete":function(e,t,n){var r,i,s=e.state.vim;if(!s.visualBlock){var o=n[0].anchor,u=n[0].head;t.linewise&&u.line!=e.firstLine()&&o.line==e.lastLine()&&o.line==u.line-1&&(o.line==e.firstLine()?o.ch=0:o=E(o.line-1,Pt(e,o.line-1))),i=e.getRange(o,u),e.replaceRange("",o,u),r=o,t.linewise&&(r=pt.moveToFirstNonWhiteSpaceCharacter(e,o))}else{i=e.getSelection();var a=vt("",n.length);e.replaceSelections(a),r=n[0].anchor}return nt.registerController.pushText(t.registerName,"delete",i,t.linewise,s.visualBlock),wt(e,r)},indent:function(e,t,n){var r=e.state.vim,i=n[0].anchor.line,s=r.visualBlock?n[n.length-1].anchor.line:n[0].head.line,o=r.visualMode?t.repeat:1;t.linewise&&s--;for(var u=i;u<=s;u++)for(var a=0;af.top?(a.line+=(u-f.top)/i,a.line=Math.ceil(a.line),e.setCursor(a),f=e.charCoords(a,"local"),e.scrollTo(null,f.top)):e.scrollTo(null,u);else{var l=u+e.getScrollInfo().clientHeight;l=i.anchor.line?s=St(i.head,0,1):s=E(i.anchor.line,0);else if(r=="inplace"&&n.visualMode)return;e.setOption("keyMap","vim-insert"),e.setOption("disableInput",!1),t&&t.replace?(e.toggleOverwrite(!0),e.setOption("keyMap","vim-replace"),v.signal(e,"vim-mode-change",{mode:"replace"})):(e.setOption("keyMap","vim-insert"),v.signal(e,"vim-mode-change",{mode:"insert"})),nt.macroModeState.isPlaying||(e.on("change",$n),v.on(e.getInputField(),"keydown",Yn)),n.visualMode&&$t(e),It(e,s,o)},toggleVisualMode:function(e,t,n){var r=t.repeat,i=e.getCursor(),s;n.visualMode?n.visualLine^t.linewise||n.visualBlock^t.blockwise?(n.visualLine=!!t.linewise,n.visualBlock=!!t.blockwise,v.signal(e,"vim-mode-change",{mode:"visual",subMode:n.visualLine?"linewise":n.visualBlock?"blockwise":""}),Wt(e)):$t(e):(n.visualMode=!0,n.visualLine=!!t.linewise,n.visualBlock=!!t.blockwise,s=wt(e,E(i.line,i.ch+r-1),!0),n.sel={anchor:i,head:s},v.signal(e,"vim-mode-change",{mode:"visual",subMode:n.visualLine?"linewise":n.visualBlock?"blockwise":""}),Wt(e),an(e,n,"<",Mt(i,s)),an(e,n,">",_t(i,s)))},reselectLastSelection:function(e,t,n){var r=n.lastSelection;n.visualMode&&Ut(e,n);if(r){var i=r.anchorMark.find(),s=r.headMark.find();if(!i||!s)return;n.sel={anchor:i,head:s},n.visualMode=!0,n.visualLine=r.visualLine,n.visualBlock=r.visualBlock,Wt(e),an(e,n,"<",Mt(i,s)),an(e,n,">",_t(i,s)),v.signal(e,"vim-mode-change",{mode:"visual",subMode:n.visualLine?"linewise":n.visualBlock?"blockwise":""})}},joinLines:function(e,t,n){var r,i;if(n.visualMode){r=e.getCursor("anchor"),i=e.getCursor("head");if(Ot(i,r)){var s=i;i=r,r=s}i.ch=Pt(e,i.line)-1}else{var o=Math.max(t.repeat,2);r=e.getCursor(),i=wt(e,E(r.line+o-1,Infinity))}var u=0;for(var a=r.line;a1)var s=Array(t.repeat+1).join(s);var p=i.linewise,d=i.blockwise;if(p&&!d)n.visualMode?s=n.visualLine?s.slice(0,-1):"\n"+s.slice(0,s.length-1)+"\n":t.after?(s="\n"+s.slice(0,s.length-1),r.ch=Pt(e,r.line)):r.ch=0;else{if(d){s=s.split("\n");for(var v=0;ve.lastLine()&&e.replaceRange("\n",E(C,0));var k=Pt(e,C);ka.length&&(s=a.length),o=E(i.line,s)}if(r=="\n")n.visualMode||e.replaceRange("",i,o),(v.commands.newlineAndIndentContinueComment||v.commands.newlineAndIndent)(e);else{var f=e.getRange(i,o);f=f.replace(/[^\n]/g,r);if(n.visualBlock){var l=(new Array(e.getOption("tabSize")+1)).join(" ");f=e.getSelection(),f=f.replace(/\t/g,l).replace(/[^\n]/g,r).split("\n"),e.replaceSelections(f)}else e.replaceRange(f,i,o);n.visualMode?(i=Ot(u[0].anchor,u[0].head)?u[0].anchor:u[0].head,e.setCursor(i),$t(e,!1)):e.setCursor(St(o,0,-1))}},incrementNumberToken:function(e,t){var n=e.getCursor(),r=e.getLine(n.line),i=/-?\d+/g,s,o,u,a,f;while((s=i.exec(r))!==null){f=s[0],o=s.index,u=o+f.length;if(n.ch=1)return!0}else e.nextCh===e.reverseSymb&&e.depth--;return!1}},section:{init:function(e){e.curMoveThrough=!0,e.symb=(e.forward?"]":"[")===e.symb?"{":"}"},isComplete:function(e){return e.index===0&&e.nextCh===e.symb}},comment:{isComplete:function(e){var t=e.lastCh==="*"&&e.nextCh==="/";return e.lastCh=e.nextCh,t}},method:{init:function(e){e.symb=e.symb==="m"?"{":"}",e.reverseSymb=e.symb==="{"?"}":"{"},isComplete:function(e){return e.nextCh===e.symb?!0:!1}},preprocess:{init:function(e){e.index=0},isComplete:function(e){if(e.nextCh==="#"){var t=e.lineText.match(/#(\w+)/)[1];if(t==="endif"){if(e.forward&&e.depth===0)return!0;e.depth++}else if(t==="if"){if(!e.forward&&e.depth===0)return!0;e.depth--}if(t==="else"&&e.depth===0)return!0}return!1}}};K("pcre",!0,"boolean"),pn.prototype={getQuery:function(){return nt.query},setQuery:function(e){nt.query=e},getOverlay:function(){return this.searchOverlay},setOverlay:function(e){this.searchOverlay=e},isReversed:function(){return nt.isReversed},setReversed:function(e){nt.isReversed=e},getScrollbarAnnotate:function(){return this.annotate},setScrollbarAnnotate:function(e){this.annotate=e}};var bn={"\\n":"\n","\\r":"\r","\\t":" "},En={"\\/":"/","\\\\":"\\","\\n":"\n","\\r":"\r","\\t":" "},Cn="(Javascript regexp)",Bn=function(){this.buildCommandMap_()};Bn.prototype={processCommand:function(e,t,n){var r=this;e.operation(function(){e.curOp.isVimOp=!0,r._processCommand(e,t,n)})},_processCommand:function(e,t,n){var r=e.state.vim,i=nt.registerController.getRegister(":"),s=i.toString();r.visualMode&&$t(e);var o=new v.StringStream(t);i.setText(t);var u=n||{};u.input=t;try{this.parseInput_(e,o,u)}catch(a){throw Tn(e,a),a}var f,l;if(!u.commandName)u.line!==undefined&&(l="move");else{f=this.matchCommand_(u.commandName);if(f){l=f.name,f.excludeFromCommandHistory&&i.setText(s),this.parseCommandArgs_(o,u,f);if(f.type=="exToKey"){for(var c=0;c0;t--){var n=e.substring(0,t);if(this.commandMap_[n]){var r=this.commandMap_[n];if(r.name.indexOf(e)===0)return r}}return null},buildCommandMap_:function(){this.commandMap_={};for(var e=0;e ";if(!n)for(var s in r){var o=r[s].toString();o.length&&(i+='"'+s+" "+o+" ")}else{var s;n=n.join("");for(var u=0;u"}}Tn(e,i)},sort:function(e,t){function o(){if(t.argString){var e=new v.StringStream(t.argString);e.eat("!")&&(n=!0);if(e.eol())return;if(!e.eatSpace())return"Invalid arguments";var o=e.match(/[a-z]+/);if(o){o=o[0],r=o.indexOf("i")!=-1,i=o.indexOf("u")!=-1;var u=o.indexOf("d")!=-1&&1,a=o.indexOf("x")!=-1&&1,f=o.indexOf("o")!=-1&&1;if(u+a+f>1)return"Invalid arguments";s=u&&"decimal"||a&&"hex"||f&&"octal"}if(e.match(/\/.*\//))return"patterns not supported"}}function b(e,t){if(n){var i;i=e,e=t,t=i}r&&(e=e.toLowerCase(),t=t.toLowerCase());var o=s&&p.exec(e),u=s&&p.exec(t);return o?(o=parseInt((o[1]+o[2]).toLowerCase(),d),u=parseInt((u[1]+u[2]).toLowerCase(),d),o-u):e")}if(!u){Tn(e,c);return}var d=0,v=function(){if(d=f){Tn(e,"Invalid argument: "+t.argString.substring(i));return}for(var l=0;l<=f-a;l++){var c=String.fromCharCode(a+l);delete n.marks[c]}}else delete n.marks[s]}}},Fn=new Bn;v.keyMap.vim={attach:C,detach:N,call:k},K("insertModeEscKeysTimeout",200,"number"),v.keyMap["vim-insert"]={"Ctrl-N":"autocomplete","Ctrl-P":"autocomplete",Enter:function(e){var t=v.commands.newlineAndIndentContinueComment||v.commands.newlineAndIndent;t(e)},fallthrough:["default"],attach:C,detach:N,call:k},v.keyMap["vim-replace"]={Backspace:"goCharLeft",fallthrough:["vim-insert"],attach:C,detach:N,call:k},rt(),v.Vim=S(),S=v.Vim;var tr={"return":"CR",backspace:"BS","delete":"Del",esc:"Esc",left:"Left",right:"Right",up:"Up",down:"Down",space:"Space",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",enter:"CR"},rr=S.handleKey.bind(S);S.handleKey=function(e,t,n){return e.operation(function(){return rr(e,t,n)},!0)},t.CodeMirror=v;var or=S.maybeInitVimState_;t.handler={$id:"ace/keyboard/vim",drawCursor:function(e,t,n,r,s){var o=this.state.vim||{},u=n.characterWidth,a=n.lineHeight,f=t.top,l=t.left;if(!o.insertMode){var c=r.cursor?i.comparePoints(r.cursor,r.start)<=0:s.selection.isBackwards()||s.selection.isEmpty();!c&&l>u&&(l-=u)}!o.insertMode&&o.status&&(a/=2,f+=a),e.left=l+"px",e.top=f+"px",e.width=u+"px",e.height=a+"px"},handleKeyboard:function(e,t,n,r,i){var s=e.editor,o=s.state.cm,u=or(o);if(r==-1)return;if(n=="c"&&t==1){if(!c.isMac&&s.getCopyText())return s.once("copy",function(){s.selection.clearSelection()}),{command:"null",passEvent:!0}}else u.insertMode||c.isMac&&this.handleMacRepeat(e,t,n)&&(t=-1,n=e.inputChar);if(t==-1||t&1||t===0&&n.length>1){var a=u.insertMode,f=nr(t,n,i||{});u.status==null&&(u.status="");var l=sr(o,f,"user");u=or(o),l&&u.status!=null?u.status+=f:u.status==null&&(u.status=""),o._signal("changeStatus");if(!l&&(t!=-1||a))return;return{command:"null",passEvent:!l}}},attach:function(e){e.state||(e.state={});var t=new v(e);e.state.cm=t,e.$vimModeHandler=this,v.keyMap.vim.attach(t),or(t).status=null,t.on("vim-command-done",function(){if(t.virtualSelectionMode())return;or(t).status=null,t.ace._signal("changeStatus"),t.ace.session.markUndoGroup()}),t.on("changeStatus",function(){t.ace.renderer.updateCursor(),t.ace._signal("changeStatus")}),t.on("vim-mode-change",function(){if(t.virtualSelectionMode())return;t.ace.renderer.setStyle("normal-mode",!or(t).insertMode),t._signal("changeStatus")}),t.ace.renderer.setStyle("normal-mode",!or(t).insertMode),e.renderer.$cursorLayer.drawCursor=this.drawCursor.bind(t),this.updateMacCompositionHandlers(e,!0)},detach:function(e){var t=e.state.cm;v.keyMap.vim.detach(t),t.destroy(),e.state.cm=null,e.$vimModeHandler=null,e.renderer.$cursorLayer.drawCursor=null,e.renderer.setStyle("normal-mode",!1),this.updateMacCompositionHandlers(e,!1)},getStatusText:function(e){var t=e.state.cm,n=or(t);if(n.insertMode)return"INSERT";var r="";return n.visualMode&&(r+="VISUAL",n.visualLine&&(r+=" LINE"),n.visualBlock&&(r+=" BLOCK")),n.status&&(r+=(r?" ":"")+n.status),r},handleMacRepeat:function(e,t,n){if(t==-1)e.inputChar=n,e.lastEvent="input";else if(e.inputChar&&e.$lastHash==t&&e.$lastKey==n){if(e.lastEvent=="input")e.lastEvent="input1";else if(e.lastEvent=="input1")return!0}else e.$lastHash=t,e.$lastKey=n,e.lastEvent="keypress"},updateMacCompositionHandlers:function(e,t){var n=function(t){var n=e.state.cm,r=or(n);if(!r.insertMode){var i=this.textInput.getElement();i.blur(),i.focus(),i.value=t}else this.onCompositionUpdateOrig(t)},r=function(t){var n=e.state.cm,r=or(n);r.insertMode||this.onCompositionStartOrig(t)};t?e.onCompositionUpdateOrig||(e.onCompositionUpdateOrig=e.onCompositionUpdate,e.onCompositionUpdate=n,e.onCompositionStartOrig=e.onCompositionStart,e.onCompositionStart=r):e.onCompositionUpdateOrig&&(e.onCompositionUpdate=e.onCompositionUpdateOrig,e.onCompositionUpdateOrig=null,e.onCompositionStart=e.onCompositionStartOrig,e.onCompositionStartOrig=null)}};var ur={getText:function(e,t){return(Math.abs(e.selection.lead.row-t)||t+1+(t<9?"\u00b7":""))+""},getWidth:function(e,t,n){return e.getLength().toString().length*n.characterWidth},update:function(e,t){t.renderer.$loop.schedule(t.renderer.CHANGE_GUTTER)},attach:function(e){e.renderer.$gutterLayer.$renderer=this,e.on("changeSelection",this.update)},detach:function(e){e.renderer.$gutterLayer.$renderer=null,e.off("changeSelection",this.update)}};S.defineOption({name:"wrap",set:function(e,t){t&&t.ace.setOption("wrap",e)},type:"boolean"},!1),S.defineEx("write","w",function(){console.log(":write is not implemented")}),b.push({keys:"zc",type:"action",action:"fold",actionArgs:{open:!1}},{keys:"zC",type:"action",action:"fold",actionArgs:{open:!1,all:!0}},{keys:"zo",type:"action",action:"fold",actionArgs:{open:!0}},{keys:"zO",type:"action",action:"fold",actionArgs:{open:!0,all:!0}},{keys:"za",type:"action",action:"fold",actionArgs:{toggle:!0}},{keys:"zA",type:"action",action:"fold",actionArgs:{toggle:!0,all:!0}},{keys:"zf",type:"action",action:"fold",actionArgs:{open:!0,all:!0}},{keys:"zd",type:"action",action:"fold",actionArgs:{open:!0,all:!0}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"addCursorAbove"}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"addCursorBelow"}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"addCursorAboveSkipCurrent"}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"addCursorBelowSkipCurrent"}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"selectMoreBefore"}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"selectMoreAfter"}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"selectNextBefore"}},{keys:"",type:"action",action:"aceCommand",actionArgs:{name:"selectNextAfter"}}),yt.aceCommand=function(e,t,n){e.vimCmd=t,e.ace.inVirtualSelectionMode?e.ace.on("beforeEndOperation",ar):ar(null,e.ace)},yt.fold=function(e,t,n){e.ace.execCommand(["toggleFoldWidget","toggleFoldWidget","foldOther","unfoldall"][(t.all?2:0)+(t.open?1:0)])},t.handler.defaultKeymap=b,t.handler.actions=yt,t.Vim=S,S.map("Y","yy","normal")})
\ No newline at end of file
diff --git a/library/ace/mode-abap.js b/library/ace/mode-abap.js
new file mode 100644
index 000000000..f79f2983e
--- /dev/null
+++ b/library/ace/mode-abap.js
@@ -0,0 +1 @@
+ace.define("ace/mode/abap_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e=this.createKeywordMapper({"variable.language":"this",keyword:"ADD ALIAS ALIASES ASCENDING ASSERT ASSIGN ASSIGNING AT BACK CALL CASE CATCH CHECK CLASS CLEAR CLOSE CNT COLLECT COMMIT COMMUNICATION COMPUTE CONCATENATE CONDENSE CONSTANTS CONTINUE CONTROLS CONVERT CREATE CURRENCY DATA DEFINE DEFINITION DEFERRED DELETE DESCENDING DESCRIBE DETAIL DIVIDE DO ELSE ELSEIF ENDAT ENDCASE ENDCLASS ENDDO ENDEXEC ENDFORM ENDFUNCTION ENDIF ENDIFEND ENDINTERFACE ENDLOOP ENDMETHOD ENDMODULE ENDON ENDPROVIDE ENDSELECT ENDTRY ENDWHILE EVENT EVENTS EXEC EXIT EXPORT EXPORTING EXTRACT FETCH FIELDS FORM FORMAT FREE FROM FUNCTION GENERATE GET HIDE IF IMPORT IMPORTING INDEX INFOTYPES INITIALIZATION INTERFACE INTERFACES INPUT INSERT IMPLEMENTATION LEAVE LIKE LINE LOAD LOCAL LOOP MESSAGE METHOD METHODS MODIFY MODULE MOVE MULTIPLY ON OVERLAY OPTIONAL OTHERS PACK PARAMETERS PERFORM POSITION PROGRAM PROVIDE PUT RAISE RANGES READ RECEIVE RECEIVING REDEFINITION REFERENCE REFRESH REJECT REPLACE REPORT RESERVE RESTORE RETURN RETURNING ROLLBACK SCAN SCROLL SEARCH SELECT SET SHIFT SKIP SORT SORTED SPLIT STANDARD STATICS STEP STOP SUBMIT SUBTRACT SUM SUMMARY SUPPRESS TABLES TIMES TRANSFER TRANSLATE TRY TYPE TYPES UNASSIGN ULINE UNPACK UPDATE WHEN WHILE WINDOW WRITE OCCURS STRUCTURE OBJECT PROPERTY CASTING APPEND RAISING VALUE COLOR CHANGING EXCEPTION EXCEPTIONS DEFAULT CHECKBOX COMMENT ID NUMBER FOR TITLE OUTPUT WITH EXIT USING INTO WHERE GROUP BY HAVING ORDER BY SINGLE APPENDING CORRESPONDING FIELDS OF TABLE LEFT RIGHT OUTER INNER JOIN AS CLIENT SPECIFIED BYPASSING BUFFER UP TO ROWS CONNECTING EQ NE LT LE GT GE NOT AND OR XOR IN LIKE BETWEEN","constant.language":"TRUE FALSE NULL SPACE","support.type":"c n i p f d t x string xstring decfloat16 decfloat34","keyword.operator":"abs sign ceil floor trunc frac acos asin atan cos sin tan abapOperator cosh sinh tanh exp log log10 sqrt strlen xstrlen charlen numofchar dbmaxlen lines"},"text",!0," "),t="WITH\\W+(?:HEADER\\W+LINE|FRAME|KEY)|NO\\W+STANDARD\\W+PAGE\\W+HEADING|EXIT\\W+FROM\\W+STEP\\W+LOOP|BEGIN\\W+OF\\W+(?:BLOCK|LINE)|BEGIN\\W+OF|END\\W+OF\\W+(?:BLOCK|LINE)|END\\W+OF|NO\\W+INTERVALS|RESPECTING\\W+BLANKS|SEPARATED\\W+BY|USING\\W+(?:EDIT\\W+MASK)|WHERE\\W+(?:LINE)|RADIOBUTTON\\W+GROUP|REF\\W+TO|(?:PUBLIC|PRIVATE|PROTECTED)(?:\\W+SECTION)?|DELETING\\W+(?:TRAILING|LEADING)(?:ALL\\W+OCCURRENCES)|(?:FIRST|LAST)\\W+OCCURRENCE|INHERITING\\W+FROM|LINE-COUNT|ADD-CORRESPONDING|AUTHORITY-CHECK|BREAK-POINT|CLASS-DATA|CLASS-METHODS|CLASS-METHOD|DIVIDE-CORRESPONDING|EDITOR-CALL|END-OF-DEFINITION|END-OF-PAGE|END-OF-SELECTION|FIELD-GROUPS|FIELD-SYMBOLS|FUNCTION-POOL|MOVE-CORRESPONDING|MULTIPLY-CORRESPONDING|NEW-LINE|NEW-PAGE|NEW-SECTION|PRINT-CONTROL|RP-PROVIDE-FROM-LAST|SELECT-OPTIONS|SELECTION-SCREEN|START-OF-SELECTION|SUBTRACT-CORRESPONDING|SYNTAX-CHECK|SYNTAX-TRACE|TOP-OF-PAGE|TYPE-POOL|TYPE-POOLS|LINE-SIZE|LINE-COUNT|MESSAGE-ID|DISPLAY-MODE|READ(?:-ONLY)?|IS\\W+(?:NOT\\W+)?(?:ASSIGNED|BOUND|INITIAL|SUPPLIED)";this.$rules={start:[{token:"string",regex:"`",next:"string"},{token:"string",regex:"'",next:"qstring"},{token:"doc.comment",regex:/^\*.+/},{token:"comment",regex:/".+$/},{token:"invalid",regex:"\\.{2,}"},{token:"keyword.operator",regex:/\W[\-+\%=<>*]\W|\*\*|[~:,\.&$]|->*?|=>/},{token:"paren.lparen",regex:"[\\[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"constant.numeric",regex:"[+-]?\\d+\\b"},{token:"variable.parameter",regex:/sy|pa?\d\d\d\d\|t\d\d\d\.|innnn/},{token:"keyword",regex:t},{token:"variable.parameter",regex:/\w+-\w+(?:-\w+)*/},{token:e,regex:"\\b\\w+\\b"},{caseInsensitive:!0}],qstring:[{token:"constant.language.escape",regex:"''"},{token:"string",regex:"'",next:"start"},{defaultToken:"string"}],string:[{token:"constant.language.escape",regex:"``"},{token:"string",regex:"`",next:"start"},{defaultToken:"string"}]}};r.inherits(s,i),t.AbapHighlightRules=s}),ace.define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++nl){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u<0-9]*)",comment:"Notes"},{token:"zupfnoter.jumptarget.string.quoted",regex:'[\\"!]\\^\\:.*?[\\"!]',comment:"Zupfnoter jumptarget"},{token:"zupfnoter.goto.string.quoted",regex:'[\\"!]\\^\\@.*?[\\"!]',comment:"Zupfnoter goto"},{token:"zupfnoter.annotation.string.quoted",regex:'[\\"!]\\^\\!.*?[\\"!]',comment:"Zupfnoter annoation"},{token:"zupfnoter.annotationref.string.quoted",regex:'[\\"!]\\^\\#.*?[\\"!]',comment:"Zupfnoter annotation reference"},{token:"chordname.string.quoted",regex:'[\\"!]\\^.*?[\\"!]',comment:"abc chord"},{token:"string.quoted",regex:'[\\"!].*?[\\"!]',comment:"abc annotation"}]},this.normalizeRules()};s.metaData={fileTypes:["abc"],name:"ABC",scopeName:"text.abcnotation"},r.inherits(s,i),t.ABCHighlightRules=s}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),ace.define("ace/mode/abc",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/abc_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./abc_highlight_rules").ABCHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o};r.inherits(u,i),function(){this.$id="ace/mode/abc"}.call(u.prototype),t.Mode=u})
\ No newline at end of file
diff --git a/library/ace/mode-actionscript.js b/library/ace/mode-actionscript.js
new file mode 100644
index 000000000..9ae91574f
--- /dev/null
+++ b/library/ace/mode-actionscript.js
@@ -0,0 +1 @@
+ace.define("ace/mode/actionscript_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"support.class.actionscript.2",regex:"\\b(?:R(?:ecordset|DBMSResolver|adioButton(?:Group)?)|X(?:ML(?:Socket|Node|Connector)?|UpdateResolverDataHolder)|M(?:M(?:Save|Execute)|icrophoneMicrophone|o(?:use|vieClip(?:Loader)?)|e(?:nu(?:Bar)?|dia(?:Controller|Display|Playback))|ath)|B(?:yName|inding|utton)|S(?:haredObject|ystem|crollPane|t(?:yleSheet|age|ream)|ound|e(?:ndEvent|rviceObject)|OAPCall|lide)|N(?:umericStepper|et(?:stream|S(?:tream|ervices)|Connection|Debug(?:Config)?))|C(?:heckBox|o(?:ntextMenu(?:Item)?|okie|lor|m(?:ponentMixins|boBox))|ustomActions|lient|amera)|T(?:ypedValue|ext(?:Snapshot|Input|F(?:ield|ormat)|Area)|ree|AB)|Object|D(?:ownload|elta(?:Item|Packet)?|at(?:e(?:Chooser|Field)?|a(?:G(?:lue|rid)|Set|Type)))|U(?:RL|TC|IScrollBar)|P(?:opUpManager|endingCall|r(?:intJob|o(?:duct|gressBar)))|E(?:ndPoint|rror)|Video|Key|F(?:RadioButton|GridColumn|MessageBox|BarChart|S(?:croll(?:Bar|Pane)|tyleFormat|plitView)|orm|C(?:heckbox|omboBox|alendar)|unction|T(?:icker|ooltip(?:Lite)?|ree(?:Node)?)|IconButton|D(?:ataGrid|raggablePane)|P(?:ieChart|ushButton|ro(?:gressBar|mptBox))|L(?:i(?:stBox|neChart)|oadingBox)|AdvancedMessageBox)|W(?:indow|SDLURL|ebService(?:Connector)?)|L(?:ist|o(?:calConnection|ad(?:er|Vars)|g)|a(?:unch|bel))|A(?:sBroadcaster|cc(?:ordion|essibility)|S(?:Set(?:Native|PropFlags)|N(?:ew|ative)|C(?:onstructor|lamp(?:2)?)|InstanceOf)|pplication|lert|rray))\\b"},{token:"support.function.actionscript.2",regex:"\\b(?:s(?:h(?:ift|ow(?:GridLines|Menu|Border|Settings|Headers|ColumnHeaders|Today|Preferences)?|ad(?:ow|ePane))|c(?:hema|ale(?:X|Mode|Y|Content)|r(?:oll(?:Track|Drag)?|een(?:Resolution|Color|DPI)))|t(?:yleSheet|op(?:Drag|A(?:nimation|llSounds|gent))?|epSize|a(?:tus|rt(?:Drag|A(?:nimation|gent))?))|i(?:n|ze|lence(?:TimeOut|Level))|o(?:ngname|urce|rt(?:Items(?:By)?|On(?:HeaderRelease)?|able(?:Columns)?)?)|u(?:ppressInvalidCalls|bstr(?:ing)?)|p(?:li(?:ce|t)|aceCol(?:umnsEqually|lumnsEqually))|e(?:nd(?:DefaultPushButtonEvent|AndLoad)?|curity|t(?:R(?:GB|o(?:otNode|w(?:Height|Count))|esizable(?:Columns)?|a(?:nge|te))|G(?:ain|roupName)|X(?:AxisTitle)?|M(?:i(?:n(?:imum|utes)|lliseconds)|o(?:nth(?:Names)?|tionLevel|de)|ultilineMode|e(?:ssage|nu(?:ItemEnabled(?:At)?|EnabledAt)|dia)|a(?:sk|ximum))|B(?:u(?:tton(?:s|Width)|fferTime)|a(?:seTabIndex|ndwidthLimit|ckground))|S(?:howAsDisabled|croll(?:ing|Speed|Content|Target|P(?:osition|roperties)|barState|Location)|t(?:yle(?:Property)?|opOnFocus|at(?:us|e))|i(?:ze|lenceLevel)|ort(?:able(?:Columns)?|Function)|p(?:litterBarPosition|acing)|e(?:conds|lect(?:Multiple|ion(?:Required|Type)?|Style|Color|ed(?:Node(?:s)?|Cell|I(?:nd(?:ices|ex)|tem(?:s)?))?|able))|kin|m(?:oothness|allScroll))|H(?:ighlight(?:s|Color)|Scroll|o(?:urs|rizontal)|eader(?:Symbol|Height|Text|Property|Format|Width|Location)?|as(?:Shader|CloseBox))|Y(?:ear|AxisTitle)?|N(?:ode(?:Properties|ExpansionHandler)|ewTextFormat)|C(?:h(?:ildNodes|a(?:ngeHandler|rt(?:Title|EventHandler)))|o(?:ntent(?:Size)?|okie|lumns)|ell(?:Symbol|Data)|l(?:i(?:ckHandler|pboard)|oseHandler)|redentials)|T(?:ype(?:dVaule)?|i(?:tle(?:barHeight)?|p(?:Target|Offset)?|me(?:out(?:Handler)?)?)|oggle|extFormat|ransform)|I(?:s(?:Branch|Open)|n(?:terval|putProperty)|con(?:SymbolName)?|te(?:rator|m(?:ByKey|Symbol)))|Orientation|D(?:i(?:splay(?:Range|Graphics|Mode|Clip|Text|edMonth)|rection)|uration|e(?:pth(?:Below|To|Above)|fault(?:GatewayURL|Mappings|NodeIconSymbolName)|l(?:iveryMode|ay)|bug(?:ID)?)|a(?:yOfWeekNames|t(?:e(?:Filter)?|a(?:Mapping(?:s)?|Item(?:Text|Property|Format)|Provider|All(?:Height|Property|Format|Width))?))|ra(?:wConnectors|gContent))|U(?:se(?:Shadow|HandCursor|EchoSuppression|rInput|Fade)|TC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear))|P(?:osition|ercentComplete|an(?:e(?:M(?:inimumSize|aximumSize)|Size|Title))?|ro(?:pert(?:y(?:Data)?|iesAt)|gress))|E(?:nabled|dit(?:Handler|able)|xpand(?:NodeTrigger|erSymbolName))|V(?:Scroll|olume|alue(?:Source)?)|KeyFrameInterval|Quality|F(?:i(?:eld|rst(?:DayOfWeek|VisibleNode))|ocus|ullYear|ps|ade(?:InLength|OutLength)|rame(?:Color|Width))|Width|L(?:ine(?:Color|Weight)|o(?:opback|adTarget)|a(?:rgeScroll|bel(?:Source|Placement)?))|A(?:s(?:Boolean|String|Number)|n(?:yTypedValue|imation)|ctiv(?:e(?:State(?:Handler)?|Handler)|ateHandler)|utoH(?:ideScrollBar|eight)))?|paratorBefore|ek|lect(?:ion(?:Disabled|Unfocused)?|ed(?:Node(?:s)?|Child|I(?:nd(?:ices|ex)|tem(?:s)?)|Dat(?:e|a))?|able(?:Ranges)?)|rver(?:String)?)|kip|qrt|wapDepths|lice|aveToSharedObj|moothing)|h(?:scroll(?:Policy)?|tml(?:Text)?|i(?:t(?:Test(?:TextNearPos)?|Area)|de(?:BuiltInItems|Child)?|ghlight(?:2D|3D)?)|orizontal|e(?:ight|ader(?:Re(?:nderer|lease)|Height|Text))|P(?:osition|ageScrollSize)|a(?:s(?:childNodes|MP3|S(?:creen(?:Broadcast|Playback)|treaming(?:Video|Audio)|ort)|Next|OwnProperty|Pr(?:inting|evious)|EmbeddedVideo|VideoEncoder|A(?:ccesibility|udio(?:Encoder)?))|ndlerName)|LineScrollSize)|ye(?:sLabel|ar)|n(?:o(?:t|de(?:Name|Close|Type|Open|Value)|Label)|u(?:llValue|mChild(?:S(?:creens|lides)|ren|Forms))|e(?:w(?:Item|line|Value|LocationDialog)|xt(?:S(?:cene|ibling|lide)|TabIndex|Value|Frame)?)?|ame(?:s)?)|c(?:h(?:ildNodes|eck|a(?:nge(?:sPending)?|r(?:CodeAt|At))|r)|o(?:s|n(?:st(?:ant|ructor)|nect|c(?:urrency|at)|t(?:ent(?:Type|Path)?|ains|rol(?:Placement|lerPolicy))|denseWhite|version)|py|l(?:or|umn(?:Stretch|Name(?:s)?|Count))|m(?:p(?:onent|lete)|ment))|u(?:stomItems|ePoint(?:s)?|r(?:veTo|Value|rent(?:Slide|ChildSlide|Item|F(?:ocused(?:S(?:creen|lide)|Form)|ps))))|e(?:il|ll(?:Renderer|Press|Edit|Focus(?:In|Out)))|l(?:i(?:ck|ents)|o(?:se(?:Button|Pane)?|ne(?:Node)?)|ear(?:S(?:haredObjects|treams)|Timeout|Interval)?)|a(?:ncelLabel|tch|p(?:tion|abilities)|l(?:cFields|l(?:e(?:e|r))?))|reate(?:GatewayConnection|Menu|Se(?:rver|gment)|C(?:hild(?:AtDepth)?|l(?:ient|ass(?:ChildAtDepth|Object(?:AtDepth)?))|all)|Text(?:Node|Field)|Item|Object(?:AtDepth)?|PopUp|E(?:lement|mptyMovieClip)))|t(?:h(?:is|row)|ype(?:of|Name)?|i(?:tle(?:StyleDeclaration)?|me(?:out)?)|o(?:talTime|String|olTipText|p|UpperCase|ggle(?:HighQuality)?|Lo(?:caleString|werCase))|e(?:st|llTarget|xt(?:RightMargin|Bold|S(?:ize|elected)|Height|Color|I(?:ndent|talic)|Disabled|Underline|F(?:ield|ont)|Width|LeftMargin|Align)?)|a(?:n|rget(?:Path)?|b(?:Stops|Children|Index|Enabled|leName))|r(?:y|igger|ac(?:e|k(?:AsMenu)?)))|i(?:s(?:Running|Branch|NaN|Con(?:soleOpen|nected)|Toggled|Installed|Open|D(?:own|ebugger)|P(?:urchased|ro(?:totypeOf|pertyEnumerable))|Empty|F(?:inite|ullyPopulated)|Local|Active)|n(?:s(?:tall|ertBefore)|cludeDeltaPacketInfo|t|it(?:ialize|Component|Pod|A(?:pplication|gent))?|de(?:nt|terminate|x(?:InParent(?:Slide|Form)?|Of)?)|put|validate|finity|LocalInternetCache)?|con(?:F(?:ield|unction))?|t(?:e(?:ratorScrolled|m(?:s|RollO(?:ut|ver)|ClassName))|alic)|d3|p|fFrameLoaded|gnore(?:Case|White))|o(?:s|n(?:R(?:ollO(?:ut|ver)|e(?:s(?:ize|ult)|l(?:ease(?:Outside)?|aseOutside)))|XML|Mouse(?:Move|Down|Up|Wheel)|S(?:ync|croller|tatus|oundComplete|e(?:tFocus|lect(?:edItem)?))|N(?:oticeEvent|etworkChange)|C(?:hanged|onnect|l(?:ipEvent|ose))|ID3|D(?:isconnect|eactivate|ata|ragO(?:ut|ver))|Un(?:install|load)|P(?:aymentResult|ress)|EnterFrame|K(?:illFocus|ey(?:Down|Up))|Fault|Lo(?:ad|g)|A(?:ctiv(?:ity|ate)|ppSt(?:op|art)))?|pe(?:n|ration)|verLayChildren|kLabel|ldValue|r(?:d)?)|d(?:i(?:s(?:connect|play(?:Normal|ed(?:Month|Year)|Full)|able(?:Shader|d(?:Ranges|Days)|CloseBox|Events))|rection)|o(?:cTypeDecl|tall|Decoding|main|LazyDecoding)|u(?:plicateMovieClip|ration)|e(?:stroy(?:ChildAt|Object)|code|fault(?:PushButton(?:Enabled)?|KeydownHandler)?|l(?:ta(?:Packet(?:Changed)?)?|ete(?:PopUp|All)?)|blocking)|a(?:shBoardSave|yNames|ta(?:Provider)?|rkshadow)|r(?:opdown(?:Width)?|a(?:w|gO(?:ut|ver))))|u(?:se(?:Sort|HandCursor|Codepage|EchoSuppression)|n(?:shift|install|derline|escape|format|watch|lo(?:ck|ad(?:Movie(?:Num)?)?))|pdate(?:Results|Mode|I(?:nputProperties|tem(?:ByIndex)?)|P(?:acket|roperties)|View|AfterEvent)|rl)|join|p(?:ixelAspectRatio|o(?:sition|p|w)|u(?:sh|rge|blish)|ercen(?:tComplete|Loaded)|lay(?:head(?:Change|Time)|ing|Hidden|erType)?|a(?:ssword|use|r(?:se(?:XML|CSS|Int|Float)|ent(?:Node|Is(?:S(?:creen|lide)|Form))|ams))|r(?:int(?:Num|AsBitmap(?:Num)?)?|o(?:to(?:type)?|pert(?:y|ies)|gress)|e(?:ss|v(?:ious(?:S(?:ibling|lide)|Value)?|Scene|Frame)|ferred(?:Height|Width))))|e(?:scape|n(?:code(?:r)?|ter(?:Frame)?|dFill|able(?:Shader|d|CloseBox|Events))|dit(?:able|Field|LocationDialog)|v(?:ent|al(?:uate)?)|q|x(?:tended|p|ec(?:ute)?|actSettings)|m(?:phasized(?:StyleDeclaration)?|bedFonts))|v(?:i(?:sible|ewPod)|ScrollPolicy|o(?:id|lume)|ersion|P(?:osition|ageScrollSize)|a(?:l(?:idat(?:ionError|e(?:Property|ActivationKey)?)|ue(?:Of)?)|riable)|LineScrollSize)|k(?:ind|ey(?:Down|Up|Press|FrameInterval))|q(?:sort|uality)|f(?:scommand|i(?:n(?:d(?:Text|First|Last)?|ally)|eldInfo|lter(?:ed|Func)?|rst(?:Slide|Child|DayOfWeek|VisibleNode)?)|o(?:nt|cus(?:In|edCell|Out|Enabled)|r(?:egroundDisabled|mat(?:ter)?))|unctionName|ps|l(?:oor|ush)|ace|romCharCode)|w(?:i(?:th|dth)|ordWrap|atch|riteAccess)|l(?:t|i(?:st(?:Owner)?|ne(?:Style|To))|o(?:c(?:k|a(?:t(?:ion|eByld)|l(?:ToGlobal|FileReadDisable)))|opback|ad(?:Movie(?:Num)?|S(?:crollContent|ound)|ed|Variables(?:Num)?|Application)?|g(?:Changes)?)|e(?:ngth|ft(?:Margin)?|ading)?|a(?:st(?:Slide|Child|Index(?:Of)?)?|nguage|b(?:el(?:Placement|F(?:ield|unction))?|leField)))|a(?:s(?:scociate(?:Controller|Display)|in|pectRatio|function)|nd|c(?:ceptConnection|tiv(?:ityLevel|ePlayControl)|os)|t(?:t(?:ach(?:Movie|Sound|Video|Audio)|ributes)|an(?:2)?)|dd(?:header|RequestHeader|Menu(?:Item(?:At)?|At)?|Sort|Header|No(?:tice|de(?:At)?)|C(?:olumn(?:At)?|uePoint)|T(?:oLocalInternetCache|reeNode(?:At)?)|I(?:con|tem(?:s(?:At)?|At)?)|DeltaItem|P(?:od|age|roperty)|EventListener|View|FieldInfo|Listener|Animation)?|uto(?:Size|Play|KeyNav|Load)|pp(?:endChild|ly(?:Changes|Updates)?)|vHardwareDisable|fterLoaded|l(?:ternateRowColors|ign|l(?:ow(?:InsecureDomain|Domain)|Transitions(?:InDone|OutDone))|bum)|r(?:tist|row|g(?:uments|List))|gent|bs)|r(?:ight(?:Margin)?|o(?:ot(?:S(?:creen|lide)|Form)|und|w(?:Height|Count)|llO(?:ut|ver))|e(?:s(?:yncDepth|t(?:orePane|artAnimation|rict)|iz(?:e|able(?:Columns)?)|olveDelta|ult(?:s)?|ponse)|c(?:o(?:ncile(?:Results|Updates)|rd)|eive(?:Video|Audio))|draw|jectConnection|place(?:Sel|ItemAt|AllItems)?|ve(?:al(?:Child)?|rse)|quest(?:SizeChange|Payment)?|f(?:errer|resh(?:ScrollContent|Destinations|Pane|FromSources)?)|lease(?:Outside)?|ad(?:Only|Access)|gister(?:SkinElement|C(?:olor(?:Style|Name)|lass)|InheritingStyle|Proxy)|move(?:Range|M(?:ovieClip|enu(?:Item(?:At)?|At))|Background|Sort|No(?:tice|de(?:sAt|At)?)|C(?:olum(?:nAt|At)|uePoints)|T(?:extField|reeNode(?:At)?)|Item(?:At)?|Pod|EventListener|FromLocalInternetCache|Listener|All(?:C(?:olumns|uePoints)|Items)?))|a(?:ndom|te|dioDot))|g(?:t|oto(?:Slide|NextSlide|PreviousSlide|FirstSlide|LastSlide|And(?:Stop|Play))|e(?:nre|t(?:R(?:GB|o(?:otNode|wCount)|e(?:sizable|mote))|X(?:AxisTitle)?|M(?:i(?:n(?:imum(?:Size)?|utes)|lliseconds)|onth(?:Names)?|ultilineMode|e(?:ssage|nu(?:ItemAt|EnabledAt|At))|aximum(?:Size)?)|B(?:ytes(?:Total|Loaded)|ounds|utton(?:s|Width)|eginIndex|a(?:ndwidthLimit|ckground))|S(?:howAsDisabled|croll(?:ing|Speed|Content|Position|barState|Location)|t(?:yle(?:Names)?|opOnFocus|ate)|ize|o(?:urce|rtState)|p(?:litterBarPosition|acing)|e(?:conds|lect(?:Multiple|ion(?:Required|Type)|Style|ed(?:Node(?:s)?|Cell|Text|I(?:nd(?:ices|ex)|tem(?:s)?))?)|rvice)|moothness|WFVersion)|H(?:ighlight(?:s|Color)|ours|e(?:ight|ader(?:Height|Text|Property|Format|Width|Location)?)|as(?:Shader|CloseBox))|Y(?:ear|AxisTitle)?|N(?:o(?:tices|de(?:DisplayedAt|At))|um(?:Children|berAvailable)|e(?:wTextFormat|xtHighestDepth))|C(?:h(?:ild(?:S(?:creen|lide)|Nodes|Form|At)|artTitle)|o(?:n(?:tent|figInfo)|okie|de|unt|lumn(?:Names|Count|Index|At))|uePoint|ellIndex|loseHandler|a(?:ll|retIndex))|T(?:ypedValue|i(?:tle(?:barHeight)?|p(?:Target|Offset)?|me(?:stamp|zoneOffset|out(?:State|Handler)|r)?)|oggle|ext(?:Extent|Format)?|r(?:ee(?:NodeAt|Length)|ans(?:form|actionId)))|I(?:s(?:Branch|Open)|n(?:stanceAtDepth|d(?:icesByKey|exByKey))|con(?:SymbolName)?|te(?:rator|m(?:sByKey|By(?:Name|Key)|id|ID|At))|d)|O(?:utput(?:Parameter(?:s|ByName)?|Value(?:s)?)|peration|ri(?:entation|ginalCellData))|D(?:i(?:s(?:play(?:Range|Mode|Clip|Index|edMonth)|kUsage)|rection)|uration|e(?:pth|faultNodeIconSymbolName|l(?:taPacket|ay)|bug(?:Config|ID)?)|a(?:y(?:OfWeekNames)?|t(?:e|a(?:Mapping(?:s)?|Item(?:Text|Property|Format)|Label|All(?:Height|Property|Format|Width))?))|rawConnectors)|U(?:se(?:Shadow|HandCursor|rInput|Fade)|RL|TC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear))|P(?:o(?:sition|ds)|ercentComplete|a(?:n(?:e(?:M(?:inimums|aximums)|Height|Title|Width))?|rentNode)|r(?:operty(?:Name|Data)?|efer(?:ences|red(?:Height|Width))))|E(?:n(?:dIndex|abled)|ditingData|x(?:panderSymbolName|andNodeTrigger))|V(?:iewed(?:Pods|Applications)|olume|ersion|alue(?:Source)?)|F(?:i(?:eld|rst(?:DayOfWeek|VisibleNode))|o(?:ntList|cus)|ullYear|ade(?:InLength|OutLength)|rame(?:Color|Width))|Width|L(?:ine(?:Color|Weight)|o(?:cal|adTarget)|ength|a(?:stTabIndex|bel(?:Source)?))|A(?:s(?:cii|Boolean|String|Number)|n(?:yTypedValue|imation)|ctiv(?:eState(?:Handler)?|ateHandler)|utoH(?:ideScrollBar|eight)|llItems|gent))?)?|lobal(?:StyleFormat|ToLocal)?|ain|roupName)|x(?:updatePackety|mlDecl)?|m(?:y(?:MethodName|Call)|in(?:imum)?|o(?:nthNames|tion(?:TimeOut|Level)|de(?:lChanged)?|use(?:Move|O(?:ut|ver)|Down(?:Somewhere|Outside)?|Up(?:Somewhere)?|WheelEnabled)|ve(?:To)?)|u(?:ted|lti(?:pleS(?:imultaneousAllowed|elections)|line))|e(?:ssage|nu(?:Show|Hide)?|th(?:od)?|diaType)|a(?:nufacturer|tch|x(?:scroll|hscroll|imum|HPosition|Chars|VPosition)?)|b(?:substring|chr|ord|length))|b(?:ytes(?:Total|Loaded)|indFormat(?:Strings|Function)|o(?:ttom(?:Scroll)?|ld|rder(?:Color)?)|u(?:tton(?:Height|Width)|iltInItems|ffer(?:Time|Length)|llet)|e(?:foreApplyUpdates|gin(?:GradientFill|Fill))|lockIndent|a(?:ndwidth|ckground(?:Style|Color|Disabled)?)|roadcastMessage)|onHTTPStatus)\\b"},{token:"support.constant.actionscript.2",regex:"\\b(?:__proto__|__resolve|_accProps|_alpha|_changed|_currentframe|_droptarget|_flash|_focusrect|_framesloaded|_global|_height|_highquality|_level|_listeners|_lockroot|_name|_parent|_quality|_root|_rotation|_soundbuftime|_target|_totalframes|_url|_visible|_width|_x|_xmouse|_xscale|_y|_ymouse|_yscale)\\b"},{token:"keyword.control.actionscript.2",regex:"\\b(?:dynamic|extends|import|implements|interface|public|private|new|static|super|var|for|in|break|continue|while|do|return|if|else|case|switch)\\b"},{token:"storage.type.actionscript.2",regex:"\\b(?:Boolean|Number|String|Void)\\b"},{token:"constant.language.actionscript.2",regex:"\\b(?:null|undefined|true|false)\\b"},{token:"constant.numeric.actionscript.2",regex:"\\b(?:0(?:x|X)[0-9a-fA-F]*|(?:[0-9]+\\.?[0-9]*|\\.[0-9]+)(?:(?:e|E)(?:\\+|-)?[0-9]+)?)(?:L|l|UL|ul|u|U|F|f)?\\b"},{token:"punctuation.definition.string.begin.actionscript.2",regex:'"',push:[{token:"punctuation.definition.string.end.actionscript.2",regex:'"',next:"pop"},{token:"constant.character.escape.actionscript.2",regex:"\\\\."},{defaultToken:"string.quoted.double.actionscript.2"}]},{token:"punctuation.definition.string.begin.actionscript.2",regex:"'",push:[{token:"punctuation.definition.string.end.actionscript.2",regex:"'",next:"pop"},{token:"constant.character.escape.actionscript.2",regex:"\\\\."},{defaultToken:"string.quoted.single.actionscript.2"}]},{token:"support.constant.actionscript.2",regex:"\\b(?:BACKSPACE|CAPSLOCK|CONTROL|DELETEKEY|DOWN|END|ENTER|HOME|INSERT|LEFT|LN10|LN2|LOG10E|LOG2E|MAX_VALUE|MIN_VALUE|NEGATIVE_INFINITY|NaN|PGDN|PGUP|PI|POSITIVE_INFINITY|RIGHT|SPACE|SQRT1_2|SQRT2|UP)\\b"},{token:"punctuation.definition.comment.actionscript.2",regex:"/\\*",push:[{token:"punctuation.definition.comment.actionscript.2",regex:"\\*/",next:"pop"},{defaultToken:"comment.block.actionscript.2"}]},{token:"punctuation.definition.comment.actionscript.2",regex:"//.*$",push_:[{token:"comment.line.double-slash.actionscript.2",regex:"$",next:"pop"},{defaultToken:"comment.line.double-slash.actionscript.2"}]},{token:"keyword.operator.actionscript.2",regex:"\\binstanceof\\b"},{token:"keyword.operator.symbolic.actionscript.2",regex:"[-!%&*+=/?:]"},{token:["meta.preprocessor.actionscript.2","punctuation.definition.preprocessor.actionscript.2","meta.preprocessor.actionscript.2"],regex:"^([ \\t]*)(#)([a-zA-Z]+)"},{token:["storage.type.function.actionscript.2","meta.function.actionscript.2","entity.name.function.actionscript.2","meta.function.actionscript.2","punctuation.definition.parameters.begin.actionscript.2"],regex:"\\b(function)(\\s+)([a-zA-Z_]\\w*)(\\s*)(\\()",push:[{token:"punctuation.definition.parameters.end.actionscript.2",regex:"\\)",next:"pop"},{token:"variable.parameter.function.actionscript.2",regex:"[^,)$]+"},{defaultToken:"meta.function.actionscript.2"}]},{token:["storage.type.class.actionscript.2","meta.class.actionscript.2","entity.name.type.class.actionscript.2","meta.class.actionscript.2","storage.modifier.extends.actionscript.2","meta.class.actionscript.2","entity.other.inherited-class.actionscript.2"],regex:"\\b(class)(\\s+)([a-zA-Z_](?:\\w|\\.)*)(?:(\\s+)(extends)(\\s+)([a-zA-Z_](?:\\w|\\.)*))?"}]},this.normalizeRules()};s.metaData={fileTypes:["as"],keyEquivalent:"^~A",name:"ActionScript",scopeName:"source.actionscript.2"},r.inherits(s,i),t.ActionScriptHighlightRules=s}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++tf)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),ace.define("ace/mode/actionscript",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/actionscript_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./actionscript_highlight_rules").ActionScriptHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o};r.inherits(u,i),function(){this.lineCommentStart="//",this.blockComment={start:"/*",end:"*/"},this.$id="ace/mode/actionscript"}.call(u.prototype),t.Mode=u})
\ No newline at end of file
diff --git a/library/ace/mode-ada.js b/library/ace/mode-ada.js
new file mode 100644
index 000000000..81cdc59e6
--- /dev/null
+++ b/library/ace/mode-ada.js
@@ -0,0 +1 @@
+ace.define("ace/mode/ada_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="abort|else|new|return|abs|elsif|not|reverse|abstract|end|null|accept|entry|select|access|exception|of|separate|aliased|exit|or|some|all|others|subtype|and|for|out|synchronized|array|function|overriding|at|tagged|generic|package|task|begin|goto|pragma|terminate|body|private|then|if|procedure|type|case|in|protected|constant|interface|until||is|raise|use|declare|range|delay|limited|record|when|delta|loop|rem|while|digits|renames|with|do|mod|requeue|xor",t="true|false|null",n="count|min|max|avg|sum|rank|now|coalesce|main",r=this.createKeywordMapper({"support.function":n,keyword:e,"constant.language":t},"identifier",!0);this.$rules={start:[{token:"comment",regex:"--.*$"},{token:"string",regex:'".*?"'},{token:"string",regex:"'.*?'"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:r,regex:"[a-zA-Z_$][a-zA-Z0-9_$]*\\b"},{token:"keyword.operator",regex:"\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|="},{token:"paren.lparen",regex:"[\\(]"},{token:"paren.rparen",regex:"[\\)]"},{token:"text",regex:"\\s+"}]}};r.inherits(s,i),t.AdaHighlightRules=s}),ace.define("ace/mode/ada",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/ada_highlight_rules","ace/range"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./ada_highlight_rules").AdaHighlightRules,o=e("../range").Range,u=function(){this.HighlightRules=s};r.inherits(u,i),function(){this.lineCommentStart="--",this.$id="ace/mode/ada"}.call(u.prototype),t.Mode=u})
\ No newline at end of file
diff --git a/library/ace/mode-apache_conf.js b/library/ace/mode-apache_conf.js
new file mode 100644
index 000000000..66eca9746
--- /dev/null
+++ b/library/ace/mode-apache_conf.js
@@ -0,0 +1 @@
+ace.define("ace/mode/apache_conf_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:["punctuation.definition.comment.apacheconf","comment.line.hash.ini","comment.line.hash.ini"],regex:"^((?:\\s)*)(#)(.*$)"},{token:["punctuation.definition.tag.apacheconf","entity.tag.apacheconf","text","string.value.apacheconf","punctuation.definition.tag.apacheconf"],regex:"(<)(Proxy|ProxyMatch|IfVersion|Directory|DirectoryMatch|Files|FilesMatch|IfDefine|IfModule|Limit|LimitExcept|Location|LocationMatch|VirtualHost)(?:(\\s)(.+?))?(>)"},{token:["punctuation.definition.tag.apacheconf","entity.tag.apacheconf","punctuation.definition.tag.apacheconf"],regex:"()(Proxy|ProxyMatch|IfVersion|Directory|DirectoryMatch|Files|FilesMatch|IfDefine|IfModule|Limit|LimitExcept|Location|LocationMatch|VirtualHost)(>)"},{token:["keyword.alias.apacheconf","text","string.regexp.apacheconf","text","string.replacement.apacheconf","text"],regex:"(Rewrite(?:Rule|Cond))(\\s+)(.+?)(\\s+)(.+?)($|\\s)"},{token:["keyword.alias.apacheconf","text","entity.status.apacheconf","text","string.regexp.apacheconf","text","string.path.apacheconf","text"],regex:"(RedirectMatch)(?:(\\s+)(\\d\\d\\d|permanent|temp|seeother|gone))?(\\s+)(.+?)(\\s+)(?:(.+?)($|\\s))?"},{token:["keyword.alias.apacheconf","text","entity.status.apacheconf","text","string.path.apacheconf","text","string.path.apacheconf","text"],regex:"(Redirect)(?:(\\s+)(\\d\\d\\d|permanent|temp|seeother|gone))?(\\s+)(.+?)(\\s+)(?:(.+?)($|\\s))?"},{token:["keyword.alias.apacheconf","text","string.regexp.apacheconf","text","string.path.apacheconf","text"],regex:"(ScriptAliasMatch|AliasMatch)(\\s+)(.+?)(\\s+)(?:(.+?)(\\s))?"},{token:["keyword.alias.apacheconf","text","string.path.apacheconf","text","string.path.apacheconf","text"],regex:"(RedirectPermanent|RedirectTemp|ScriptAlias|Alias)(\\s+)(.+?)(\\s+)(?:(.+?)($|\\s))?"},{token:"keyword.core.apacheconf",regex:"\\b(?:AcceptPathInfo|AccessFileName|AddDefaultCharset|AddOutputFilterByType|AllowEncodedSlashes|AllowOverride|AuthName|AuthType|CGIMapExtension|ContentDigest|DefaultType|DocumentRoot|EnableMMAP|EnableSendfile|ErrorDocument|ErrorLog|FileETag|ForceType|HostnameLookups|IdentityCheck|Include|KeepAlive|KeepAliveTimeout|LimitInternalRecursion|LimitRequestBody|LimitRequestFields|LimitRequestFieldSize|LimitRequestLine|LimitXMLRequestBody|LogLevel|MaxKeepAliveRequests|NameVirtualHost|Options|Require|RLimitCPU|RLimitMEM|RLimitNPROC|Satisfy|ScriptInterpreterSource|ServerAdmin|ServerAlias|ServerName|ServerPath|ServerRoot|ServerSignature|ServerTokens|SetHandler|SetInputFilter|SetOutputFilter|TimeOut|TraceEnable|UseCanonicalName)\\b"},{token:"keyword.mpm.apacheconf",regex:"\\b(?:AcceptMutex|AssignUserID|BS2000Account|ChildPerUserID|CoreDumpDirectory|EnableExceptionHook|Group|Listen|ListenBacklog|LockFile|MaxClients|MaxMemFree|MaxRequestsPerChild|MaxRequestsPerThread|MaxSpareServers|MaxSpareThreads|MaxThreads|MaxThreadsPerChild|MinSpareServers|MinSpareThreads|NumServers|PidFile|ReceiveBufferSize|ScoreBoardFile|SendBufferSize|ServerLimit|StartServers|StartThreads|ThreadLimit|ThreadsPerChild|ThreadStackSize|User|Win32DisableAcceptEx)\\b"},{token:"keyword.access.apacheconf",regex:"\\b(?:Allow|Deny|Order)\\b"},{token:"keyword.actions.apacheconf",regex:"\\b(?:Action|Script)\\b"},{token:"keyword.alias.apacheconf",regex:"\\b(?:Alias|AliasMatch|Redirect|RedirectMatch|RedirectPermanent|RedirectTemp|ScriptAlias|ScriptAliasMatch)\\b"},{token:"keyword.auth.apacheconf",regex:"\\b(?:AuthAuthoritative|AuthGroupFile|AuthUserFile)\\b"},{token:"keyword.auth_anon.apacheconf",regex:"\\b(?:Anonymous|Anonymous_Authoritative|Anonymous_LogEmail|Anonymous_MustGiveEmail|Anonymous_NoUserID|Anonymous_VerifyEmail)\\b"},{token:"keyword.auth_dbm.apacheconf",regex:"\\b(?:AuthDBMAuthoritative|AuthDBMGroupFile|AuthDBMType|AuthDBMUserFile)\\b"},{token:"keyword.auth_digest.apacheconf",regex:"\\b(?:AuthDigestAlgorithm|AuthDigestDomain|AuthDigestFile|AuthDigestGroupFile|AuthDigestNcCheck|AuthDigestNonceFormat|AuthDigestNonceLifetime|AuthDigestQop|AuthDigestShmemSize)\\b"},{token:"keyword.auth_ldap.apacheconf",regex:"\\b(?:AuthLDAPAuthoritative|AuthLDAPBindDN|AuthLDAPBindPassword|AuthLDAPCharsetConfig|AuthLDAPCompareDNOnServer|AuthLDAPDereferenceAliases|AuthLDAPEnabled|AuthLDAPFrontPageHack|AuthLDAPGroupAttribute|AuthLDAPGroupAttributeIsDN|AuthLDAPRemoteUserIsDN|AuthLDAPUrl)\\b"},{token:"keyword.autoindex.apacheconf",regex:"\\b(?:AddAlt|AddAltByEncoding|AddAltByType|AddDescription|AddIcon|AddIconByEncoding|AddIconByType|DefaultIcon|HeaderName|IndexIgnore|IndexOptions|IndexOrderDefault|ReadmeName)\\b"},{token:"keyword.cache.apacheconf",regex:"\\b(?:CacheDefaultExpire|CacheDisable|CacheEnable|CacheForceCompletion|CacheIgnoreCacheControl|CacheIgnoreHeaders|CacheIgnoreNoLastMod|CacheLastModifiedFactor|CacheMaxExpire)\\b"},{token:"keyword.cern_meta.apacheconf",regex:"\\b(?:MetaDir|MetaFiles|MetaSuffix)\\b"},{token:"keyword.cgi.apacheconf",regex:"\\b(?:ScriptLog|ScriptLogBuffer|ScriptLogLength)\\b"},{token:"keyword.cgid.apacheconf",regex:"\\b(?:ScriptLog|ScriptLogBuffer|ScriptLogLength|ScriptSock)\\b"},{token:"keyword.charset_lite.apacheconf",regex:"\\b(?:CharsetDefault|CharsetOptions|CharsetSourceEnc)\\b"},{token:"keyword.dav.apacheconf",regex:"\\b(?:Dav|DavDepthInfinity|DavMinTimeout|DavLockDB)\\b"},{token:"keyword.deflate.apacheconf",regex:"\\b(?:DeflateBufferSize|DeflateCompressionLevel|DeflateFilterNote|DeflateMemLevel|DeflateWindowSize)\\b"},{token:"keyword.dir.apacheconf",regex:"\\b(?:DirectoryIndex|DirectorySlash)\\b"},{token:"keyword.disk_cache.apacheconf",regex:"\\b(?:CacheDirLength|CacheDirLevels|CacheExpiryCheck|CacheGcClean|CacheGcDaily|CacheGcInterval|CacheGcMemUsage|CacheGcUnused|CacheMaxFileSize|CacheMinFileSize|CacheRoot|CacheSize|CacheTimeMargin)\\b"},{token:"keyword.dumpio.apacheconf",regex:"\\b(?:DumpIOInput|DumpIOOutput)\\b"},{token:"keyword.env.apacheconf",regex:"\\b(?:PassEnv|SetEnv|UnsetEnv)\\b"},{token:"keyword.expires.apacheconf",regex:"\\b(?:ExpiresActive|ExpiresByType|ExpiresDefault)\\b"},{token:"keyword.ext_filter.apacheconf",regex:"\\b(?:ExtFilterDefine|ExtFilterOptions)\\b"},{token:"keyword.file_cache.apacheconf",regex:"\\b(?:CacheFile|MMapFile)\\b"},{token:"keyword.headers.apacheconf",regex:"\\b(?:Header|RequestHeader)\\b"},{token:"keyword.imap.apacheconf",regex:"\\b(?:ImapBase|ImapDefault|ImapMenu)\\b"},{token:"keyword.include.apacheconf",regex:"\\b(?:SSIEndTag|SSIErrorMsg|SSIStartTag|SSITimeFormat|SSIUndefinedEcho|XBitHack)\\b"},{token:"keyword.isapi.apacheconf",regex:"\\b(?:ISAPIAppendLogToErrors|ISAPIAppendLogToQuery|ISAPICacheFile|ISAPIFakeAsync|ISAPILogNotSupported|ISAPIReadAheadBuffer)\\b"},{token:"keyword.ldap.apacheconf",regex:"\\b(?:LDAPCacheEntries|LDAPCacheTTL|LDAPConnectionTimeout|LDAPOpCacheEntries|LDAPOpCacheTTL|LDAPSharedCacheFile|LDAPSharedCacheSize|LDAPTrustedCA|LDAPTrustedCAType)\\b"},{token:"keyword.log.apacheconf",regex:"\\b(?:BufferedLogs|CookieLog|CustomLog|LogFormat|TransferLog|ForensicLog)\\b"},{token:"keyword.mem_cache.apacheconf",regex:"\\b(?:MCacheMaxObjectCount|MCacheMaxObjectSize|MCacheMaxStreamingBuffer|MCacheMinObjectSize|MCacheRemovalAlgorithm|MCacheSize)\\b"},{token:"keyword.mime.apacheconf",regex:"\\b(?:AddCharset|AddEncoding|AddHandler|AddInputFilter|AddLanguage|AddOutputFilter|AddType|DefaultLanguage|ModMimeUsePathInfo|MultiviewsMatch|RemoveCharset|RemoveEncoding|RemoveHandler|RemoveInputFilter|RemoveLanguage|RemoveOutputFilter|RemoveType|TypesConfig)\\b"},{token:"keyword.misc.apacheconf",regex:"\\b(?:ProtocolEcho|Example|AddModuleInfo|MimeMagicFile|CheckSpelling|ExtendedStatus|SuexecUserGroup|UserDir)\\b"},{token:"keyword.negotiation.apacheconf",regex:"\\b(?:CacheNegotiatedDocs|ForceLanguagePriority|LanguagePriority)\\b"},{token:"keyword.nw_ssl.apacheconf",regex:"\\b(?:NWSSLTrustedCerts|NWSSLUpgradeable|SecureListen)\\b"},{token:"keyword.proxy.apacheconf",regex:"\\b(?:AllowCONNECT|NoProxy|ProxyBadHeader|ProxyBlock|ProxyDomain|ProxyErrorOverride|ProxyFtpDirCharset|ProxyIOBufferSize|ProxyMaxForwards|ProxyPass|ProxyPassReverse|ProxyPreserveHost|ProxyReceiveBufferSize|ProxyRemote|ProxyRemoteMatch|ProxyRequests|ProxyTimeout|ProxyVia)\\b"},{token:"keyword.rewrite.apacheconf",regex:"\\b(?:RewriteBase|RewriteCond|RewriteEngine|RewriteLock|RewriteLog|RewriteLogLevel|RewriteMap|RewriteOptions|RewriteRule)\\b"},{token:"keyword.setenvif.apacheconf",regex:"\\b(?:BrowserMatch|BrowserMatchNoCase|SetEnvIf|SetEnvIfNoCase)\\b"},{token:"keyword.so.apacheconf",regex:"\\b(?:LoadFile|LoadModule)\\b"},{token:"keyword.ssl.apacheconf",regex:"\\b(?:SSLCACertificateFile|SSLCACertificatePath|SSLCARevocationFile|SSLCARevocationPath|SSLCertificateChainFile|SSLCertificateFile|SSLCertificateKeyFile|SSLCipherSuite|SSLEngine|SSLMutex|SSLOptions|SSLPassPhraseDialog|SSLProtocol|SSLProxyCACertificateFile|SSLProxyCACertificatePath|SSLProxyCARevocationFile|SSLProxyCARevocationPath|SSLProxyCipherSuite|SSLProxyEngine|SSLProxyMachineCertificateFile|SSLProxyMachineCertificatePath|SSLProxyProtocol|SSLProxyVerify|SSLProxyVerifyDepth|SSLRandomSeed|SSLRequire|SSLRequireSSL|SSLSessionCache|SSLSessionCacheTimeout|SSLUserName|SSLVerifyClient|SSLVerifyDepth)\\b"},{token:"keyword.usertrack.apacheconf",regex:"\\b(?:CookieDomain|CookieExpires|CookieName|CookieStyle|CookieTracking)\\b"},{token:"keyword.vhost_alias.apacheconf",regex:"\\b(?:VirtualDocumentRoot|VirtualDocumentRootIP|VirtualScriptAlias|VirtualScriptAliasIP)\\b"},{token:["keyword.php.apacheconf","text","entity.property.apacheconf","text","string.value.apacheconf","text"],regex:"\\b(php_value|php_flag)\\b(?:(\\s+)(.+?)(?:(\\s+)(.+?))?)?(\\s)"},{token:["punctuation.variable.apacheconf","variable.env.apacheconf","variable.misc.apacheconf","punctuation.variable.apacheconf"],regex:"(%\\{)(?:(HTTP_USER_AGENT|HTTP_REFERER|HTTP_COOKIE|HTTP_FORWARDED|HTTP_HOST|HTTP_PROXY_CONNECTION|HTTP_ACCEPT|REMOTE_ADDR|REMOTE_HOST|REMOTE_PORT|REMOTE_USER|REMOTE_IDENT|REQUEST_METHOD|SCRIPT_FILENAME|PATH_INFO|QUERY_STRING|AUTH_TYPE|DOCUMENT_ROOT|SERVER_ADMIN|SERVER_NAME|SERVER_ADDR|SERVER_PORT|SERVER_PROTOCOL|SERVER_SOFTWARE|TIME_YEAR|TIME_MON|TIME_DAY|TIME_HOUR|TIME_MIN|TIME_SEC|TIME_WDAY|TIME|API_VERSION|THE_REQUEST|REQUEST_URI|REQUEST_FILENAME|IS_SUBREQ|HTTPS)|(.*?))(\\})"},{token:["entity.mime-type.apacheconf","text"],regex:"\\b((?:text|image|application|video|audio)/.+?)(\\s)"},{token:"entity.helper.apacheconf",regex:"\\b(?:from|unset|set|on|off)\\b",caseInsensitive:!0},{token:"constant.integer.apacheconf",regex:"\\b\\d+\\b"},{token:["text","punctuation.definition.flag.apacheconf","string.flag.apacheconf","punctuation.definition.flag.apacheconf","text"],regex:"(\\s)(\\[)(.*?)(\\])(\\s)"}]},this.normalizeRules()};s.metaData={fileTypes:["conf","CONF","htaccess","HTACCESS","htgroups","HTGROUPS","htpasswd","HTPASSWD",".htaccess",".HTACCESS",".htgroups",".HTGROUPS",".htpasswd",".HTPASSWD"],name:"Apache Conf",scopeName:"source.apacheconf"},r.inherits(s,i),t.ApacheConfHighlightRules=s}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++tf)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),ace.define("ace/mode/apache_conf",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/apache_conf_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./apache_conf_highlight_rules").ApacheConfHighlightRules,o=e("./folding/cstyle").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o};r.inherits(u,i),function(){this.lineCommentStart="#",this.$id="ace/mode/apache_conf"}.call(u.prototype),t.Mode=u})
\ No newline at end of file
diff --git a/library/ace/mode-applescript.js b/library/ace/mode-applescript.js
new file mode 100644
index 000000000..b9fdd014f
--- /dev/null
+++ b/library/ace/mode-applescript.js
@@ -0,0 +1 @@
+ace.define("ace/mode/applescript_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){var e="about|above|after|against|and|around|as|at|back|before|beginning|behind|below|beneath|beside|between|but|by|considering|contain|contains|continue|copy|div|does|eighth|else|end|equal|equals|error|every|exit|fifth|first|for|fourth|from|front|get|given|global|if|ignoring|in|into|is|it|its|last|local|me|middle|mod|my|ninth|not|of|on|onto|or|over|prop|property|put|ref|reference|repeat|returning|script|second|set|seventh|since|sixth|some|tell|tenth|that|the|then|third|through|thru|timeout|times|to|transaction|try|until|where|while|whose|with|without",t="AppleScript|false|linefeed|return|pi|quote|result|space|tab|true",n="activate|beep|count|delay|launch|log|offset|read|round|run|say|summarize|write",r="alias|application|boolean|class|constant|date|file|integer|list|number|real|record|string|text|character|characters|contents|day|frontmost|id|item|length|month|name|paragraph|paragraphs|rest|reverse|running|time|version|weekday|word|words|year",i=this.createKeywordMapper({"support.function":n,"constant.language":t,"support.type":r,keyword:e},"identifier");this.$rules={start:[{token:"comment",regex:"--.*$"},{token:"comment",regex:"\\(\\*",next:"comment"},{token:"string",regex:'".*?"'},{token:"support.type",regex:"\\b(POSIX file|POSIX path|(date|time) string|quoted form)\\b"},{token:"support.function",regex:"\\b(clipboard info|the clipboard|info for|list (disks|folder)|mount volume|path to|(close|open for) access|(get|set) eof|current date|do shell script|get volume settings|random number|set volume|system attribute|system info|time to GMT|(load|run|store) script|scripting components|ASCII (character|number)|localized string|choose (application|color|file|file name|folder|from list|remote application|URL)|display (alert|dialog))\\b|^\\s*return\\b"},{token:"constant.language",regex:"\\b(text item delimiters|current application|missing value)\\b"},{token:"keyword",regex:"\\b(apart from|aside from|instead of|out of|greater than|isn't|(doesn't|does not) (equal|come before|come after|contain)|(greater|less) than( or equal)?|(starts?|ends|begins?) with|contained by|comes (before|after)|a (ref|reference))\\b"},{token:i,regex:"[a-zA-Z][a-zA-Z0-9_]*\\b"}],comment:[{token:"comment",regex:"\\*\\)",next:"start"},{defaultToken:"comment"}]},this.normalizeRules()};r.inherits(s,i),t.AppleScriptHighlightRules=s}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++tf)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++no)return new i(o,r,l,t.length)}}.call(o.prototype)}),ace.define("ace/mode/applescript",["require","exports","module","ace/lib/oop","ace/mode/text","ace/tokenizer","ace/mode/applescript_highlight_rules","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("../tokenizer").Tokenizer,o=e("./applescript_highlight_rules").AppleScriptHighlightRules,u=e("./folding/cstyle").FoldMode,a=function(){this.HighlightRules=o,this.foldingRules=new u};r.inherits(a,i),function(){this.lineCommentStart="--",this.blockComment={start:"(*",end:"*)"},this.$id="ace/mode/applescript"}.call(a.prototype),t.Mode=a})
\ No newline at end of file
diff --git a/library/ace/mode-asciidoc.js b/library/ace/mode-asciidoc.js
new file mode 100644
index 000000000..de55f241b
--- /dev/null
+++ b/library/ace/mode-asciidoc.js
@@ -0,0 +1 @@
+ace.define("ace/mode/asciidoc_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){function t(e){var t=/\w/.test(e)?"\\b":"(?:\\B|^)";return t+e+"[^"+e+"].*?"+e+"(?![\\w*])"}var e="[a-zA-Z\u00a1-\uffff]+\\b";this.$rules={start:[{token:"empty",regex:/$/},{token:"literal",regex:/^\.{4,}\s*$/,next:"listingBlock"},{token:"literal",regex:/^-{4,}\s*$/,next:"literalBlock"},{token:"string",regex:/^\+{4,}\s*$/,next:"passthroughBlock"},{token:"keyword",regex:/^={4,}\s*$/},{token:"text",regex:/^\s*$/},{token:"empty",regex:"",next:"dissallowDelimitedBlock"}],dissallowDelimitedBlock:[{include:"paragraphEnd"},{token:"comment",regex:"^//.+$"},{token:"keyword",regex:"^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):"},{include:"listStart"},{token:"literal",regex:/^\s+.+$/,next:"indentedBlock"},{token:"empty",regex:"",next:"text"}],paragraphEnd:[{token:"doc.comment",regex:/^\/{4,}\s*$/,next:"commentBlock"},{token:"tableBlock",regex:/^\s*[|!]=+\s*$/,next:"tableBlock"},{token:"keyword",regex:/^(?:--|''')\s*$/,next:"start"},{token:"option",regex:/^\[.*\]\s*$/,next:"start"},{token:"pageBreak",regex:/^>{3,}$/,next:"start"},{token:"literal",regex:/^\.{4,}\s*$/,next:"listingBlock"},{token:"titleUnderline",regex:/^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/,next:"start"},{token:"singleLineTitle",regex:/^={1,5}\s+\S.*$/,next:"start"},{token:"otherBlock",regex:/^(?:\*{2,}|_{2,})\s*$/,next:"start"},{token:"optionalTitle",regex:/^\.[^.\s].+$/,next:"start"}],listStart:[{token:"keyword",regex:/^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/,next:"listText"},{token:"meta.tag",regex:/^.+(?::{2,4}|;;)(?: |$)/,next:"listText"},{token:"support.function.list.callout",regex:/^(?:<\d+>|\d+>|>) /,next:"text"},{token:"keyword",regex:/^\+\s*$/,next:"start"}],text:[{token:["link","variable.language"],regex:/((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/},{token:"link",regex:/(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/},{token:"link",regex:/\b[\w\.\/\-]+@[\w\.\/\-]+\b/},{include:"macros"},{include:"paragraphEnd"},{token:"literal",regex:/\+{3,}/,next:"smallPassthrough"},{token:"escape",regex:/\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/},{token:"escape",regex:/\\[_*'`+#]|\\{2}[_*'`+#]{2}/},{token:"keyword",regex:/\s\+$/},{token:"text",regex:e},{token:["keyword","string","keyword"],regex:/(<<[\w\d\-$]+,)(.*?)(>>|$)/},{token:"keyword",regex:/<<[\w\d\-$]+,?|>>/},{token:"constant.character",regex:/\({2,3}.*?\){2,3}/},{token:"keyword",regex:/\[\[.+?\]\]/},{token:"support",regex:/^\[{3}[\w\d =\-]+\]{3}/},{include:"quotes"},{token:"empty",regex:/^\s*$/,next:"start"}],listText:[{include:"listStart"},{include:"text"}],indentedBlock:[{token:"literal",regex:/^[\s\w].+$/,next:"indentedBlock"},{token:"literal",regex:"",next:"start"}],listingBlock:[{token:"literal",regex:/^\.{4,}\s*$/,next:"dissallowDelimitedBlock"},{token:"constant.numeric",regex:"<\\d+>"},{token:"literal",regex:"[^<]+"},{token:"literal",regex:"<"}],literalBlock:[{token:"literal",regex:/^-{4,}\s*$/,next:"dissallowDelimitedBlock"},{token:"constant.numeric",regex:"<\\d+>"},{token:"literal",regex:"[^<]+"},{token:"literal",regex:"<"}],passthroughBlock:[{token:"literal",regex:/^\+{4,}\s*$/,next:"dissallowDelimitedBlock"},{token:"literal",regex:e+"|\\d+"},{include:"macros"},{token:"literal",regex:"."}],smallPassthrough:[{token:"literal",regex:/[+]{3,}/,next:"dissallowDelimitedBlock"},{token:"literal",regex:/^\s*$/,next:"dissallowDelimitedBlock"},{token:"literal",regex:e+"|\\d+"},{include:"macros"}],commentBlock:[{token:"doc.comment",regex:/^\/{4,}\s*$/,next:"dissallowDelimitedBlock"},{token:"doc.comment",regex:"^.*$"}],tableBlock:[{token:"tableBlock",regex:/^\s*\|={3,}\s*$/,next:"dissallowDelimitedBlock"},{token:"tableBlock",regex:/^\s*!={3,}\s*$/,next:"innerTableBlock"},{token:"tableBlock",regex:/\|/},{include:"text",noEscape:!0}],innerTableBlock:[{token:"tableBlock",regex:/^\s*!={3,}\s*$/,next:"tableBlock"},{token:"tableBlock",regex:/^\s*|={3,}\s*$/,next:"dissallowDelimitedBlock"},{token:"tableBlock",regex:/\!/}],macros:[{token:"macro",regex:/{[\w\-$]+}/},{token:["text","string","text","constant.character","text"],regex:/({)([\w\-$]+)(:)?(.+)?(})/},{token:["text","markup.list.macro","keyword","string"],regex:/(\w+)(footnote(?:ref)?::?)([^\s\[]+)?(\[.*?\])?/},{token:["markup.list.macro","keyword","string"],regex:/([a-zA-Z\-][\w\.\/\-]*::?)([^\s\[]+)(\[.*?\])?/},{token:["markup.list.macro","keyword"],regex:/([a-zA-Z\-][\w\.\/\-]+::?)(\[.*?\])/},{token:"keyword",regex:/^:.+?:(?= |$)/}],quotes:[{token:"string.italic",regex:/__[^_\s].*?__/},{token:"string.italic",regex:t("_")},{token:"keyword.bold",regex:/\*\*[^*\s].*?\*\*/},{token:"keyword.bold",regex:t("\\*")},{token:"literal",regex:t("\\+")},{token:"literal",regex:/\+\+[^+\s].*?\+\+/},{token:"literal",regex:/\$\$.+?\$\$/},{token:"literal",regex:t("`")},{token:"keyword",regex:t("^")},{token:"keyword",regex:t("~")},{token:"keyword",regex:/##?/},{token:"keyword",regex:/(?:\B|^)``|\b''/}]};var n={macro:"constant.character",tableBlock:"doc.comment",titleUnderline:"markup.heading",singleLineTitle:"markup.heading",pageBreak:"string",option:"string.regexp",otherBlock:"markup.list",literal:"support.function",optionalTitle:"constant.numeric",escape:"constant.language.escape",link:"markup.underline.list"};for(var r in this.$rules){var i=this.$rules[r];for(var s=i.length;s--;){var o=i[s];if(o.include||typeof o=="string"){var u=[s,1].concat(this.$rules[o.include||o]);o.noEscape&&(u=u.filter(function(e){return!e.next})),i.splice.apply(i,u)}else o.token in n&&(o.token=n[o.token])}}};r.inherits(s,i),t.AsciidocHighlightRules=s}),ace.define("ace/mode/folding/asciidoc",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.foldingStartMarker=/^(?:\|={10,}|[\.\/=\-~^+]{4,}\s*$|={1,5} )/,this.singleLineHeadingRe=/^={1,5}(?=\s+\S)/,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?r[0]=="="?this.singleLineHeadingRe.test(r)?"start":e.getLine(n-1).length!=e.getLine(n).length?"":"start":e.bgTokenizer.getState(n)=="dissallowDelimitedBlock"?"end":"start":""},this.getFoldWidgetRange=function(e,t,n){function l(t){return f=e.getTokens(t)[0],f&&f.type}function d(){var t=f.value.match(p);if(t)return t[0].length;var r=c.indexOf(f.value[0])+1;return r==1&&e.getLine(n-1).length!=e.getLine(n).length?Infinity:r}var r=e.getLine(n),i=r.length,o=e.getLength(),u=n,a=n;if(!r.match(this.foldingStartMarker))return;var f,c=["=","-","~","^","+"],h="markup.heading",p=this.singleLineHeadingRe;if(l(n)==h){var v=d();while(++nu)while(a>u&&(!l(a)||f.value[0]=="["))a--;if(a>u){var y=e.getLine(a).length;return new s(u,i,a,y)}}else{var b=e.bgTokenizer.getState(n);if(b=="dissallowDelimitedBlock"){while(n-->0)if(e.bgTokenizer.getState(n).lastIndexOf("Block")==-1)break;a=n+1;if(au){var y=e.getLine(n).length;return new s(u,5,a,y-5)}}}}}.call(o.prototype)}),ace.define("ace/mode/asciidoc",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/asciidoc_highlight_rules","ace/mode/folding/asciidoc"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./asciidoc_highlight_rules").AsciidocHighlightRules,o=e("./folding/asciidoc").FoldMode,u=function(){this.HighlightRules=s,this.foldingRules=new o};r.inherits(u,i),function(){this.type="text",this.getNextLineIndent=function(e,t,n){if(e=="listblock"){var r=/^((?:.+)?)([-+*][ ]+)/.exec(t);return r?(new Array(r[1].length+1)).join(" ")+r[2]:""}return this.$getIndent(t)},this.$id="ace/mode/asciidoc"}.call(u.prototype),t.Mode=u})
\ No newline at end of file
diff --git a/library/ace/mode-assembly_x86.js b/library/ace/mode-assembly_x86.js
new file mode 100644
index 000000000..06378b61d
--- /dev/null
+++ b/library/ace/mode-assembly_x86.js
@@ -0,0 +1 @@
+ace.define("ace/mode/assembly_x86_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"keyword.control.assembly",regex:"\\b(?:aaa|aad|aam|aas|adc|add|addpd|addps|addsd|addss|addsubpd|addsubps|aesdec|aesdeclast|aesenc|aesenclast|aesimc|aeskeygenassist|and|andpd|andps|andnpd|andnps|arpl|blendpd|blendps|blendvpd|blendvps|bound|bsf|bsr|bswap|bt|btc|btr|bts|cbw|cwde|cdqe|clc|cld|cflush|clts|cmc|cmov(?:n?e|ge?|ae?|le?|be?|n?o|n?z)|cmp|cmppd|cmpps|cmps|cnpsb|cmpsw|cmpsd|cmpsq|cmpss|cmpxchg|cmpxchg8b|cmpxchg16b|comisd|comiss|cpuid|crc32|cvtdq2pd|cvtdq2ps|cvtpd2dq|cvtpd2pi|cvtpd2ps|cvtpi2pd|cvtpi2ps|cvtps2dq|cvtps2pd|cvtps2pi|cvtsd2si|cvtsd2ss|cvts2sd|cvtsi2ss|cvtss2sd|cvtss2si|cvttpd2dq|cvtpd2pi|cvttps2dq|cvttps2pi|cvttps2dq|cvttps2pi|cvttsd2si|cvttss2si|cwd|cdq|cqo|daa|das|dec|div|divpd|divps|divsd|divss|dppd|dpps|emms|enter|extractps|f2xm1|fabs|fadd|faddp|fiadd|fbld|fbstp|fchs|fclex|fnclex|fcmov(?:n?e|ge?|ae?|le?|be?|n?o|n?z)|fcom|fcmop|fcompp|fcomi|fcomip|fucomi|fucomip|fcos|fdecstp|fdiv|fdivp|fidiv|fdivr|fdivrp|fidivr|ffree|ficom|ficomp|fild|fincstp|finit|fnint|fist|fistp|fisttp|fld|fld1|fldl2t|fldl2e|fldpi|fldlg2|fldln2|fldz|fldcw|fldenv|fmul|fmulp|fimul|fnop|fpatan|fprem|fprem1|fptan|frndint|frstor|fsave|fnsave|fscale|fsin|fsincos|fsqrt|fst|fstp|fstcw|fnstcw|fstenv|fnstenv|fsts|fnstsw|fsub|fsubp|fisub|fsubr|fsubrp|fisubr|ftst|fucom|fucomp|fucompp|fxam|fxch|fxrstor|fxsave|fxtract|fyl2x|fyl2xp1|haddpd|haddps|husbpd|hsubps|idiv|imul|in|inc|ins|insb|insw|insd|insertps|int|into|invd|invplg|invpcid|iret|iretd|iretq|lahf|lar|lddqu|ldmxcsr|lds|les|lfs|lgs|lss|lea|leave|lfence|lgdt|lidt|llgdt|lmsw|lock|lods|lodsb|lodsw|lodsd|lodsq|lsl|ltr|maskmovdqu|maskmovq|maxpd|maxps|maxsd|maxss|mfence|minpd|minps|minsd|minss|monitor|mov|movapd|movaps|movbe|movd|movq|movddup|movdqa|movdqu|movq2q|movhlps|movhpd|movhps|movlhps|movlpd|movlps|movmskpd|movmskps|movntdqa|movntdq|movnti|movntpd|movntps|movntq|movq|movq2dq|movs|movsb|movsw|movsd|movsq|movsd|movshdup|movsldup|movss|movsx|movsxd|movupd|movups|movzx|mpsadbw|mul|mulpd|mulps|mulsd|mulss|mwait|neg|not|or|orpd|orps|out|outs|outsb|outsw|outsd|pabsb|pabsw|pabsd|packsswb|packssdw|packusdw|packuswbpaddb|paddw|paddd|paddq|paddsb|paddsw|paddusb|paddusw|palignr|pand|pandn|pause|pavgb|pavgw|pblendvb|pblendw|pclmulqdq|pcmpeqb|pcmpeqw|pcmpeqd|pcmpeqq|pcmpestri|pcmpestrm|pcmptb|pcmptgw|pcmpgtd|pcmpgtq|pcmpistri|pcmpisrm|pextrb|pextrd|pextrq|pextrw|phaddw|phaddd|phaddsw|phinposuw|phsubw|phsubd|phsubsw|pinsrb|pinsrd|pinsrq|pinsrw|pmaddubsw|pmadddwd|pmaxsb|pmaxsd|pmaxsw|pmaxsw|pmaxub|pmaxud|pmaxuw|pminsb|pminsd|pminsw|pminub|pminud|pminuw|pmovmskb|pmovsx|pmovzx|pmuldq|pmulhrsw|pmulhuw|pmulhw|pmulld|pmullw|pmuludw|pop|popa|popad|popcnt|popf|popfd|popfq|por|prefetch|psadbw|pshufb|pshufd|pshufhw|pshuflw|pshufw|psignb|psignw|psignd|pslldq|psllw|pslld|psllq|psraw|psrad|psrldq|psrlw|psrld|psrlq|psubb|psubw|psubd|psubq|psubsb|psubsw|psubusb|psubusw|test|ptest|punpckhbw|punpckhwd|punpckhdq|punpckhddq|punpcklbw|punpcklwd|punpckldq|punpckldqd|push|pusha|pushad|pushf|pushfd|pxor|prcl|rcr|rol|ror|rcpps|rcpss|rdfsbase|rdgsbase|rdmsr|rdpmc|rdrand|rdtsc|rdtscp|rep|repe|repz|repne|repnz|roundpd|roundps|roundsd|roundss|rsm|rsqrps|rsqrtss|sahf|sal|sar|shl|shr|sbb|scas|scasb|scasw|scasd|set(?:n?e|ge?|ae?|le?|be?|n?o|n?z)|sfence|sgdt|shld|shrd|shufpd|shufps|sidt|sldt|smsw|sqrtpd|sqrtps|sqrtsd|sqrtss|stc|std|stmxcsr|stos|stosb|stosw|stosd|stosq|str|sub|subpd|subps|subsd|subss|swapgs|syscall|sysenter|sysexit|sysret|teset|ucomisd|ucomiss|ud2|unpckhpd|unpckhps|unpcklpd|unpcklps|vbroadcast|vcvtph2ps|vcvtp2sph|verr|verw|vextractf128|vinsertf128|vmaskmov|vpermilpd|vpermilps|vperm2f128|vtestpd|vtestps|vzeroall|vzeroupper|wait|fwait|wbinvd|wrfsbase|wrgsbase|wrmsr|xadd|xchg|xgetbv|xlat|xlatb|xor|xorpd|xorps|xrstor|xsave|xsaveopt|xsetbv|lzcnt|extrq|insertq|movntsd|movntss|vfmaddpd|vfmaddps|vfmaddsd|vfmaddss|vfmaddsubbpd|vfmaddsubps|vfmsubaddpd|vfmsubaddps|vfmsubpd|vfmsubps|vfmsubsd|vfnmaddpd|vfnmaddps|vfnmaddsd|vfnmaddss|vfnmsubpd|vfnmusbps|vfnmusbsd|vfnmusbss|cvt|xor|cli|sti|hlt|nop|lock|wait|enter|leave|ret|loop(?:n?e|n?z)?|call|j(?:mp|n?e|ge?|ae?|le?|be?|n?o|n?z))\\b",caseInsensitive:!0},{token:"variable.parameter.register.assembly",regex:"\\b(?:CS|DS|ES|FS|GS|SS|RAX|EAX|RBX|EBX|RCX|ECX|RDX|EDX|RCX|RIP|EIP|IP|RSP|ESP|SP|RSI|ESI|SI|RDI|EDI|DI|RFLAGS|EFLAGS|FLAGS|R8-15|(?:Y|X)MM(?:[0-9]|10|11|12|13|14|15)|(?:A|B|C|D)(?:X|H|L)|CR(?:[0-4]|DR(?:[0-7]|TR6|TR7|EFER)))\\b",caseInsensitive:!0},{token:"constant.character.decimal.assembly",regex:"\\b[0-9]+\\b"},{token:"constant.character.hexadecimal.assembly",regex:"\\b0x[A-F0-9]+\\b",caseInsensitive:!0},{token:"constant.character.hexadecimal.assembly",regex:"\\b[A-F0-9]+h\\b",caseInsensitive:!0},{token:"string.assembly",regex:/'([^\\']|\\.)*'/},{token:"string.assembly",regex:/"([^\\"]|\\.)*"/},{token:"support.function.directive.assembly",regex:"^\\[",push:[{token:"support.function.directive.assembly",regex:"\\]$",next:"pop"},{defaultToken:"support.function.directive.assembly"}]},{token:["support.function.directive.assembly","support.function.directive.assembly","entity.name.function.assembly"],regex:"(^struc)( )([_a-zA-Z][_a-zA-Z0-9]*)"},{token:"support.function.directive.assembly",regex:"^endstruc\\b"},{token:["support.function.directive.assembly","entity.name.function.assembly","support.function.directive.assembly","constant.character.assembly"],regex:"^(%macro )([_a-zA-Z][_a-zA-Z0-9]*)( )([0-9]+)"},{token:"support.function.directive.assembly",regex:"^%endmacro"},{token:["text","support.function.directive.assembly","text","entity.name.function.assembly"],regex:"(\\s*)(%define|%xdefine|%idefine|%undef|%assign|%defstr|%strcat|%strlen|%substr|%00|%0|%rotate|%rep|%endrep|%include|\\$\\$|\\$|%unmacro|%if|%elif|%else|%endif|%(?:el)?ifdef|%(?:el)?ifmacro|%(?:el)?ifctx|%(?:el)?ifidn|%(?:el)?ifidni|%(?:el)?ifid|%(?:el)?ifnum|%(?:el)?ifstr|%(?:el)?iftoken|%(?:el)?ifempty|%(?:el)?ifenv|%pathsearch|%depend|%use|%push|%pop|%repl|%arg|%stacksize|%local|%error|%warning|%fatal|%line|%!|%comment|%endcomment|__NASM_VERSION_ID__|__NASM_VER__|__FILE__|__LINE__|__BITS__|__OUTPUT_FORMAT__|__DATE__|__TIME__|__DATE_NUM__|_TIME__NUM__|__UTC_DATE__|__UTC_TIME__|__UTC_DATE_NUM__|__UTC_TIME_NUM__|__POSIX_TIME__|__PASS__|ISTRUC|AT|IEND|BITS 16|BITS 32|BITS 64|USE16|USE32|__SECT__|ABSOLUTE|EXTERN|GLOBAL|COMMON|CPU|FLOAT)\\b( ?)((?:[_a-zA-Z][_a-zA-Z0-9]*)?)",caseInsensitive:!0},{token:"support.function.directive.assembly",regex:"\\b(?:d[bwdqtoy]|res[bwdqto]|equ|times|align|alignb|sectalign|section|ptr|byte|word|dword|qword|incbin)\\b",caseInsensitive:!0},{token:"entity.name.function.assembly",regex:"^\\s*%%[\\w.]+?:$"},{token:"entity.name.function.assembly",regex:"^\\s*%\\$[\\w.]+?:$"},{token:"entity.name.function.assembly",regex:"^[\\w.]+?:"},{token:"entity.name.function.assembly",regex:"^[\\w.]+?\\b"},{token:"comment.assembly",regex:";.*$"}]},this.normalizeRules()};s.metaData={fileTypes:["asm"],name:"Assembly x86",scopeName:"source.assembly"},r.inherits(s,i),t.AssemblyX86HighlightRules=s}),ace.define("ace/mode/folding/coffee",["require","exports","module","ace/lib/oop","ace/mode/folding/fold_mode","ace/range"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("./fold_mode").FoldMode,s=e("../../range").Range,o=t.FoldMode=function(){};r.inherits(o,i),function(){this.getFoldWidgetRange=function(e,t,n){var r=this.indentationBlock(e,n);if(r)return r;var i=/\S/,o=e.getLine(n),u=o.search(i);if(u==-1||o[u]!="#")return;var a=o.length,f=e.getLength(),l=n,c=n;while(++nl){var p=e.getLine(c).length;return new s(l,a,c,p)}},this.getFoldWidget=function(e,t,n){var r=e.getLine(n),i=r.search(/\S/),s=e.getLine(n+1),o=e.getLine(n-1),u=o.search(/\S/),a=s.search(/\S/);if(i==-1)return e.foldWidgets[n-1]=u!=-1&&u