From 44dd1ef6f6a3325d3a55550da95dd22bd96684dc Mon Sep 17 00:00:00 2001 From: discomrade Date: Wed, 13 Oct 2021 13:32:23 +0000 Subject: [PATCH 01/74] Add IPv6 support for DNSBL Should have used the library but didn't want to experiement and posiibly break the includes --- inc/functions.php | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 44712b16..c2a7dc36 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1753,9 +1753,6 @@ function buildJavascript() { function checkDNSBL() { global $config; - if (isIPv6()) - return; // No IPv6 support yet. - if (!isset($_SERVER['REMOTE_ADDR'])) return; // Fix your web server configuration @@ -1765,7 +1762,11 @@ function checkDNSBL() { if (in_array($_SERVER['REMOTE_ADDR'], $config['dnsbl_exceptions'])) return; - $ipaddr = ReverseIPOctets($_SERVER['REMOTE_ADDR']); + if (isIPv6()) { + $ipaddr = ReverseIPv6Octets($_SERVER['REMOTE_ADDR']); + } else { + $ipaddr = ReverseIPv4Octets($_SERVER['REMOTE_ADDR']); + } foreach ($config['dnsbl'] as $blacklist) { if (!is_array($blacklist)) @@ -1801,10 +1802,30 @@ function isIPv6() { return strstr($_SERVER['REMOTE_ADDR'], ':') !== false; } -function ReverseIPOctets($ip) { +function ReverseIPv4Octets($ip) { return implode('.', array_reverse(explode('.', $ip))); } +function ReverseIPv6Octets($ip) { + return strrev(implode(".", str_split(str_replace(':', '', inet_expand($ip))))); +} + +// copypastad from lib/IP/Lifo/IP.php, TODO replace this with a proper include +function inet_expand($ip) +{ + // strip possible cidr notation off + if (($pos = strpos($ip, '/')) !== false) { + $ip = substr($ip, 0, $pos); + } + $bytes = unpack('n*', inet_pton($ip)); + if (count($bytes) > 2) { + return implode(':', array_map(function ($b) { + return sprintf("%04x", $b); + }, $bytes)); + } + return $ip; +} + function wordfilters(&$body) { global $config; From cbc887df8d81561fdc9927be4e37f0b6c1174caf Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 13 Oct 2021 19:28:24 +0200 Subject: [PATCH 02/74] Feedback on uniqueIpFix. Moves the insertion of the bar | after Unique IPs to be inserted by the thread watcher JS script. see: https://leftypol.org/tech/res/6724.html#11998 --- js/thread-stats.js | 2 +- templates/post_thread.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/thread-stats.js b/js/thread-stats.js index 7fd2ac1f..db804f1f 100644 --- a/js/thread-stats.js +++ b/js/thread-stats.js @@ -22,7 +22,7 @@ $(document).ready(function(){ el.prepend('0 UIDs | '); } el.prepend('0 images | '); - el.prepend('0 replies | '); + el.prepend('| 0 replies | '); delete el; function update_thread_stats(){ var op = $('#thread_'+ thread_id).find('div.post.op:not(.post-hover):not(.inline)').first(); diff --git a/templates/post_thread.html b/templates/post_thread.html index 9df3f2fb..bdb4863e 100644 --- a/templates/post_thread.html +++ b/templates/post_thread.html @@ -100,7 +100,7 @@ {% endfor %}
{% if not index %} -
Unique IPs: {{ iparray|length }} |
+
Unique IPs: {{ iparray|length }}
{% endif %} {% if hr %}
{% endif %} From a8f6b123b047ea2b777c3ea9d147ba64e46c4c71 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 14 Oct 2021 06:00:23 +0000 Subject: [PATCH 03/74] Lower maximum delay for recent post auto-update --- js/mod/recent-posts-auto-reload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/mod/recent-posts-auto-reload.js b/js/mod/recent-posts-auto-reload.js index e401c8bd..1c269c18 100644 --- a/js/mod/recent-posts-auto-reload.js +++ b/js/mod/recent-posts-auto-reload.js @@ -101,7 +101,7 @@ $(document).ready(function(){ // Grab the settings var settings = new script_settings('auto-reload-mod'); var poll_interval_mindelay = settings.get('min_delay_bottom', 5000); - var poll_interval_maxdelay = settings.get('max_delay', 600000); + var poll_interval_maxdelay = settings.get('max_delay', 10000); var poll_interval_errordelay = settings.get('error_delay', 30000); // number of ms to wait before reloading From d0e445e444485375a05bc489c121167933e003a8 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 14 Oct 2021 07:04:26 +0000 Subject: [PATCH 04/74] Clean up duplicate code --- inc/bans.php | 6 +++--- inc/functions.php | 21 ++++----------------- 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/inc/bans.php b/inc/bans.php index 81e38006..e629ddae 100644 --- a/inc/bans.php +++ b/inc/bans.php @@ -1,8 +1,8 @@ 2) { - return implode(':', array_map(function ($b) { - return sprintf("%04x", $b); - }, $bytes)); - } - return $ip; + return strrev(implode(".", str_split(str_replace(':', '', IP::inet_expand($ip))))); } function wordfilters(&$body) { From 320fc8e86d114a29a05a7b05b6dc40323a3f2736 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 14 Oct 2021 21:03:28 -0100 Subject: [PATCH 05/74] Separate mod auto-update settings from normal settings --- js/mod/recent-posts-auto-reload.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/js/mod/recent-posts-auto-reload.js b/js/mod/recent-posts-auto-reload.js index 1c269c18..90ba9fdb 100644 --- a/js/mod/recent-posts-auto-reload.js +++ b/js/mod/recent-posts-auto-reload.js @@ -42,24 +42,24 @@ auto_reload_enabled = true; // for watch.js to interop $(document).ready(function(){ // Adds Options panel item - if (typeof localStorage.auto_recent_update === 'undefined') { - localStorage.auto_recent_update = 'true'; //default value + if (typeof localStorage.auto_recent_update_mod === 'undefined') { + localStorage.auto_recent_update_mod = 'true'; //default value } if (window.Options && Options.get_tab('general')) { Options.extend_tab("general", "
"+_("Auto update (recent)")+"" - + ('') - + ('') + + ('') + + ('') + '
'); - $('#auto-recent-update>input').on('click', function() { - if ($('#auto-recent-update>input').is(':checked')) { - localStorage.auto_recent_update = 'true'; + $('#auto-recent-update-mod>input').on('click', function() { + if ($('#auto-recent-update-mod>input').is(':checked')) { + localStorage.auto_recent_update_mod = 'true'; } else { - localStorage.auto_recent_update = 'false'; + localStorage.auto_recent_update_mod = 'false'; } }); - $('#auto_recent_desktop_notifications>input,#auto_recent_desktop_notifications_all>input').on('click', function() { + $('#auto_recent_desktop_notifications_all_mod>input').on('click', function() { if (!("Notification" in window)) return; var setting = $(this).parent().attr('id'); @@ -78,12 +78,12 @@ $(document).ready(function(){ } }); - if (localStorage.auto_recent_update === 'true') { - $('#auto-recent-update>input').prop('checked', true); + if (localStorage.auto_recent_update_mod === 'true') { + $('#auto-recent-update-mod>input').prop('checked', true); } - if (localStorage.auto_recent_desktop_notifications_all === 'true') { - $('#auto_recent_desktop_notifications_all>input').prop('checked', true); + if (localStorage.auto_recent_desktop_notifications_all_mod === 'true') { + $('#auto_recent_desktop_notifications_all_mod>input').prop('checked', true); notify = "all"; } } @@ -94,7 +94,7 @@ $(document).ready(function(){ $(".bar-bottom span:last-child").append("["+_("Update")+"] ( "+_("Auto")+") "); // Set the updater checkbox according to user setting - if (localStorage.auto_recent_update === 'true') { + if (localStorage.auto_recent_update_mod === 'true') { $('#auto_update_status').prop('checked', true); } From a0f586dfa2d22f06bb96d1236133501d7f47f030 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 14 Oct 2021 23:08:10 +0000 Subject: [PATCH 06/74] Fix notifications: replace reference to undisplayed div --- js/auto-reload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/auto-reload.js b/js/auto-reload.js index aedbea4f..0d64a77b 100644 --- a/js/auto-reload.js +++ b/js/auto-reload.js @@ -188,7 +188,7 @@ $(document).ready(function(){ if (typeof end_of_page == "undefined") var end_of_page = false; if (end_of_page || (new_posts && window_active && $(window).scrollTop() + $(window).height() >= - $('div.boardlist.bottom').position().top)) { + $('#thread-interactions').position().top)) { new_posts = 0; } From bea6c371b11a7a80a74c41bc1163918c92803c7c Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 15 Oct 2021 00:06:24 +0000 Subject: [PATCH 07/74] Make all notifications show, not just the first unread --- js/auto-reload.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/auto-reload.js b/js/auto-reload.js index 0d64a77b..5cdf12ae 100644 --- a/js/auto-reload.js +++ b/js/auto-reload.js @@ -240,10 +240,10 @@ $(document).ready(function(){ if (!new_posts) { first_new_post = this; makeIcon('reply'); - if (notify === "all" || (notify === "mention" && $(this).find('.own_post').length)) { + } + if (notify === "all" || (notify === "mention" && $(this).find('.own_post').length)) { var body = $(this).children('.body').html().replace(//gi, "\n"); var n = new Notification("New reply to "+$('title').text(), {body: $('
').html(body).text()}); - } } if ($("div.post").length > 1){ $(this).insertAfter($('div.post:not(.post-hover):last').next()).after('
'); From 04289c6613e3e9311f039a252bd44e37cd7c1d60 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 15 Oct 2021 00:09:00 +0000 Subject: [PATCH 08/74] Fix notifications --- js/mod/recent-posts-auto-reload.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/js/mod/recent-posts-auto-reload.js b/js/mod/recent-posts-auto-reload.js index 90ba9fdb..e2d661d2 100644 --- a/js/mod/recent-posts-auto-reload.js +++ b/js/mod/recent-posts-auto-reload.js @@ -116,7 +116,7 @@ $(document).ready(function(){ var title = document.title; if (typeof update_title == "undefined") { - var update_title = function() { + var update_title = function() { if (new_posts) { document.title = "("+new_posts+") "+title; } else { @@ -134,6 +134,7 @@ $(document).ready(function(){ var window_active = true; $(window).focus(function() { window_active = true; + recheck_activated(); // Reset the delay if needed if(settings.get('reset_focus', true)) { @@ -155,7 +156,6 @@ $(document).ready(function(){ }); - var decrement_timer = function() { poll_current_time = poll_current_time - 1000; $('#update_secs').text(poll_current_time/1000); @@ -165,6 +165,16 @@ $(document).ready(function(){ } } + var recheck_activated = function() { + if (new_posts && window_active && + $(window).scrollTop() <= + $('header').position().top + $('header').outerHeight(true)) { + new_posts = 0; + } + update_title(); + first_new_post = null; + }; + // automatically updates the thread after a specified delay var auto_update = function(delay) { clearInterval(countdown_interval); @@ -207,11 +217,11 @@ $(document).ready(function(){ if($('#' + id).length == 0) { if (!new_posts) { first_new_post = this; - makeIcon('reply'); - if (notify === "all") { - var body = $(this).children('.body').html().replace(//gi, "\n"); - var n = new Notification("New reply to "+$('title').text(), {body: $('
').html(body).text()}); - } + } + // Notify on all posts, not just the first unread + if (notify === "all") { + var body = $(this).children('.body').html().replace(//gi, "\n"); + var n = new Notification("New reply to "+$('title').text(), {body: $('
').html(body).text()}); } if ($("div.post,div.thread").length > 1){ $(this).parent().insertBefore($($('div.post,div.thread').not('.post-hover').first()).parent()); @@ -222,6 +232,7 @@ $(document).ready(function(){ new_posts++; loaded_posts++; $(document).trigger('new_post', this); + recheck_activated(); } }); @@ -279,6 +290,9 @@ $(document).ready(function(){ return false; }; + $(window).scrollStopped(function() { + recheck_activated(); + }); $('#update_thread').on('click', function() { poll(manualUpdate = true); return false; }); From 47ac8c7ae9aeabda129344fecd2bf0287f3146c9 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 15 Oct 2021 00:52:23 +0000 Subject: [PATCH 09/74] Use stored title instead of document.title in notifications Prevents number of unreads being added to notificaiton thread name --- js/auto-reload.js | 4 ++-- js/mod/recent-posts-auto-reload.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/auto-reload.js b/js/auto-reload.js index 5cdf12ae..3e291f01 100644 --- a/js/auto-reload.js +++ b/js/auto-reload.js @@ -242,8 +242,8 @@ $(document).ready(function(){ makeIcon('reply'); } if (notify === "all" || (notify === "mention" && $(this).find('.own_post').length)) { - var body = $(this).children('.body').html().replace(//gi, "\n"); - var n = new Notification("New reply to "+$('title').text(), {body: $('
').html(body).text()}); + var body = $(this).children('.body').html().replace(//gi, "\n"); + var n = new Notification("New reply to "+title, {body: $('
').html(body).text()}); } if ($("div.post").length > 1){ $(this).insertAfter($('div.post:not(.post-hover):last').next()).after('
'); diff --git a/js/mod/recent-posts-auto-reload.js b/js/mod/recent-posts-auto-reload.js index e2d661d2..0bad51bd 100644 --- a/js/mod/recent-posts-auto-reload.js +++ b/js/mod/recent-posts-auto-reload.js @@ -221,7 +221,7 @@ $(document).ready(function(){ // Notify on all posts, not just the first unread if (notify === "all") { var body = $(this).children('.body').html().replace(//gi, "\n"); - var n = new Notification("New reply to "+$('title').text(), {body: $('
').html(body).text()}); + var n = new Notification("New reply to "+title, {body: $('
').html(body).text()}); } if ($("div.post,div.thread").length > 1){ $(this).parent().insertBefore($($('div.post,div.thread').not('.post-hover').first()).parent()); From 320ae12266527b2e7a3208a3d1f9909e2d887def Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 15 Oct 2021 01:23:02 -0100 Subject: [PATCH 10/74] Add option for custom YouTube embed proxy --- js/youtube.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/js/youtube.js b/js/youtube.js index e2fb7dd1..4c31ed09 100644 --- a/js/youtube.js +++ b/js/youtube.js @@ -22,13 +22,31 @@ * */ - $(document).ready(function(){ + // Adds Options panel item + if (typeof localStorage.youtube_embed_proxy === 'undefined') { + if (location.hostname.includes(".onion")){ + localStorage.youtube_embed_proxy = 'tuberyps2pn6dor6h47brof3w2asmauahhk4ei42krugybzzzo55klad.onion'; + } else { + localStorage.youtube_embed_proxy = 'incogtube.com'; //default value + } + } + + if (window.Options && Options.get_tab('general')) { + Options.extend_tab("general", "
"+_("Media Proxy (requires refresh)")+"" + + ('') + + '
'); + + $('#youtube-embed-proxy-url>input').val(localStorage.youtube_embed_proxy); + $('#youtube-embed-proxy-url>input').on('input', function() { + localStorage.youtube_embed_proxy = $('#youtube-embed-proxy-url>input').val(); + }); + } + const ON = "[Remove]"; const OFF = "[Embed]"; - const YOUTUBE = 'www.youtube.com'; - const ONION = 'tuberyps2pn6dor6h47brof3w2asmauahhk4ei42krugybzzzo55klad.onion'; - const PROXY = 'incogtube.com' + const YOUTUBE = 'www.youtube.com'; + const PROXY = localStorage.youtube_embed_proxy; function addEmbedButton(index, videoNode) { videoNode = $(videoNode); var contents = videoNode.contents(); @@ -41,7 +59,7 @@ $(document).ready(function(){ 'width="360" height="270" src="//' + embedHost + '/embed/' + videoId + '?autoplay=1&html5=1" allowfullscreen frameborder="0"/>'); } - var defaultEmbed = makeEmbedNode(location.hostname.includes("onion") ? ONION : YOUTUBE); + var defaultEmbed = makeEmbedNode(location.hostname.includes(".onion") ? PROXY : YOUTUBE); var proxyEmbed = makeEmbedNode(PROXY); videoNode.click(function(e) { e.preventDefault(); From 072807882f5dd5213518c9a5a7ec0fb17d851ae3 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 15 Oct 2021 04:20:09 +0000 Subject: [PATCH 11/74] Fix double-encoding on post edit form https://git.leftypol.org/leftypol/leftypol/issues/31 --- templates/mod/edit_post_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/mod/edit_post_form.html b/templates/mod/edit_post_form.html index a22f36f3..7f8d4b1e 100644 --- a/templates/mod/edit_post_form.html +++ b/templates/mod/edit_post_form.html @@ -15,7 +15,7 @@ {% trans %}Email{% endtrans %} - + @@ -32,7 +32,7 @@ {% trans %}Comment{% endtrans %} - + From b9133416604bd11f3e7e147e5f963053f08ae13f Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 15 Oct 2021 06:05:03 -0100 Subject: [PATCH 12/74] Add blur images option --- js/blur-images.js | 102 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 js/blur-images.js diff --git a/js/blur-images.js b/js/blur-images.js new file mode 100644 index 00000000..4e7aca1b --- /dev/null +++ b/js/blur-images.js @@ -0,0 +1,102 @@ +/* + * blur-images.js (edit of toggle-images.js) + * + * Released under the MIT license + * Copyright (c) 2012 Michael Save + * Copyright (c) 2013-2014 Marcin Ɓabanowski + * + * Usage: + * $config['additional_javascript'][] = 'js/jquery.min.js'; + * //$config['additional_javascript'][] = 'js/options.js'; + * //$config['additional_javascript'][] = 'js/style-select.js'; + * //$config['additional_javascript'][] = 'js/options/general.js'; + * $config['additional_javascript'][] = 'js/toggle-images.js'; + * + * Note: I put it immediately under options/general and make the opacity !important to ensure fast loading time + * Intended for anti-raid protection + */ + +$(document).ready(function(){ + var hide_images = localStorage['hideimages'] ? true : false; + + $('').appendTo($('head')); + + var hideImage = function() { + if ($(this).parent().data('expanded') == 'true') { + $(this).parent().click(); + } + $(this).addClass('hidden'); + }; + + var restoreImage = function() { + $(this) + .attr('src', $(this).attr('data-orig')) + .removeClass('hidden'); + }; + + // Fix for hide-images.js + var show_hide_hide_images_buttons = function() { + if (hide_images) { + $('a.hide-image-link').each(function() { + if ($(this).next().hasClass('show-image-link')) { + $(this).next().hide(); + } + $(this).hide().after(''+_('hidden')+''); + }); + } else { + $('span.toggle-images-placeholder').remove(); + $('a.hide-image-link').each(function() { + if ($(this).next().hasClass('show-image-link')) { + $(this).next().show(); + } else { + $(this).show(); + } + }); + } + }; + + var selector, event; + if (window.Options && Options.get_tab('general')) { + selector = '#toggle-images>input'; + event = 'change'; + Options.extend_tab("general", ""); + } + else { + selector = '#toggle-images a'; + event = 'click'; + $('hr:first').before(''); + $('div#toggle-images a') + .text(hide_images ? _('Show images') : _('Hide images')); + } + + $(selector) + .on(event, function() { + hide_images = !hide_images; + if (hide_images) { + $('img.post-image, .theme-catalog .thread>a>img').each(hideImage); + localStorage.hideimages = true; + } else { + $('img.post-image, .theme-catalog .thread>a>img').each(restoreImage); + delete localStorage.hideimages; + } + + show_hide_hide_images_buttons(); + + $(this).text(hide_images ? _('Show images') : _('Hide images')) + }); + + if (hide_images) { + $('img.post-image, .theme-catalog .thread>a>img').each(hideImage); + show_hide_hide_images_buttons(); + + if (window.Options && Options.get_tab('general')) { + $('#toggle-images>input').prop('checked', true); + } + } + + $(document).on('new_post', function(e, post) { + if (hide_images) { + $(post).find('img.post-image').each(hideImage); + } + }); +}); From 58d1e37c1a4cea9d5015eaab61959cf558d4dac4 Mon Sep 17 00:00:00 2001 From: tmp-server Date: Sat, 16 Oct 2021 02:34:44 +0000 Subject: [PATCH 13/74] Fix new thread notifications breaking script Tried to access invalid child. --- js/mod/recent-posts-auto-reload.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/mod/recent-posts-auto-reload.js b/js/mod/recent-posts-auto-reload.js index 0bad51bd..0db4ea62 100644 --- a/js/mod/recent-posts-auto-reload.js +++ b/js/mod/recent-posts-auto-reload.js @@ -220,7 +220,11 @@ $(document).ready(function(){ } // Notify on all posts, not just the first unread if (notify === "all") { - var body = $(this).children('.body').html().replace(//gi, "\n"); + if ($(this).hasClass('thread')){ + var body = $(this).children('.post').children('.body').html().replace(//gi, "\n"); + } else { + var body = $(this).children('.body').html().replace(//gi, "\n"); + } var n = new Notification("New reply to "+title, {body: $('
').html(body).text()}); } if ($("div.post,div.thread").length > 1){ From 78ab47d433b12cc96d00775ab19df5f702d6de9d Mon Sep 17 00:00:00 2001 From: discomrade Date: Sun, 17 Oct 2021 21:57:12 -0100 Subject: [PATCH 14/74] Correct notification text for threads --- js/mod/recent-posts-auto-reload.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/mod/recent-posts-auto-reload.js b/js/mod/recent-posts-auto-reload.js index 0db4ea62..c16d5fdb 100644 --- a/js/mod/recent-posts-auto-reload.js +++ b/js/mod/recent-posts-auto-reload.js @@ -222,10 +222,11 @@ $(document).ready(function(){ if (notify === "all") { if ($(this).hasClass('thread')){ var body = $(this).children('.post').children('.body').html().replace(//gi, "\n"); + var n = new Notification("New thread in "+title, {body: $('
').html(body).text()}); } else { var body = $(this).children('.body').html().replace(//gi, "\n"); + var n = new Notification("New reply to "+title, {body: $('
').html(body).text()}); } - var n = new Notification("New reply to "+title, {body: $('
').html(body).text()}); } if ($("div.post,div.thread").length > 1){ $(this).parent().insertBefore($($('div.post,div.thread').not('.post-hover').first()).parent()); From d7b8e9a22b4b7d95cb938838fd416e9ab27c34b6 Mon Sep 17 00:00:00 2001 From: discomrade Date: Wed, 27 Oct 2021 20:29:31 +0000 Subject: [PATCH 15/74] Add PFLP, Socrates flags --- static/flags/pflp.png | Bin 0 -> 958 bytes static/flags/socrates.png | Bin 0 -> 788 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/flags/pflp.png create mode 100644 static/flags/socrates.png diff --git a/static/flags/pflp.png b/static/flags/pflp.png new file mode 100644 index 0000000000000000000000000000000000000000..c2df326052f462bf096cabe4951e369c513881da GIT binary patch literal 958 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6XVU3I`u#fXMsm#F#`j) zFbFd;%$g$sRIn|;C&U#f`5!-GWBYGy{lBK>|C~Ah=gs@y*!bVs`9CKoLYK7k{{;*F z|N8a+|Np;_9)0%k_?Dml=j_@4>(~ERQ-dm#lKOw@)c?PKzh-8BD=Yi={{4GF!FLP{ z@42|Xm6rZHapJ$GCP*b4+rM}3-Z3(Mkdk^YB=nA*{aaz--zQK0^Y8#=fA8A$$;9M? zxcGZ9vHyXAAoc(LeGLx&QC|MZ-2Bg#D?gVn|Lp1cB{C9X>7Q%YJ}E2zdG_pkcJ>!T z!_R(xU$e9S-o5+p!-sDL1rRm=K7an~;_~~!gTHUz{=IPF@A>oJii!hr-oE`o zUjB1p;?Ip6zowa&jzNbjFNf3IKvAT0c&ukU+({hu>uzSq{iV`2Fp z6$LT*|Ar0kt*zhN*?mb!_%A3361;x>-=|L>H8j2gMU0LA0~G@Wfk;d1|BfA>eSQC4 zx$@uE_CG7@e-4iSQ>Xsjv*&+kC@2giBtRlSl|Y8J_J4W#9DVIez?hp<666=mpuFhr zk6({g>kCi(1dIY8__k1b-#-WwNM4Xdu>b#G`4KAd(+)Y8Pl%*y!K zI37HC^z7l&$KnDaLSl@cU5_47Rav?uHRb6OQISTb7_U=WtFm56&5F8ZwX4eE@2^K% zY;A6@j?J2-wk++L7|$Uap-Izb&3YAf&1{xh+O{&DGkYd|)qM?|9^D zCe4eRbA0zXKNN&Qh&hnws`hl!xcgr>T=dXT7>Q>!)ej*3z#$ zJiJ`JzTeVbojseTyEgZ&!g-BXGjEs8m|0p@`u&U3-|UOeWP)fv8gO1E8Ryqew?ZgAl&}QBWaK zf{+3NghC!poQLe#u|vGEV;eiW>wS11j3Xf>8*{6fqx+p1&AG#r@+D~3UC$lqC z$AX_x5{niRa~!VU&s`Y^-lXsWs`x3ei#a9meyQ25=yXa^_w8eT&I- z<`o>{v7wrrMpN~DVD{QHHa7}hjBsz%j=DI|kmb(IVZYCIfu~`fq_Qg?=W5CUhUElo znz$fvl~|a2M0>ge4cj$327}9?@_c4|;%Y}#rvyQ8532`+<3gVpNjQ`4Ka0Oi>Q4ro S4yIB70000 Date: Thu, 28 Oct 2021 01:37:52 -0100 Subject: [PATCH 16/74] Prevent blur-images.js interfereing with regular hiding images --- js/blur-images.js | 82 +++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/js/blur-images.js b/js/blur-images.js index 4e7aca1b..4a603d68 100644 --- a/js/blur-images.js +++ b/js/blur-images.js @@ -17,36 +17,36 @@ */ $(document).ready(function(){ - var hide_images = localStorage['hideimages'] ? true : false; + var blur_images = localStorage['blurimages'] ? true : false; - $('').appendTo($('head')); + $('').appendTo($('head')); - var hideImage = function() { + var blurImage = function() { if ($(this).parent().data('expanded') == 'true') { $(this).parent().click(); } - $(this).addClass('hidden'); + $(this).addClass('blur'); }; var restoreImage = function() { $(this) .attr('src', $(this).attr('data-orig')) - .removeClass('hidden'); + .removeClass('blur'); }; // Fix for hide-images.js - var show_hide_hide_images_buttons = function() { - if (hide_images) { - $('a.hide-image-link').each(function() { - if ($(this).next().hasClass('show-image-link')) { + var show_hide_blur_images_buttons = function() { + if (blur_images) { + $('a.blur-image-link').each(function() { + if ($(this).next().hasClass('unblur-image-link')) { $(this).next().hide(); } - $(this).hide().after(''+_('hidden')+''); + $(this).hide().after(''+_('hidden')+''); }); } else { - $('span.toggle-images-placeholder').remove(); - $('a.hide-image-link').each(function() { - if ($(this).next().hasClass('show-image-link')) { + $('span.blur-images-placeholder').remove(); + $('a.blur-image-link').each(function() { + if ($(this).next().hasClass('unblur-image-link')) { $(this).next().show(); } else { $(this).show(); @@ -55,48 +55,48 @@ $(document).ready(function(){ } }; - var selector, event; - if (window.Options && Options.get_tab('general')) { - selector = '#toggle-images>input'; - event = 'change'; - Options.extend_tab("general", ""); - } - else { - selector = '#toggle-images a'; - event = 'click'; - $('hr:first').before(''); - $('div#toggle-images a') - .text(hide_images ? _('Show images') : _('Hide images')); - } + var selector, event; + if (window.Options && Options.get_tab('general')) { + selector = '#blur-images>input'; + event = 'change'; + Options.extend_tab("general", ""); + } + else { + selector = '#blur-images a'; + event = 'click'; + $('hr:first').before(''); + $('div#blur-images a') + .text(blur_images ? _('Unblur images') : _('Blur images')); + } $(selector) .on(event, function() { - hide_images = !hide_images; - if (hide_images) { - $('img.post-image, .theme-catalog .thread>a>img').each(hideImage); - localStorage.hideimages = true; + blur_images = !blur_images; + if (blur_images) { + $('img.post-image, .theme-catalog .thread>a>img').each(blurImage); + localStorage.blurimages = true; } else { $('img.post-image, .theme-catalog .thread>a>img').each(restoreImage); - delete localStorage.hideimages; + delete localStorage.blurimages; } - show_hide_hide_images_buttons(); + show_hide_blur_images_buttons(); - $(this).text(hide_images ? _('Show images') : _('Hide images')) + $(this).text(blur_images ? _('Unblur images') : _('Blur images')) }); - if (hide_images) { - $('img.post-image, .theme-catalog .thread>a>img').each(hideImage); - show_hide_hide_images_buttons(); + if (blur_images) { + $('img.post-image, .theme-catalog .thread>a>img').each(blurImage); + show_hide_blur_images_buttons(); - if (window.Options && Options.get_tab('general')) { - $('#toggle-images>input').prop('checked', true); - } + if (window.Options && Options.get_tab('general')) { + $('#toggle-images>input').prop('checked', true); + } } $(document).on('new_post', function(e, post) { - if (hide_images) { - $(post).find('img.post-image').each(hideImage); + if (blur_images) { + $(post).find('img.post-image').each(blurImage); } }); }); From b1485a14b56804629699f32d4e6fb719b5acf125 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 5 Nov 2021 10:05:10 -0100 Subject: [PATCH 17/74] Rename temporary themes --- stylesheets/{temp_dark.css => dark_bunker.css} | 0 stylesheets/{temp_dark_red.css => dark_bunker_red.css} | 0 stylesheets/{demain_dark.css => demain.css} | 0 stylesheets/{anons_dark_red.css => demain_classic.css} | 0 stylesheets/{demain_light.css => muted.css} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename stylesheets/{temp_dark.css => dark_bunker.css} (100%) rename stylesheets/{temp_dark_red.css => dark_bunker_red.css} (100%) rename stylesheets/{demain_dark.css => demain.css} (100%) rename stylesheets/{anons_dark_red.css => demain_classic.css} (100%) rename stylesheets/{demain_light.css => muted.css} (100%) diff --git a/stylesheets/temp_dark.css b/stylesheets/dark_bunker.css similarity index 100% rename from stylesheets/temp_dark.css rename to stylesheets/dark_bunker.css diff --git a/stylesheets/temp_dark_red.css b/stylesheets/dark_bunker_red.css similarity index 100% rename from stylesheets/temp_dark_red.css rename to stylesheets/dark_bunker_red.css diff --git a/stylesheets/demain_dark.css b/stylesheets/demain.css similarity index 100% rename from stylesheets/demain_dark.css rename to stylesheets/demain.css diff --git a/stylesheets/anons_dark_red.css b/stylesheets/demain_classic.css similarity index 100% rename from stylesheets/anons_dark_red.css rename to stylesheets/demain_classic.css diff --git a/stylesheets/demain_light.css b/stylesheets/muted.css similarity index 100% rename from stylesheets/demain_light.css rename to stylesheets/muted.css From d6a8dca27e00804aaad637f9c7ffd2a60e447fef Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 5 Nov 2021 11:51:39 -0100 Subject: [PATCH 18/74] Make select elements consistent with forms --- stylesheets/dark_bunker.css | 2 +- stylesheets/dark_bunker_red.css | 2 +- stylesheets/demain.css | 2 +- stylesheets/demain_classic.css | 2 +- stylesheets/gentoochan.css | 2 +- stylesheets/gurochan.css | 2 +- stylesheets/muted.css | 2 +- stylesheets/szalet.css | 2 +- stylesheets/yotsuba.css | 3 +++ 9 files changed, 11 insertions(+), 8 deletions(-) diff --git a/stylesheets/dark_bunker.css b/stylesheets/dark_bunker.css index 9cbaa129..c291404f 100644 --- a/stylesheets/dark_bunker.css +++ b/stylesheets/dark_bunker.css @@ -61,7 +61,7 @@ form table tr th { border: 1px solid #117743; } /* Input fields */ -textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"] { +textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"], select { color: #ACACAC; background: #282A2E; border: 1px double #07371F; diff --git a/stylesheets/dark_bunker_red.css b/stylesheets/dark_bunker_red.css index a9d28fa7..1b9b3489 100644 --- a/stylesheets/dark_bunker_red.css +++ b/stylesheets/dark_bunker_red.css @@ -61,7 +61,7 @@ form table tr th { border: 1px solid #cd0000; } /* Input fields */ -textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"] { +textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"], select { color: #ACACAC; background: #282A2E; border: 1px double #07371F; diff --git a/stylesheets/demain.css b/stylesheets/demain.css index 057cb40e..df8f6318 100644 --- a/stylesheets/demain.css +++ b/stylesheets/demain.css @@ -95,7 +95,7 @@ form table tr th { border: 1px solid #373b41; } /* Input fields */ -textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"] { +textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"], select { color: #ACACAC; background: #282A2E; border: 1px double #1d1f21; diff --git a/stylesheets/demain_classic.css b/stylesheets/demain_classic.css index 97f3f490..ea290c47 100644 --- a/stylesheets/demain_classic.css +++ b/stylesheets/demain_classic.css @@ -60,7 +60,7 @@ form table tr th { border: 1px solid #373b41; } /* Input fields */ -textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"] { +textarea, input:not([type="file"]):not([type="checkbox"]), [type="submit"], select { color: #ACACAC; background: #282A2E; border: 1px double #1d1f21; diff --git a/stylesheets/gentoochan.css b/stylesheets/gentoochan.css index 93111b3f..49fa8a77 100644 --- a/stylesheets/gentoochan.css +++ b/stylesheets/gentoochan.css @@ -18,7 +18,7 @@ a.post_no { .boardlist { color: #ccc; } -div.post.reply, input, textarea { +div.post.reply, input, textarea, select { background: rgba(0, 0, 0, 0.1); border: 1px solid rgba(0, 0, 0, 0.2); border-radius: 2px; diff --git a/stylesheets/gurochan.css b/stylesheets/gurochan.css index d763f5f0..45119baa 100644 --- a/stylesheets/gurochan.css +++ b/stylesheets/gurochan.css @@ -7,7 +7,7 @@ html, body { font-family: Tahoma, Verdana, Arial, sans-serif; font-size: 10pt; } -input, textarea { +input, textarea, select { background-color: #E6CBC0; border: 1px solid #CA927B; } diff --git a/stylesheets/muted.css b/stylesheets/muted.css index bd4516d8..c0d00ecb 100644 --- a/stylesheets/muted.css +++ b/stylesheets/muted.css @@ -115,7 +115,7 @@ form table tr th { /* Input fields */ textarea, input:not([type="file"]):not([type="checkbox"]), -[type="submit"] { +[type="submit"], select { color: #4c4c4c; background: #e9eced; border: 1px double #cccccc; diff --git a/stylesheets/szalet.css b/stylesheets/szalet.css index 77a216a6..88f7d094 100644 --- a/stylesheets/szalet.css +++ b/stylesheets/szalet.css @@ -48,7 +48,7 @@ input { textarea { background: #dedede url('img/testorange_textarea_bg.gif') repeat-x; } -input, textarea { +input, textarea, select { background: #200000; color: #99938D; } diff --git a/stylesheets/yotsuba.css b/stylesheets/yotsuba.css index 4ec557b9..e5adf7f1 100644 --- a/stylesheets/yotsuba.css +++ b/stylesheets/yotsuba.css @@ -30,6 +30,9 @@ form table tr th { color: #800000; border: 1px solid #800000; } +[type="submit"] { + border: 1px solid #9A9A9A; +} textarea:focus, input:not([type="file"]):not([type="checkbox"]):focus, [type="submit"]:hover { border: 1px solid #EA8; } From abe5dfa1711fd0f8fe3ab5dc525c894ccb3a2335 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 11 Nov 2021 07:10:32 -0100 Subject: [PATCH 19/74] Remove roulette oekaki hack --- roulette/config.php | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 roulette/config.php diff --git a/roulette/config.php b/roulette/config.php deleted file mode 100644 index 4e42fd23..00000000 --- a/roulette/config.php +++ /dev/null @@ -1,14 +0,0 @@ - Date: Thu, 11 Nov 2021 09:42:03 -0100 Subject: [PATCH 20/74] Revert attempt at deferring file selector Reverts most of https://git.leftypol.org/leftypol/leftypol/commit/ab8b4b95249ab0cfb364cac1dddb267005099a29 which failed to remove the previous file uploader https://git.leftypol.org/leftypol/leftypol/issues/37 --- js/file-selector.js | 4 ---- templates/post_form.html | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/js/file-selector.js b/js/file-selector.js index 2d347b3b..19c4b0c0 100644 --- a/js/file-selector.js +++ b/js/file-selector.js @@ -191,7 +191,3 @@ $(document).ready(function () { } }); -$(document).ready(function () { - var maxImages = document.querySelector("form[name=post]").dataset.maxImages; - init_file_selector(Number(maxImages)); -}); diff --git a/templates/post_form.html b/templates/post_form.html index bf02ad1a..5cbe0d35 100644 --- a/templates/post_form.html +++ b/templates/post_form.html @@ -148,6 +148,8 @@ + + {% if config.allow_upload_by_url %}
: From fb349c4f5886955b1d1bb4a417813ced6f210242 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 11 Nov 2021 10:43:18 -0100 Subject: [PATCH 21/74] Concatenate dark.css to dark_red.css to improve performance --- stylesheets/dark_red.css | 237 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 228 insertions(+), 9 deletions(-) diff --git a/stylesheets/dark_red.css b/stylesheets/dark_red.css index 915f5600..3e252380 100644 --- a/stylesheets/dark_red.css +++ b/stylesheets/dark_red.css @@ -1,14 +1,7 @@ /** - * dark.css, red extension - * Clumps all rules into three rules to determine the new accent color + * dark.css, red accent */ -@import url("/stylesheets/dark.css"); - -span.quote { - /* color:#D96262; */ -} - div.blotter, h1, h2, header div.subtitle, div.title, a:link:hover, a:visited:hover p.intro a.post_no:hover, div.post.reply div.body a:link:hover, div.post.reply div.body a:visited:hover, p.intro span.name, p.intro a.email, p.intro a.email span.name, p.intro a.email:hover, p.intro a.email:hover span.name, @@ -17,5 +10,231 @@ input[type="submit"]:hover, div.ban h2 { } p.intro span.subject { - color: #962C22; /*old #664445 */ + color: #962C22; +} + +/*dark.css has been appended (2021-11-11) instead of @import'd for performance*/ +body { + background: #1E1E1E; + color: #999999; + font-family: Verdana, sans-serif; + font-size: 14px; +} +.quote { + color:#B8D962; +} +@font-face { + font-family: 'lain'; + src: url('./fonts/nrdyyh.woff') format('woff'), + url('./fonts/tojcxo.TTF') format('truetype'); +} +h1 +{ + letter-spacing: -2px; + font-size: 20pt; + text-align: center; + color: #32DD72; +} +div.title, h1 { + color: #32DD72; +} +div.title p { + font-size: 10px; +} +a:link, a:visited, .intro a.email span.name { + color: #CCCCCC; + text-decoration: none; + font-family: sans-serif; +} +a:link:hover, a:visited:hover { + color: #fff; + font-family: sans-serif; + text-decoration: none; +} +a.post_no { + color: #AAAAAA; + text-decoration: none; +} +a.post_no:hover { + color: #32DD72 !important; + text-decoration: underline overline; +} +div.post.reply { + background: #333333; + border: #555555 1px solid; +} +div.post.reply.highlighted { + background: #555; + border: transparent 1px solid; +} +div.post.reply div.body a:link, div.post.reply div.body a:visited { + color: #CCCCCC; +} +div.post.reply div.body a:link:hover, div.post.reply div.body a:visited:hover { + color: #32DD72; +} +.intro span.subject { + font-size: 12px; + font-family: sans-serif; + color: #446655; + font-weight: 800; +} +.intro span.name { + color: #32DD72; + font-weight: 800; +} +.intro a.capcode, p.intro a.nametag { + color: magenta; + margin-left: 0; +} +.intro a.email, p.intro a.email span.name, p.intro a.email:hover, p.intro a.email:hover span.name { + color: #32ddaf; +} +input[type="text"], textarea, select { + background: #333333; + color: #CCCCCC; + border: #666666 1px solid; + padding-left: 5px; + padding-right: -5px; + font-family: sans-serif; + font-size: 10pt; +} +input[type="password"] { + background: #333333; + color: #CCCCCC; + border: #666666 1px solid; +} +form table tr th { + background: #333333; + color: #AAAAAA; + font-weight: 800; + text-align: left; + padding: 0; +} +div.banner { + background: #32DD72; + color: #000; + text-align: center; + width: 250px; + padding: 4px; + padding-left: 12px; + padding-right: 12px; + margin-left: auto; + margin-right: auto; + font-size: 12px; +} +div.banner a { + color:#000; +} +input[type="submit"] { + background: #333333; + border: #888888 1px solid; + color: #CCCCCC; +} +input[type="submit"]:hover { + background: #555555; + border: #888888 1px solid; + color: #32DD72; +} +input[type="text"]:focus { + border:#aaa 1px solid; +} +p.fileinfo a:hover { + text-decoration: underline; +} +span.trip { + color: #AAAAAA; +} +div.pages { + background: #1E1E1E; + font-family: sans-serif; +} +.bar.bottom { + bottom: 0px; + border-top: 1px solid #333333; + background-color: #1E1E1E; +} +div.pages a.selected { + color: #CCCCCC; +} +hr { + height: 1px; + border: #333333 1px solid; +} +div.boardlist { + text-align: center; + color: #999999; +} +div.ban { + background-color: transparent; + border: transparent 0px solid; +} +div.ban h2 { + background: transparent; + color: lime; + font-size: 12px; +} +table.modlog tr th { + background: #333333; + color: #AAAAAA; +} +div.boardlist:not(.bottom) { + background-color: #1E1E1E; + +} +.desktop-style div.boardlist:not(.bottom) { + position:static; + text-shadow: black 1px 1px 1px, black -1px -1px 1px, black -1px 1px 1px, black 1px -1px 1px; + color: #999999; + background-color: #1E1E1E; +} +div.report { + color: #666666; +} +#options_div, #alert_div { + background: #333333; +} +.options_tab_icon { + color: #AAAAAA; +} +.options_tab_icon.active { + color: #FFFFFF; +} +#quick-reply table { + background: none repeat scroll 0% 0% #333 !important; +} +.modlog tr:nth-child(even), .modlog th { + background-color: #282A2E; +} +.box { + background: #333333; + border-color: #555555; + color: #C5C8C6; + border-radius: 10px; +} +.box-title { + background: transparent; + color: #32DD72; +} +table thead th { + background: #333333; + border-color: #555555; + color: #C5C8C6; + border-radius: 4px; +} +table tbody tr:nth-of-type( even ) { + background-color: #333333; +} +table.board-list-table .board-uri .board-sfw { + color: #CCCCCC; +} +tbody.board-list-omitted td { + background: #333333; + border-color: #555555; +} +table.board-list-table .board-tags .board-cell:hover { + background: #1e1e1e; +} +table.board-list-table tr:nth-of-type( even ) .board-tags .board-cell { + background: #333333; } From c9c36158803affb194c0768e64ade936b5ffd120 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 11 Nov 2021 11:59:13 -0100 Subject: [PATCH 22/74] Fix ordering in previous change --- stylesheets/dark_red.css | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/stylesheets/dark_red.css b/stylesheets/dark_red.css index 3e252380..ba7908ce 100644 --- a/stylesheets/dark_red.css +++ b/stylesheets/dark_red.css @@ -2,18 +2,7 @@ * dark.css, red accent */ -div.blotter, h1, h2, header div.subtitle, div.title, a:link:hover, a:visited:hover p.intro a.post_no:hover, -div.post.reply div.body a:link:hover, div.post.reply div.body a:visited:hover, p.intro span.name, -p.intro a.email, p.intro a.email span.name, p.intro a.email:hover, p.intro a.email:hover span.name, -input[type="submit"]:hover, div.ban h2 { - color: #DD3232; -} - -p.intro span.subject { - color: #962C22; -} - -/*dark.css has been appended (2021-11-11) instead of @import'd for performance*/ +/*dark.css has been prepended (2021-11-11) instead of @import'd for performance*/ body { background: #1E1E1E; color: #999999; @@ -238,3 +227,14 @@ table.board-list-table .board-tags .board-cell:hover { table.board-list-table tr:nth-of-type( even ) .board-tags .board-cell { background: #333333; } +/* red accents */ +div.blotter, h1, h2, header div.subtitle, div.title, a:link:hover, a:visited:hover p.intro a.post_no:hover, +div.post.reply div.body a:link:hover, div.post.reply div.body a:visited:hover, p.intro span.name, +p.intro a.email, p.intro a.email span.name, p.intro a.email:hover, p.intro a.email:hover span.name, +input[type="submit"]:hover, div.ban h2 { + color: #DD3232; +} + +p.intro span.subject { + color: #962C22; +} \ No newline at end of file From e1b83ec5480fbb02178b77d0b4fee704b012efd8 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 11 Nov 2021 13:06:19 -0100 Subject: [PATCH 23/74] Call upload-selection.js inline Makes the change happen earlier, reducing content shift --- js/upload-selection.js | 6 +++--- templates/post_form.html | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/js/upload-selection.js b/js/upload-selection.js index b342a134..c40b3383 100644 --- a/js/upload-selection.js +++ b/js/upload-selection.js @@ -9,10 +9,10 @@ * $config['additional_javascript'][] = 'js/jquery.min.js'; * //$config['additional_javascript'][] = 'js/wpaint.js'; * $config['additional_javascript'][] = 'js/upload-selection.js'; - * + * */ -$(function(){ +function init_upload_selection(){ var enabled_file = true; var enabled_url = $("#upload_url").length > 0; var enabled_embed = $("#upload_embed").length > 0; @@ -84,4 +84,4 @@ $(function(){ enable_file(); } -}); +} diff --git a/templates/post_form.html b/templates/post_form.html index 5cbe0d35..cff1c03a 100644 --- a/templates/post_form.html +++ b/templates/post_form.html @@ -210,6 +210,9 @@ +{% if 'js/upload-selection.js' in config.additional_javascript %} + +{% endif %} From 409fbdf24afbafd0b48753b37404256b7157ea46 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 11 Nov 2021 13:07:32 -0100 Subject: [PATCH 24/74] Make file-selector.js inline call conditional --- templates/post_form.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/post_form.html b/templates/post_form.html index cff1c03a..1d77443a 100644 --- a/templates/post_form.html +++ b/templates/post_form.html @@ -148,7 +148,10 @@ + {% if 'js/file-selector.js' in config.additional_javascript %} + {% endif %} + {% if config.allow_upload_by_url %}
From ba6b4f1bab1f16eee262a9b35662d10d700f5c2f Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 12 Nov 2021 03:37:23 -0100 Subject: [PATCH 25/74] Tidy up theme.php --- templates/themes/categories/theme.php | 126 +++++++++++++------------- 1 file changed, 63 insertions(+), 63 deletions(-) diff --git a/templates/themes/categories/theme.php b/templates/themes/categories/theme.php index 22a0905d..15cf77de 100644 --- a/templates/themes/categories/theme.php +++ b/templates/themes/categories/theme.php @@ -35,9 +35,9 @@ public static function homepage($settings) { global $config; $description = "Leftypol is an imageboard where users can post anonymously.
We engage in both serious political discourse and informal discussion on various topics related to leftist thought.

They are... an interesting group of people - Senpai Wolff "; - $metadescription = "Leftypol is an imageboard where users can post anonymously about both serious political discourse and informal discussion on various topics related to leftist thought."; + $metadescription = "Leftypol is an imageboard where users can post anonymously about both serious political discourse and informal discussion on various topics related to leftist thought."; $metaextra = ''. -''; +''; // other sites should delete this! $query = query("SELECT * FROM ``news`` ORDER BY `time` DESC") or error(db_error()); $news = $query->fetchAll(PDO::FETCH_ASSOC); $stats = Categories::getPostStatistics($settings); @@ -100,67 +100,67 @@ return $categories; } - private static function getPostStatistics($settings) { - global $config; - - if (!isset($config['boards'])) { - return null; - } - - $HOUR = 3600; - $DAY = $HOUR * 24; - $WEEK = $DAY * 7; - - $stats = []; - $hourly = []; - $daily = []; - $weekly = []; - - foreach (array_merge(... $config['boards']) as $uri) { - $_board = getBoardInfo($uri); - if (!$_board) { - // board doesn't exist. - continue; - } - - $boardStat['title'] = $_board['title']; - - $boardStat['hourly_ips'] = Categories::countUniqueIps($hourly, $HOUR, $_board); - $boardStat['daily_ips'] = Categories::countUniqueIps($daily, $DAY, $_board); - $boardStat['weekly_ips'] = Categories::countUniqueIps($weekly, $WEEK, $_board); - - $pph_query = query( - sprintf("SELECT COUNT(*) AS count FROM ``posts_%s`` WHERE time > %d", - $_board['uri'], - time()-3600) - ) or error(db_error()); - - $boardStat['pph'] = $pph_query->fetch()['count']; - - $stats['boards'][] = $boardStat; - } - - $stats['hourly_ips'] = count($hourly); - $stats['daily_ips'] = count($daily); - $stats['weekly_ips'] = count($weekly); - $stats['pph'] = array_sum(array_column($stats['boards'], 'pph')); - - return $stats; - } - - private static function countUniqueIps(&$markAsCounted, $timespan, $_board) { - $unique_query = query( - sprintf("SELECT DISTINCT ip FROM ``posts_%s`` WHERE time > %d", - $_board['uri'], - time()-$timespan) - ) or error(db_error()); - $uniqueIps = $unique_query->fetchAll(); - foreach ($uniqueIps as $_k => $row) { - $markAsCounted[$row['ip']] = true; - } - - return count($uniqueIps); - } + private static function getPostStatistics($settings) { + global $config; + + if (!isset($config['boards'])) { + return null; + } + + $HOUR = 3600; + $DAY = $HOUR * 24; + $WEEK = $DAY * 7; + + $stats = []; + $hourly = []; + $daily = []; + $weekly = []; + + foreach (array_merge(... $config['boards']) as $uri) { + $_board = getBoardInfo($uri); + if (!$_board) { + // board doesn't exist. + continue; + } + + $boardStat['title'] = $_board['title']; + + $boardStat['hourly_ips'] = Categories::countUniqueIps($hourly, $HOUR, $_board); + $boardStat['daily_ips'] = Categories::countUniqueIps($daily, $DAY, $_board); + $boardStat['weekly_ips'] = Categories::countUniqueIps($weekly, $WEEK, $_board); + + $pph_query = query( + sprintf("SELECT COUNT(*) AS count FROM ``posts_%s`` WHERE time > %d", + $_board['uri'], + time()-3600) + ) or error(db_error()); + + $boardStat['pph'] = $pph_query->fetch()['count']; + + $stats['boards'][] = $boardStat; + } + + $stats['hourly_ips'] = count($hourly); + $stats['daily_ips'] = count($daily); + $stats['weekly_ips'] = count($weekly); + $stats['pph'] = array_sum(array_column($stats['boards'], 'pph')); + + return $stats; + } + + private static function countUniqueIps(&$markAsCounted, $timespan, $_board) { + $unique_query = query( + sprintf("SELECT DISTINCT ip FROM ``posts_%s`` WHERE time > %d", + $_board['uri'], + time()-$timespan) + ) or error(db_error()); + $uniqueIps = $unique_query->fetchAll(); + foreach ($uniqueIps as $_k => $row) { + $markAsCounted[$row['ip']] = true; + } + + return count($uniqueIps); + } }; ?> From 61199734988e5f8188fc69a1f52d5fbb3d9831c4 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 12 Nov 2021 03:37:30 -0100 Subject: [PATCH 26/74] Move logo to config variable --- templates/themes/faq/index.html | 2 +- templates/themes/rules/rules.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/themes/faq/index.html b/templates/themes/faq/index.html index e91ad7b8..634ff36b 100644 --- a/templates/themes/faq/index.html +++ b/templates/themes/faq/index.html @@ -21,7 +21,7 @@

{{ settings.title }}

{{ settings.subtitle }}
-
logo
+
logo

My question isn't here. What do I do ? diff --git a/templates/themes/rules/rules.html b/templates/themes/rules/rules.html index a1a33e5d..956ec476 100755 --- a/templates/themes/rules/rules.html +++ b/templates/themes/rules/rules.html @@ -21,7 +21,7 @@
- logo + logo
{% include 'rules.html' %} From 44a2a569d12706db51c0b74970b8f9503cc17e34 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 12 Nov 2021 04:18:46 -0100 Subject: [PATCH 27/74] Move logo to default location --- static/{leftypol_logo.png => logo.png} | Bin 1 file changed, 0 insertions(+), 0 deletions(-) rename static/{leftypol_logo.png => logo.png} (100%) diff --git a/static/leftypol_logo.png b/static/logo.png similarity index 100% rename from static/leftypol_logo.png rename to static/logo.png From ca9a85e9f1801e7211a695143286445e5b910356 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 12 Nov 2021 04:50:47 -0100 Subject: [PATCH 28/74] Improve page titles and social media cards --- templates/index.html | 15 ++++++++++++++- templates/themes/categories/frames.html | 9 +++++++++ templates/thread.html | 3 +++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/templates/index.html b/templates/index.html index 0b48979a..db04fa05 100644 --- a/templates/index.html +++ b/templates/index.html @@ -15,7 +15,20 @@ {% include 'header.html' %} - {{ board.url }} - {{ board.title|e }} + {% set page_num %}{% for page in pages %}{% if page.selected %}{% if page.num != 1 %}{{ page.num }}{% endif %}{% endif %}{% endfor %}{% endset %} + {% set meta_subject %}{{ board.subtitle|newline_to_full_stop|e }}{% endset %} + + + + + + + + + + + + {{ board.url }} - {{ board.title|e }}{% if page_num %} - Page {{ page_num }}{% endif %}
diff --git a/templates/themes/categories/frames.html b/templates/themes/categories/frames.html index babb5da6..6b2fac38 100644 --- a/templates/themes/categories/frames.html +++ b/templates/themes/categories/frames.html @@ -123,6 +123,15 @@ {{ settings.title }} + + + + + + + + + {{ metaextra }} diff --git a/templates/thread.html b/templates/thread.html index eab2178a..dec9952c 100644 --- a/templates/thread.html +++ b/templates/thread.html @@ -17,6 +17,9 @@ + + + {% if thread.files.0.thumb %}{% endif %} From 4febc6aa77aafca431ecc3bbc68d828e502429d6 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 12 Nov 2021 10:21:39 -0100 Subject: [PATCH 29/74] Make bans default to board of offending post --- templates/mod/ban_form.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/mod/ban_form.html b/templates/mod/ban_form.html index b79c8ee1..8bc4a5c8 100644 --- a/templates/mod/ban_form.html +++ b/templates/mod/ban_form.html @@ -69,17 +69,17 @@
  • - +
  • - {% for board in boards %} + {% for b in boards %}
  • - -
  • {% endfor %} From ab366688c8dcc5981c4cb3f38f3e97c21597e50a Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 12 Nov 2021 10:26:48 -0100 Subject: [PATCH 30/74] Add default ban length of 1 hour instead of permanent ban --- templates/mod/ban_form.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/mod/ban_form.html b/templates/mod/ban_form.html index 8bc4a5c8..1f940ff8 100644 --- a/templates/mod/ban_form.html +++ b/templates/mod/ban_form.html @@ -61,8 +61,8 @@ - - (eg. "2d1h30m" or "2 days") + + (eg. "2d1h30m" or "2 days", empty is permaban) {% trans 'Board' %} From f62d9c6a966415a2b21cee7e32c0a494f7ebb859 Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 15 Nov 2021 05:56:32 -0100 Subject: [PATCH 31/74] Only add drag-drop handlers to dropzone, not the entire document This enables dragging text into the textbox. --- js/file-selector.js | 66 +++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/js/file-selector.js b/js/file-selector.js index 19c4b0c0..cee52f19 100644 --- a/js/file-selector.js +++ b/js/file-selector.js @@ -86,43 +86,39 @@ $(document).on('ajax_after_post', function () { }); var dragCounter = 0; -var dropHandlers = { - dragenter: function (e) { - e.stopPropagation(); - e.preventDefault(); - - if (dragCounter === 0) $('.dropzone').addClass('dragover'); - dragCounter++; - }, - dragover: function (e) { - // needed for webkit to work - e.stopPropagation(); - e.preventDefault(); - }, - dragleave: function (e) { - e.stopPropagation(); - e.preventDefault(); - - dragCounter--; - if (dragCounter === 0) $('.dropzone').removeClass('dragover'); - }, - drop: function (e) { - e.stopPropagation(); - e.preventDefault(); - - $('.dropzone').removeClass('dragover'); - dragCounter = 0; - - var fileList = e.originalEvent.dataTransfer.files; - for (var i=0; i Date: Sun, 28 Nov 2021 00:28:49 +0000 Subject: [PATCH 32/74] Quick hack to prevent oversized PDF thumbnails. --- post.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/post.php b/post.php index fc2a2583..41e93165 100644 --- a/post.php +++ b/post.php @@ -1112,7 +1112,7 @@ function handle_post(){ if (($file['extension'] == "pdf" && $config['pdf_file_thumbnail']) || ($file['extension'] == "djvu" && $config['djvu_file_thumbnail']) ){ $path = $file['thumb']; - $error = shell_exec_error( 'convert -thumbnail x300 -background white -alpha remove ' . + $error = shell_exec_error( 'convert -size '.$config['thumb_width'].'x'.$config['thumb_height'].' -thumbnail '.$config['thumb_width'].'x'.$config['thumb_height'].' -background white -alpha remove ' . escapeshellarg($file['tmp_name']. '[0]') . ' ' . escapeshellarg($file['thumb'])); From 2a105dc5870b03448328a709a6dfda564d688ba4 Mon Sep 17 00:00:00 2001 From: discomrade Date: Tue, 7 Dec 2021 00:15:32 -0100 Subject: [PATCH 33/74] Update site rules --- templates/rules.html | 125 ++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 66 deletions(-) diff --git a/templates/rules.html b/templates/rules.html index dd158c7c..e152d682 100644 --- a/templates/rules.html +++ b/templates/rules.html @@ -8,70 +8,63 @@

    RULES -


    - The rules for users are defined in our /leftypol/ Manifesto. Below is a summary. -
      -
    1. Anyone posting child pornography will immediately face a permanent ban and their IP will be logged and recorded to - be handed over to the authorities (if this is ever required).
      Content which ‘doxxes’ another user - or person will also be removed.
      Other content which promotes or endorses illegal activity may be - removed at the discretion of the moderators.

    2. -
    3. No spam. Spam from a bot is subject to a permanent ban or more severe actions - to preserve site security. Spam from a user may also be subject to a ban.

    4. -
    5. Pornography should not be posted on /leftypol/ or /meta/ without good reason. In addition, - images which are excessively offensive to the eye or to civilised sensibilities may be removed - without warning (for example, gore, shock images) and punished with moderator action.

    6. -
    7. Posts should, overall, be conducive to an informed and productive discussion. /leftypol/ is not an - academic journal, but it also should not be a cesspit of back and forth bickering and pointless - insults. Users should attempt to argue for the point they are presenting in an honest and open - way and should be receptive to information or arguments that do, in fact, challenge their views. - Reactionism and liberalism, or any other kind of non-leftist positions are not banned per se, as - we will endeavour to allow and encourage people of other political philosophies to explore - leftism through /leftypol/ so long as they follow the rules contained herein. However, non-leftist - users are ultimately to be considered ‘guests’ and thus will be removed if they prove a nuisance - or disrupt the normal functioning of the site.

    8. -
    9. In addition, /leftypol/ is committed to the ideal of left unity, or at least that the left should have - an avenue for open discussion, so all ‘mainstream’ leftist ideologies will be permitted (so long as - they do not violate the conditions set out in Article 1). /leftypol/ does not adhere to a specific - leftist ideology.

    10. -
    11. To ensure a basic level of quality, topics or posts will not be tolerated when contributions are not - conductive to well-intentioned discussion. Therefore, posts or topics are likely to be removed at - the discretion of moderation staff if they; -
        -
      1. argue under false pretences ("false flagging")
        -  e.g. "Hey fellow commies, did you prep your wife's bull today?"
      2. -
      3. imply reactionary or false positions of the userbase as a form of group shaming
        -  e.g. "Why do you guys all hate trans people?"
      4. -
      5. are of an overly derisive and mocking nature
        -  e.g. "haha, btfo commies hitler rulez"
      6. -
      7. are of a gratuitously offensive or hysterical nature
        -  e.g. "I hate fucking Mudslimes, we need to hang them all before they rape our children"
      8. -
      9. are debating inherently reactionary topics where no reasonable debate is possible
        -  e.g. "In what way should be exterminate the lesser races, guys?"
      10. -
      11. are low effort sectarian bait rather than good faith discussion
        -  e.g. “Tankie/Anarkiddie hate thread” or “Why does this theorist suck so much?”
      12. -
      13. are likely to create pointless and unconstructive arguments about ‘idpol’ (as defined in - Article 1)
        -  e.g. “Why can’t I have women as sex slaves?” or “Why are whiteoids like this?”
      14. -

      - These examples are low quality posts that are considered, at best, bait, but are better described as - spam. Any poster that violates this rule may be subject to a ban, and any post that violates this is - subject to deletion, subject to the discretion of moderators, if they feel that the topic may be an - avenue for productive discussion.

    12. -
    13. Volunteers may remove other posts according to their own discretion which they feel do not - contribute to the stated mission of /leftypol/, but they should try to adhere to the standards of the - community and of their fellow moderators, and to refrain from arbitrary decisions. Where there is - disagreement among moderators, the matter will be decided by informal consensus of currently - active moderators. If there is still disagreement, the matter should be escalated to a formal vote.
    14. -

    - - Once a ban is issued, it should be followed by the user and not contravened. The evasion of bans - will lead to continued bans and possibly an escalation of moderator action against a user. In - addition, it is prohibited to attempt to imitate a moderator, or to give the impression of being - multiple users at a time (for example to falsely make one’s own opinion appear more popular)

    - Users have the right to question and challenge any bans or post removals, or other moderator - actions, which they feel are unfair or do not live up to the spirit of the rules. This may be done in - the moderation feedback threads on the various boards, or on the /meta/ board, but comments - should be considered and constructive, and should not devolve into polemics against the - volunteers. Ultimately, the judgement of the moderation team is final. -
    +

+ +

GLOBAL:

+ +

0) Intentionally evading a ban will result in an immediate, long-term ban.

+ +

1) Anyone posting child pornography, child modelling or who attempts to challenge this rule (e.g. 'this is technically legal') will be permanently banned. Their information will be forwarded to relevant legal authorities.

+ +

2) Spam and malicious flooding is banned. This includes flooding a thread in protest, posting off-topic content in unrelated threads, and soyjak spam (quoting with no meaningful addition). Bot spam will result in a permanent ban. If you wish to make a post to advertise another site such as an imageboard or Discord server, contact the moderators first for clearance.

+ +

3) Actively promoting extreme illegal activity ('fedposting') may be removed or banned at the discretion of the moderators. There are more suitable sites for doing that.

+ +

4) Pretending to be multiple users ('samefagging') in order to fake popularity or start drama will usually result in a ban. Imitating a staff member is banned.

+ +

5) Any 'shock images' (gore, extreme pornography, abuse, etc.), regardless of intention, may be removed and punished with a ban. If it's legitimately constructive to a conversation, it may stay up if hidden using the Spoiler Image button and clearly described in the post to avoid being confused for trolling.

+ +

6) Direct calls to maliciously raid other communities may be removed at the moderators' decision. This includes raiding other imageboards and calls to brigade live-streamers. Leftypol is not your personal army.

+ +

BOARD RULES:
+These rules are enforced less rigorously on /siberia/ than they are on more 'high-quality' boards such as /leftypol/ or /edu/.

+ +

7) Reactionism and liberalism, or any other kind of non-leftist positions are not banned in itself, as we will endeavour to allow and encourage people of other political philosophies to explore leftism through /leftypol/ so long as they follow the rules contained herein. However, non-leftist users are ultimately to be considered ‘guests’ and thus will be removed if they prove a nuisance or disrupt the normal functioning of the site. Low-effort raiders will be banned. +Opening posts with liberalism or reactionary topics will be treated with far more scrutiny to prevent them filling the catalog.

+

8) Creating a new thread for a topic with an existing 'general' thread (e.g. creating threads about COVID-19 news, any e-celebrities, or USA mainstream politics) will be deleted or merged and will usually result in a short ban. Creating a redundant thread will be treated the same. Search the Catalog view search to find existing threads.

+ +

9) Due to derailing, COVID denialism outside the COVID-19 thread will be deleted.

+ +

10) All boards except for /siberia/ (and potentially /roulette/) are 'Safe For Work' boards. Pornography should not be posted on them without good reason, and any pornography on these boards should be hidden using the Spoiler Image option. New threads on /siberia/ with pornographic topics should have a Spoiler Image on the opening post.

+ +

11) Posts should, overall, be conductive to an informed and productive discussion. /leftypol/ is not an academic journal, but it also should not be a cesspit of back and forth bickering and pointless insults. Users should attempt to argue for the point they are presenting in an honest and open way and should be receptive to information or arguments that do, in fact, challenge their views.

+ +

12) Reactionary 'I am [ideology] AMA'-type threads are considered inherently bad faith and off-topic, and will be removed from /leftypol/.

+ +

13) /leftypol/ is committed to the ideal that the left should have an avenue for open discussion, so all ‘mainstream’ leftist ideologies will be permitted (so long as they do not violate the conditions set out in Article 1. /leftypol/ does not adhere to a specific leftist ideology. Sectarianism is banned. This includes idpol and '[left ideology] hate' threads.

+ +

14) To ensure a basic level of quality, topics or posts will not be tolerated when contributions are not conductive to well-intentioned discussion. Therefore, posts or topics are likely to be removed at the discretion of moderation staff if they;

+
  • a) argue under false pretences ("false flagging")
    +  e.g. "Hey fellow commies, did you prep your wife's bull today?"

  • +
  • b) imply reactionary or false positions of the userbase as a form of group shaming
    +  e.g. "Why do you guys all hate white people?"

  • +
  • c) are of an overly derisive and mocking nature
    +  e.g. "haha, btfo commies hitler rulez"

  • +
  • d) are of a gratuitously offensive or hysterical nature
    +  e.g. "I hate fucking Mudslimes, we need to hang them all before they rape our children"

  • +
  • e) are debating inherently reactionary topics where no reasonable debate is possible
    +  e.g. "In what way should be exterminate the lesser races, guys?"

  • +
  • f) are low effort sectarian bait rather than good faith discussion
    +  e.g. “Tankie/Anarkiddie hate thread” or “Why does this theorist suck so much?”

  • +
  • g) are likely to create pointless and unconstructive arguments about ‘idpol’ (as defined in Article 1).
    +  e.g. “Why can’t I have women as sex slaves?” or “Why are whiteoids like this?”

+ +

These examples are low quality posts that are considered, at best, bait, but are better described as spam. Any poster that violates this rule may be subject to a ban, and any post that violates this is subject to deletion at the discretion of moderators, if they feel that the topic may be an avenue for productive discussion.

+ +

META:

+ +

15) Volunteers may remove other posts according to their own discretion which they feel do not contribute to the stated mission of /leftypol/, but they should try to adhere to the standards of the community and of their fellow moderators, and to refrain from arbitrary decisions. Where there is disagreement among moderators, the matter will be decided by informal consensus of currently active moderators. If there is still disagreement, the matter should be escalated to a formal vote.

+ +

16) Users have the right to question and challenge any bans or post removals, or other moderator actions, which they feel are unfair or do not live up to the spirit of the rules. This may be done in the moderation feedback threads on the various boards, on the /meta/ board, through the ban appeal feature, or in the Leftypol Matrix Congress chat, but comments should be considered and constructive, and should not devolve into polemics against the volunteers. Ultimately, the judgement of the moderation team is final.

+
From 846c11f934258de340bcc3f17d1756b42319f27e Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 9 Dec 2021 23:16:23 -0100 Subject: [PATCH 34/74] Add IP address link to ban appeals --- templates/mod/ban_appeals.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/mod/ban_appeals.html b/templates/mod/ban_appeals.html index 23eced12..53588daf 100644 --- a/templates/mod/ban_appeals.html +++ b/templates/mod/ban_appeals.html @@ -16,7 +16,7 @@ {% if mod|hasPermission(config.mod.show_ip, board.uri) %} {% trans 'IP' %} - {{ ban.mask }} + {{ ban.mask }} {% endif %} From 9321c9888366f84810a6a4e7204f10b8c50231cf Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 10 Dec 2021 07:40:54 -0100 Subject: [PATCH 35/74] Add RAF flag --- static/flags/raf.png | Bin 0 -> 1390 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/flags/raf.png diff --git a/static/flags/raf.png b/static/flags/raf.png new file mode 100644 index 0000000000000000000000000000000000000000..4eee94c853308ec308244bac1c63a39851326374 GIT binary patch literal 1390 zcmV-!1(EuRP)EX>4Tx04R}tkv&MmP!xqvQ?;d39PA+CkfAzR5EXIMDionYs1;guFnQ@8G%+M8 zE{=k0!NH%!s)LKOt`4q(Aov5~=H{g6A|>9J6k5c1;qgAsyXWxUeSpxYGR^8512o+> zGpVGQ%dd!`S40s(7yy9Cej@B6cQ)q=%z@3D(Sp9b#C2LjNMQkskRU=q4HZ;jBSE`PiiHfFCw=^bu3sXTLaquJ zIp(ne4YKP8|AXJNwTcttUQ#p(biX*x$1o7u1)6oo`95}><_Qpd2CnqBf1?3Rf0ABr zYw;tXZyUI{ZfnXOaJd5vJQ=bnyHb#rP%HxPXY@^Zp#K(#ta@{6o#XTY$kMFRH^9Lm zFjAuIHJ^8fJLmRqPiuZZ$!2n62c3KD00006VoOIv0E+;Y0PFEH#ZCYK010qNS#tmY zE+YT{E+YYWr9XB6000McNlirueSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00TxzL_t(I%bk>4XdHDI#ecIiyF0Vloivl%Qg@TJiMefP zKroORG?0rmzKF#>Xz)%$pM<`7p{$}J^ra~6i%`To2}&uV7F3#tRw6Al(X0fUY*RN) zc5}~Wc4ucYJAYrLl>|Jm-{A)bzH?*_P!fzoFxqMak7HHJyO7(@uW+!MY6HC75UlFV zWA6gf`F8rH(h-Rgc6>C!qZt_4(zJEUvUo%@*s{u=&`OHWhvWBC zmg*tA26|0E8?YU#-+}I+L`0E6cd2_yHDdkEZ77aMwo+yyJ4@a#Pd9|>vF$R2J=6B^ zJR!UV5AU)p`~9yuo_E@*i_!0GXE zZv1+k(UUJQx3)yQqlK(xl37_M(bmQ%=gx8Cw<*?E^Hla6biJBrV}n6F9$S)vvH%LG z+)<5iW$4*Kv9W$%q^GCETVp50?>8sKh0i_~E4hp~`{Day+bW1#f2M^T3JE0c0&~C= z@TpRAEKgJ_SAehlYE?!!d;O6}_2>6@wwakt^U=F0WZR`b`2^9%1WM6iC!1rix35$w zl}-_028l8@4q*B$vv>`cFAu}jz3t+(ZQ7F?x%{-F%G{c{P5rJ!T~TH7`~=%SUMG~> zrN#oqEL9EsHF_%24ms_1L)5U(`#h!2hqi`N^w z#XEhY;`wN&c%!9P81PL3)Cd1idZ@d}WT2eBbM{!g>%E|)ux?6tv*jJ$Q53ExeuGTHmq!u;G|a zt)d=DJ-~Qq9I7Z1Lictg_v#;e*70R-~U%%dr*e}12AVO|M2hIKm5aE$p_xzivR!s07*qoM6N<$f>J$^TL1t6 literal 0 HcmV?d00001 From e0e53d9bec7e3fdd02b7c9ddc4fc190d418f7a12 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 10 Dec 2021 07:47:54 -0100 Subject: [PATCH 36/74] Add banner --- banners/1639006516292.webp | Bin 0 -> 6344 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 banners/1639006516292.webp diff --git a/banners/1639006516292.webp b/banners/1639006516292.webp new file mode 100644 index 0000000000000000000000000000000000000000..913ed930858554d96777560951c3e8201a54a9d7 GIT binary patch literal 6344 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 K4p)O%00012k$Ou2 literal 0 HcmV?d00001 From 3d3c0de67809ba3292d9eb5bcef15168aa1f3389 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 10 Dec 2021 23:07:01 -0100 Subject: [PATCH 37/74] Update RAF flag --- static/flags/raf.png | Bin 1390 -> 1140 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/static/flags/raf.png b/static/flags/raf.png index 4eee94c853308ec308244bac1c63a39851326374..7994f9d89a8a04275763b2ff458b6254f78cee97 100644 GIT binary patch delta 1069 zcmV+|1k(HN3iJq&Bs+s?LqkwWLqi~Na&Km7Y-IodD3N`UJxIe)6opSyrD7`%b`WvM zP@OD@ia2T&iclfc3avVryz~#6G?8B>e|zU}-+h44s4&gy8V5ApHq*(3n9Z$dj$A?7w1|2_x`LtHE%H>AQI0q!?cMvh^IGggY!Odl$B(a_?&pm zqy~u}xvqHp#<}RSz%!#}COuCaB^HYvtaLCdnHupFaZJ^8$``U8tDLtuYn2*nfAz^< z7|H7^%Uq{5j3gGZ1PLM()KEqRHsZAFq*zGPdBVp(Xpmh$_#gb9 ztyP$u@RA}4p!>yfK1P7hF3_wy&iAq7G*5uwGjOH1{nZ9A^GSNWt;LRj{%zpmx~(aD zz~v4w_+-eY>`FmeLZJY>pV2qvEr5Yrpm)uiTk9OB4?u=ymAU~A4uR1kWv~0ZyQgz* z|K4fM?+3xta$q`=QqhyK0Th1%nn^@KR5;6}(@kicWfTSA=bJA-CTY58A{jzd>L#_A zDpIYIN}EWl@n;Z`2HOdh{n3tWG(3BsFi;;Bct z?K^(M$hE+!O%U$f$%7rVq8(fPkEp`HDMBE$ashX4X5}i}fZ7dbNY`_)qg?D~`y>aE z{Tn7J&#WUKVGFj_#qs{SQrKIJ!tLwS7Xwu^-Y>MALJ{Y1K%~e>gvyARLPD|{!W2$M zaU6H!fvQqz-^(;Ti^YFi_ozMnzWmyniPw+1Tvy}q*ADsO_@L~?X-^IuwVcfweC~Of z+^-gvmrW&qn46nBQ;|-mpJ{7ryL*0qK6-m;$y?LYqU4HC3k9DK4?FP6OESa5Ru&g+ zyKj%vnV&tny6W(eBfgoFEjMqobj}zdtN2EQG$kzECI>!uaTDNTpH%7cqfv@kT`)$H~gd%Ex%u)nD9;Hy5*6 znb9#X^!6&Dv$IoUW20OyXL54Fu3dNhj&7WHRq*RrP0h~Eo+*_|C-7NWv|r})`4KpO zVG6|fa9L8~c9(kopG$WfBp<00000NkvXXu0mjf$sQ0+ delta 1321 zcmV+^1=jlX2<{4yBs+v@LqkwWLqi~Na&Km7Y-IodD3N`UJxIe)6opSywWU-X>>%Qh zp*mR*6>-!m6rn<>6R_dVS=rQxCyC>#rc=I<^H}A)#aXM?e^~3D z{DskizP!YBT0=--0gI3zLO~4`RAD1QyH1LQ44o%^{DZDvB9}t03K%)&u>lRT>j(dX z-?O!f6XRY|GzoOSIL^l~5ZVQrb;tQWcAVx35PSx%^tOMa0Zf0AUT z${ujJ0}MPFvMIY#kd{y^0`F(^E=_r${}za>dUI=?eSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00TxzL_t(I z%bk>4XdHDI#ecIiyF0Vloivl%Qg@TJiMefPKroORG?0rmzKF#>Xz)&dL!X4cd7-SL zBJ`yw?Tb*vJPArEq83z|hgKpjG|{XCn`~1zO?Gq7W_D+1GCO}?rIiFcuixPZ2flM; z4p0(|LonKE1dn4?%Da%;&#!Q>nrZ{Q+z_nl%wz8Y)BBly2hmjMYEi?_bogu9b$GJ1 z)zJSp@Wo^@puyuYxjK}8P$E(_JbiC|^T>gblMq-j40UsJGh}F*Vp$dd*V5_eV=&SY zi4t~vG{K`87}?Uab<47NL^Ig3%AU|liqD7R_fwYYA-o29O+Xv49jo7g?w~|OkwJH< zdrCE8{mpGCjz_jqW+FRF-Y-u#gzB;FGKD?U_V7F*yaf;MvMl?5{jWKmciOGEq7#=cMPD6zNw<71zE~}%zBo@Y;zv!y`R?bRqR*W?5xqT^j@B48F*T&d zZO1-Zw44Un6W+z4p}}D-q=lDObL2MGS-88v>G5%H{Cb_ylP@s0wnV(6g{)8sKh0i_~E4hp~`{Day+bW1#f2M^T3JE0c0&~C=@TpRAEKgJ_SAehlYE?!!d;O6} z_2>6@wwakt^U=F0WZR`b`2^9%1WM6iC!1rix35$wl}-_VU) z)xGWFv~Ajx8@c?nqsrWxxlR49L|sv3^85tbKVB!4+oi?=#VlMN7#R2(hgodqfxm%G z(1-!CR4U~II2?)8>G&>2!m8+N?+~vv^@tCS4vW_tyTvVb|m-e zAA8wfN_zOp+L<#MQYp`cLeVzO#ihm3#$a`Gty>8&9~ij@wI8Sj+!@N>|5smoP=^2m fFlQ+L@bB9{{KI3(2j1d~00000NkvXXu0mjff#Q99 From 2a11efd859e7bc59b9d69e5102ead49b827f6031 Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 13 Dec 2021 13:18:10 -0100 Subject: [PATCH 38/74] Fix typo in blur-images.js --- js/blur-images.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/blur-images.js b/js/blur-images.js index 4a603d68..6803f27a 100644 --- a/js/blur-images.js +++ b/js/blur-images.js @@ -90,7 +90,7 @@ $(document).ready(function(){ show_hide_blur_images_buttons(); if (window.Options && Options.get_tab('general')) { - $('#toggle-images>input').prop('checked', true); + $('#blur-images>input').prop('checked', true); } } From b3db9c52b70f0f7103b96b61891f752791e996ab Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 13 Dec 2021 13:32:55 -0100 Subject: [PATCH 39/74] Enable winter snow --- js/winter-snow.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 js/winter-snow.js diff --git a/js/winter-snow.js b/js/winter-snow.js new file mode 100644 index 00000000..99814436 --- /dev/null +++ b/js/winter-snow.js @@ -0,0 +1,26 @@ +// hacky enabling of snowstorm, probably a better way +$(document).ready(function(){ + var snow = localStorage['snow'] ? false : true; + + if (window.Options && Options.get_tab('general')) { + selector = '#add-snow>input'; + event = 'change'; + Options.extend_tab("general", ""); + } + + $(selector) + .on(event, function() { + snow = !snow; + if (snow) { + delete localStorage.snow; + } else { + localStorage.snow = false; + } + }); + if (snow) { + if (window.Options && Options.get_tab('general')) { + $('#add-snow>input').prop('checked', true); + } + $.getScript( "/js/snowstorm.js", function() {snowStorm.snowCharacter="•";snowStorm.start();}); + } +}); From 973b7d94e8a25f12e337df451cc0dc166c9f085b Mon Sep 17 00:00:00 2001 From: discomrade Date: Tue, 14 Dec 2021 10:41:03 -0100 Subject: [PATCH 40/74] [HACK] Hide tags in CSS See https://git.leftypol.org/leftypol/leftypol/issues/65 --- stylesheets/style.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/stylesheets/style.css b/stylesheets/style.css index a4ab484c..1803bb9a 100644 --- a/stylesheets/style.css +++ b/stylesheets/style.css @@ -1,5 +1,13 @@ /*Lainchan*/ +/* Hack: make tags invisible. https://git.leftypol.org/leftypol/leftypol/issues/65 + Turning a post into raw HTML mode will copy the content of these tags, + so flags and other data will show. This hides them, but they still exist. */ +tinyboard{ + display:none; +} + + div.sidearrows{ display:none; } From 8c8083ba617ce5aaef7bcfbbb17f3f240bf5344d Mon Sep 17 00:00:00 2001 From: discomrade Date: Sat, 18 Dec 2021 22:58:16 -0100 Subject: [PATCH 41/74] Make snow off-by-default due to lag --- js/winter-snow.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/winter-snow.js b/js/winter-snow.js index 99814436..93aa956c 100644 --- a/js/winter-snow.js +++ b/js/winter-snow.js @@ -1,6 +1,11 @@ // hacky enabling of snowstorm, probably a better way $(document).ready(function(){ - var snow = localStorage['snow'] ? false : true; + var snow = localStorage['snow'] ? true : false; + // delete previous value if "false"; this used to be on-by-default + if (snow && localStorage.snow == false) { + delete localStorage.snow; + snow = false; + } if (window.Options && Options.get_tab('general')) { selector = '#add-snow>input'; @@ -12,9 +17,9 @@ $(document).ready(function(){ .on(event, function() { snow = !snow; if (snow) { - delete localStorage.snow; + localStorage.snow = true; } else { - localStorage.snow = false; + delete localStorage.snow; } }); if (snow) { From 4a67df855bae4e6d0a56788a43898110f93e0b25 Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 20 Dec 2021 23:43:06 -0100 Subject: [PATCH 42/74] Birthdady themeing --- static/partyhat.png | Bin 0 -> 13374 bytes stylesheets/birthday2.css | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 static/partyhat.png create mode 100644 stylesheets/birthday2.css diff --git a/static/partyhat.png b/static/partyhat.png new file mode 100644 index 0000000000000000000000000000000000000000..b8110dced63cf44e3fcaa49ee0b27f14d6bbd5fd GIT binary patch literal 13374 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 .files > :nth-child(1):not(.multifile) > a:before { + content: url('/static/partyhat.png'); + float: left; + display: block; + margin-right: -160px; + position: relative; + top: -120px; + left: -30px; + +} +[data-board] > .files > :nth-child(1).multifile > a:before { + content: url('/static/partyhat.png'); + float: left; + display: block; + margin-right: -160px; + position: relative; + top: -120px; + left: -50px; + +} + From 19eca78aced9059252f22ff9c16e31d6010439ca Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 20 Dec 2021 23:50:15 -0100 Subject: [PATCH 43/74] Minor adjustment to birthday CSS --- stylesheets/birthday2.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stylesheets/birthday2.css b/stylesheets/birthday2.css index d21462a4..ed16716c 100644 --- a/stylesheets/birthday2.css +++ b/stylesheets/birthday2.css @@ -4,7 +4,7 @@ display: block; margin-right: -160px; position: relative; - top: -120px; + top: -150px; left: -30px; } @@ -14,7 +14,7 @@ display: block; margin-right: -160px; position: relative; - top: -120px; + top: -150px; left: -50px; } From c5814178aee666b34902665a0bd0b4667758a875 Mon Sep 17 00:00:00 2001 From: discomrade Date: Sun, 2 Jan 2022 08:44:26 -0100 Subject: [PATCH 44/74] Add Redneck flag --- static/flags/redneck.png | Bin 0 -> 317 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/flags/redneck.png diff --git a/static/flags/redneck.png b/static/flags/redneck.png new file mode 100644 index 0000000000000000000000000000000000000000..fc87338b6763ec5d89fafca8aad0dd57647fe4a6 GIT binary patch literal 317 zcmV-D0mA-?P)`f00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0MbcBK~y+Tt&_nH zf-n$7yG4n2uX@wOpYrGQqcqW*9`$Y{WtlQf)8Im)aSqFro$Z4Z Date: Sat, 15 Jan 2022 03:09:10 -0100 Subject: [PATCH 45/74] Allow users to disable and clear (You)s Credit to based anon https://leftypol.org/tech/res/6724.html#12776 --- js/show-own-posts.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/js/show-own-posts.js b/js/show-own-posts.js index e26f5abd..1402a606 100644 --- a/js/show-own-posts.js +++ b/js/show-own-posts.js @@ -17,6 +17,28 @@ +function(){ +if (typeof localStorage.own_posts_tracking === 'undefined') { + localStorage.own_posts_tracking = 'true'; // set default +} + +const addgui = function () { + if (!(window.Options && Options.get_tab ('general'))) { return; } + const prefix = "showownposts_"; + const gui = '
(You)s' + + '' + + ' ' + + '
'; + Options.extend_tab ("general", gui); + const cb = Options.get_tab ('general').content.find ('#' + prefix + 'track'); + cb.prop ('checked', localStorage.own_posts_tracking === 'true'); + cb.on ("change", function (ev) { + const cb = ev.target; + localStorage.own_posts_tracking = cb.checked ? 'true' : 'false'; + }); + Options.get_tab ('general').content.find ('#' + prefix + 'clear').on ("click", function () { + localStorage.own_posts = '{}'; + }); +} var update_own = function() { if ($(this).is('.you')) return; @@ -61,9 +83,11 @@ $(function() { board = $('input[name="board"]').first().val(); update_all(); + addgui(); }); $(document).on('ajax_after_post', function(e, r) { + if (localStorage.own_posts_tracking !== 'true') { return; } var posts = JSON.parse(localStorage.own_posts || '{}'); posts[board] = posts[board] || []; posts[board].push(r.id); From fed7d6a3e8ad8a2e15768909ab967e6a007a27e5 Mon Sep 17 00:00:00 2001 From: discomrade Date: Tue, 29 Jun 2021 23:10:12 -0200 Subject: [PATCH 46/74] Merge vichan PHP8 fixes, configure composer, fix outstanding incompatibilities --- README.md | 16 +- banned.php | 3 +- composer.json | 47 +- composer.lock | 1464 ++---------- inc/anti-bot.php | 63 - inc/bans.php | 4 - inc/bootstrap.php | 3 + inc/error.php | 4 +- inc/functions.php | 86 +- inc/lib/Twig/Autoloader.php | 54 - inc/lib/Twig/BaseNodeVisitor.php | 54 - inc/lib/Twig/Cache/Filesystem.php | 93 - inc/lib/Twig/Cache/Null.php | 40 - inc/lib/Twig/CacheInterface.php | 58 - inc/lib/Twig/Compiler.php | 286 --- inc/lib/Twig/CompilerInterface.php | 34 - inc/lib/Twig/ContainerRuntimeLoader.php | 39 - inc/lib/Twig/Environment.php | 1604 ------------- inc/lib/Twig/Error.php | 363 --- inc/lib/Twig/Error/Loader.php | 40 - inc/lib/Twig/Error/Runtime.php | 22 - inc/lib/Twig/Error/Syntax.php | 55 - inc/lib/Twig/ExistsLoaderInterface.php | 31 - inc/lib/Twig/ExpressionParser.php | 744 ------ inc/lib/Twig/Extension.php | 69 - inc/lib/Twig/Extension/Core.php | 1642 ------------- inc/lib/Twig/Extension/Debug.php | 67 - inc/lib/Twig/Extension/Escaper.php | 112 - inc/lib/Twig/Extension/GlobalsInterface.php | 24 - .../Twig/Extension/InitRuntimeInterface.php | 24 - inc/lib/Twig/Extension/Optimizer.php | 35 - inc/lib/Twig/Extension/Profiler.php | 49 - inc/lib/Twig/Extension/Sandbox.php | 103 - inc/lib/Twig/Extension/Staging.php | 112 - inc/lib/Twig/Extension/StringLoader.php | 47 - inc/lib/Twig/ExtensionInterface.php | 90 - inc/lib/Twig/FactoryRuntimeLoader.php | 39 - .../Twig/FileExtensionEscapingStrategy.php | 60 - inc/lib/Twig/Filter.php | 84 - inc/lib/Twig/Filter/Function.php | 40 - inc/lib/Twig/Filter/Method.php | 42 - inc/lib/Twig/Filter/Node.php | 42 - inc/lib/Twig/FilterCallableInterface.php | 24 - inc/lib/Twig/FilterInterface.php | 43 - inc/lib/Twig/Function.php | 74 - inc/lib/Twig/Function/Function.php | 41 - inc/lib/Twig/Function/Method.php | 43 - inc/lib/Twig/Function/Node.php | 42 - inc/lib/Twig/FunctionCallableInterface.php | 24 - inc/lib/Twig/FunctionInterface.php | 40 - inc/lib/Twig/Lexer.php | 427 ---- inc/lib/Twig/LexerInterface.php | 32 - inc/lib/Twig/Loader/Array.php | 97 - inc/lib/Twig/Loader/Chain.php | 151 -- inc/lib/Twig/Loader/Filesystem.php | 290 --- inc/lib/Twig/Loader/String.php | 58 - inc/lib/Twig/LoaderInterface.php | 57 - inc/lib/Twig/Markup.php | 39 - inc/lib/Twig/Node.php | 256 -- inc/lib/Twig/Node/AutoEscape.php | 36 - inc/lib/Twig/Node/Block.php | 41 - inc/lib/Twig/Node/BlockReference.php | 34 - inc/lib/Twig/Node/Body.php | 21 - inc/lib/Twig/Node/CheckSecurity.php | 80 - inc/lib/Twig/Node/Do.php | 35 - inc/lib/Twig/Node/Embed.php | 46 - inc/lib/Twig/Node/Expression.php | 22 - inc/lib/Twig/Node/Expression/Array.php | 83 - inc/lib/Twig/Node/Expression/AssignName.php | 25 - inc/lib/Twig/Node/Expression/Binary.php | 37 - inc/lib/Twig/Node/Expression/Binary/Add.php | 20 - inc/lib/Twig/Node/Expression/Binary/And.php | 20 - .../Node/Expression/Binary/BitwiseAnd.php | 20 - .../Twig/Node/Expression/Binary/BitwiseOr.php | 20 - .../Node/Expression/Binary/BitwiseXor.php | 20 - .../Twig/Node/Expression/Binary/Concat.php | 20 - inc/lib/Twig/Node/Expression/Binary/Div.php | 20 - .../Twig/Node/Expression/Binary/EndsWith.php | 32 - inc/lib/Twig/Node/Expression/Binary/Equal.php | 19 - .../Twig/Node/Expression/Binary/FloorDiv.php | 26 - .../Twig/Node/Expression/Binary/Greater.php | 19 - .../Node/Expression/Binary/GreaterEqual.php | 19 - inc/lib/Twig/Node/Expression/Binary/In.php | 30 - inc/lib/Twig/Node/Expression/Binary/Less.php | 19 - .../Twig/Node/Expression/Binary/LessEqual.php | 19 - .../Twig/Node/Expression/Binary/Matches.php | 30 - inc/lib/Twig/Node/Expression/Binary/Mod.php | 20 - inc/lib/Twig/Node/Expression/Binary/Mul.php | 20 - .../Twig/Node/Expression/Binary/NotEqual.php | 19 - inc/lib/Twig/Node/Expression/Binary/NotIn.php | 30 - inc/lib/Twig/Node/Expression/Binary/Or.php | 20 - inc/lib/Twig/Node/Expression/Binary/Power.php | 34 - inc/lib/Twig/Node/Expression/Binary/Range.php | 30 - .../Node/Expression/Binary/StartsWith.php | 32 - inc/lib/Twig/Node/Expression/Binary/Sub.php | 20 - .../Twig/Node/Expression/BlockReference.php | 93 - inc/lib/Twig/Node/Expression/Call.php | 291 --- inc/lib/Twig/Node/Expression/Conditional.php | 33 - inc/lib/Twig/Node/Expression/Constant.php | 25 - .../Node/Expression/ExtensionReference.php | 32 - inc/lib/Twig/Node/Expression/Filter.php | 41 - .../Twig/Node/Expression/Filter/Default.php | 45 - inc/lib/Twig/Node/Expression/Function.php | 45 - inc/lib/Twig/Node/Expression/GetAttr.php | 74 - inc/lib/Twig/Node/Expression/MacroCall.php | 60 - inc/lib/Twig/Node/Expression/MethodCall.php | 43 - inc/lib/Twig/Node/Expression/Name.php | 102 - inc/lib/Twig/Node/Expression/NullCoalesce.php | 48 - inc/lib/Twig/Node/Expression/Parent.php | 44 - inc/lib/Twig/Node/Expression/TempName.php | 28 - inc/lib/Twig/Node/Expression/Test.php | 42 - .../Twig/Node/Expression/Test/Constant.php | 48 - inc/lib/Twig/Node/Expression/Test/Defined.php | 61 - .../Twig/Node/Expression/Test/Divisibleby.php | 35 - inc/lib/Twig/Node/Expression/Test/Even.php | 34 - inc/lib/Twig/Node/Expression/Test/Null.php | 33 - inc/lib/Twig/Node/Expression/Test/Odd.php | 34 - inc/lib/Twig/Node/Expression/Test/Sameas.php | 31 - inc/lib/Twig/Node/Expression/Unary.php | 29 - inc/lib/Twig/Node/Expression/Unary/Neg.php | 20 - inc/lib/Twig/Node/Expression/Unary/Not.php | 20 - inc/lib/Twig/Node/Expression/Unary/Pos.php | 20 - inc/lib/Twig/Node/Flush.php | 33 - inc/lib/Twig/Node/For.php | 113 - inc/lib/Twig/Node/ForLoop.php | 52 - inc/lib/Twig/Node/If.php | 68 - inc/lib/Twig/Node/Import.php | 51 - inc/lib/Twig/Node/Include.php | 90 - inc/lib/Twig/Node/Macro.php | 125 - inc/lib/Twig/Node/Module.php | 461 ---- inc/lib/Twig/Node/Print.php | 36 - inc/lib/Twig/Node/Sandbox.php | 44 - inc/lib/Twig/Node/SandboxedModule.php | 60 - inc/lib/Twig/Node/SandboxedPrint.php | 51 - inc/lib/Twig/Node/Set.php | 98 - inc/lib/Twig/Node/SetTemp.php | 40 - inc/lib/Twig/Node/Spaceless.php | 37 - inc/lib/Twig/Node/Text.php | 36 - inc/lib/Twig/Node/With.php | 64 - inc/lib/Twig/NodeCaptureInterface.php | 21 - inc/lib/Twig/NodeInterface.php | 32 - inc/lib/Twig/NodeOutputInterface.php | 21 - inc/lib/Twig/NodeTraverser.php | 86 - inc/lib/Twig/NodeVisitor/Escaper.php | 154 -- inc/lib/Twig/NodeVisitor/Optimizer.php | 253 -- inc/lib/Twig/NodeVisitor/SafeAnalysis.php | 150 -- inc/lib/Twig/NodeVisitor/Sandbox.php | 82 - inc/lib/Twig/NodeVisitorInterface.php | 45 - inc/lib/Twig/Parser.php | 412 ---- inc/lib/Twig/ParserInterface.php | 29 - inc/lib/Twig/Profiler/Dumper/Base.php | 62 - inc/lib/Twig/Profiler/Dumper/Blackfire.php | 72 - inc/lib/Twig/Profiler/Dumper/Html.php | 47 - inc/lib/Twig/Profiler/Dumper/Text.php | 35 - inc/lib/Twig/Profiler/Node/EnterProfile.php | 39 - inc/lib/Twig/Profiler/Node/LeaveProfile.php | 33 - .../Twig/Profiler/NodeVisitor/Profiler.php | 67 - inc/lib/Twig/Profiler/Profile.php | 170 -- inc/lib/Twig/RuntimeLoaderInterface.php | 29 - inc/lib/Twig/Sandbox/SecurityError.php | 21 - .../Sandbox/SecurityNotAllowedFilterError.php | 33 - .../SecurityNotAllowedFunctionError.php | 33 - .../Sandbox/SecurityNotAllowedMethodError.php | 40 - .../SecurityNotAllowedPropertyError.php | 40 - .../Sandbox/SecurityNotAllowedTagError.php | 33 - inc/lib/Twig/Sandbox/SecurityPolicy.php | 125 - .../Twig/Sandbox/SecurityPolicyInterface.php | 26 - inc/lib/Twig/SimpleFilter.php | 121 - inc/lib/Twig/SimpleFunction.php | 111 - inc/lib/Twig/SimpleTest.php | 73 - inc/lib/Twig/Source.php | 53 - inc/lib/Twig/SourceContextLoaderInterface.php | 33 - inc/lib/Twig/Template.php | 708 ------ inc/lib/Twig/TemplateInterface.php | 48 - inc/lib/Twig/TemplateWrapper.php | 133 -- inc/lib/Twig/Test.php | 37 - inc/lib/Twig/Test/Function.php | 38 - inc/lib/Twig/Test/IntegrationTestCase.php | 249 -- inc/lib/Twig/Test/Method.php | 40 - inc/lib/Twig/Test/Node.php | 40 - inc/lib/Twig/Test/NodeTestCase.php | 75 - inc/lib/Twig/TestCallableInterface.php | 22 - inc/lib/Twig/TestInterface.php | 27 - inc/lib/Twig/Token.php | 207 -- inc/lib/Twig/TokenParser.php | 33 - inc/lib/Twig/TokenParser/AutoEscape.php | 83 - inc/lib/Twig/TokenParser/Block.php | 73 - inc/lib/Twig/TokenParser/Do.php | 34 - inc/lib/Twig/TokenParser/Embed.php | 67 - inc/lib/Twig/TokenParser/Extends.php | 46 - inc/lib/Twig/TokenParser/Filter.php | 53 - inc/lib/Twig/TokenParser/Flush.php | 34 - inc/lib/Twig/TokenParser/For.php | 127 - inc/lib/Twig/TokenParser/From.php | 66 - inc/lib/Twig/TokenParser/If.php | 86 - inc/lib/Twig/TokenParser/Import.php | 41 - inc/lib/Twig/TokenParser/Include.php | 65 - inc/lib/Twig/TokenParser/Macro.php | 60 - inc/lib/Twig/TokenParser/Sandbox.php | 61 - inc/lib/Twig/TokenParser/Set.php | 75 - inc/lib/Twig/TokenParser/Spaceless.php | 51 - inc/lib/Twig/TokenParser/Use.php | 70 - inc/lib/Twig/TokenParser/With.php | 52 - inc/lib/Twig/TokenParserBroker.php | 120 - inc/lib/Twig/TokenParserBrokerInterface.php | 44 - inc/lib/Twig/TokenParserInterface.php | 43 - inc/lib/Twig/TokenStream.php | 196 -- inc/lib/Twig/Util/DeprecationCollector.php | 86 - inc/lib/Twig/Util/TemplateDirIterator.php | 28 - inc/lib/minify/FirePHP.php | 1370 ----------- inc/lib/minify/HTTP/ConditionalGet.php | 366 --- inc/lib/minify/HTTP/Encoder.php | 335 --- inc/lib/minify/JSMin.php | 449 ---- inc/lib/minify/JSMinPlus.php | 2086 ----------------- inc/lib/minify/Minify.php | 608 ----- inc/lib/minify/Minify/Build.php | 101 - inc/lib/minify/Minify/CSS/UriRewriter.php | 307 --- inc/lib/minify/Minify/Cache/APC.php | 133 -- inc/lib/minify/Minify/Cache/File.php | 197 -- inc/lib/minify/Minify/Cache/Memcache.php | 140 -- inc/lib/minify/Minify/Cache/ZendPlatform.php | 142 -- inc/lib/minify/Minify/CommentPreserver.php | 89 - inc/lib/minify/Minify/Controller/Base.php | 222 -- inc/lib/minify/Minify/Controller/Files.php | 76 - inc/lib/minify/Minify/Controller/Groups.php | 91 - inc/lib/minify/Minify/Controller/MinApp.php | 238 -- inc/lib/minify/Minify/Controller/Page.php | 68 - inc/lib/minify/Minify/Controller/Version1.php | 119 - inc/lib/minify/Minify/HTML/Helper.php | 225 -- inc/lib/minify/Minify/JS/ClosureCompiler.php | 230 -- inc/lib/minify/Minify/Lines.php | 143 -- inc/lib/minify/Minify/Logger.php | 47 - inc/lib/minify/Minify/Packer.php | 37 - inc/lib/minify/Minify/Source.php | 187 -- inc/lib/minify/Minify/YUI/CssCompressor.java | 382 --- inc/lib/minify/Minify/YUI/CssCompressor.php | 171 -- inc/lib/minify/Minify/YUICompressor.php | 156 -- inc/lib/minify/MrClay/Cli.php | 384 --- inc/lib/minify/MrClay/Cli/Arg.php | 183 -- .../extensions}/Extension/I18n.php | 1 - .../extensions}/Extension/Tinyboard.php | 0 .../extensions}/Node/Trans.php | 2 +- .../extensions}/TokenParser/Trans.php | 2 +- inc/template.php | 12 +- install.php | 3 +- log.php | 3 +- mod.php | 9 +- post.php | 22 +- report.php | 2 +- search.php | 2 +- smart_build.php | 2 +- templates/themes/catalog/theme.php | 4 +- 252 files changed, 280 insertions(+), 28499 deletions(-) create mode 100644 inc/bootstrap.php delete mode 100644 inc/lib/Twig/Autoloader.php delete mode 100644 inc/lib/Twig/BaseNodeVisitor.php delete mode 100644 inc/lib/Twig/Cache/Filesystem.php delete mode 100644 inc/lib/Twig/Cache/Null.php delete mode 100644 inc/lib/Twig/CacheInterface.php delete mode 100644 inc/lib/Twig/Compiler.php delete mode 100644 inc/lib/Twig/CompilerInterface.php delete mode 100644 inc/lib/Twig/ContainerRuntimeLoader.php delete mode 100644 inc/lib/Twig/Environment.php delete mode 100644 inc/lib/Twig/Error.php delete mode 100644 inc/lib/Twig/Error/Loader.php delete mode 100644 inc/lib/Twig/Error/Runtime.php delete mode 100644 inc/lib/Twig/Error/Syntax.php delete mode 100644 inc/lib/Twig/ExistsLoaderInterface.php delete mode 100644 inc/lib/Twig/ExpressionParser.php delete mode 100644 inc/lib/Twig/Extension.php delete mode 100644 inc/lib/Twig/Extension/Core.php delete mode 100644 inc/lib/Twig/Extension/Debug.php delete mode 100644 inc/lib/Twig/Extension/Escaper.php delete mode 100644 inc/lib/Twig/Extension/GlobalsInterface.php delete mode 100644 inc/lib/Twig/Extension/InitRuntimeInterface.php delete mode 100644 inc/lib/Twig/Extension/Optimizer.php delete mode 100644 inc/lib/Twig/Extension/Profiler.php delete mode 100644 inc/lib/Twig/Extension/Sandbox.php delete mode 100644 inc/lib/Twig/Extension/Staging.php delete mode 100644 inc/lib/Twig/Extension/StringLoader.php delete mode 100644 inc/lib/Twig/ExtensionInterface.php delete mode 100644 inc/lib/Twig/FactoryRuntimeLoader.php delete mode 100644 inc/lib/Twig/FileExtensionEscapingStrategy.php delete mode 100644 inc/lib/Twig/Filter.php delete mode 100644 inc/lib/Twig/Filter/Function.php delete mode 100644 inc/lib/Twig/Filter/Method.php delete mode 100644 inc/lib/Twig/Filter/Node.php delete mode 100644 inc/lib/Twig/FilterCallableInterface.php delete mode 100644 inc/lib/Twig/FilterInterface.php delete mode 100644 inc/lib/Twig/Function.php delete mode 100644 inc/lib/Twig/Function/Function.php delete mode 100644 inc/lib/Twig/Function/Method.php delete mode 100644 inc/lib/Twig/Function/Node.php delete mode 100644 inc/lib/Twig/FunctionCallableInterface.php delete mode 100644 inc/lib/Twig/FunctionInterface.php delete mode 100644 inc/lib/Twig/Lexer.php delete mode 100644 inc/lib/Twig/LexerInterface.php delete mode 100644 inc/lib/Twig/Loader/Array.php delete mode 100644 inc/lib/Twig/Loader/Chain.php delete mode 100644 inc/lib/Twig/Loader/Filesystem.php delete mode 100644 inc/lib/Twig/Loader/String.php delete mode 100644 inc/lib/Twig/LoaderInterface.php delete mode 100644 inc/lib/Twig/Markup.php delete mode 100644 inc/lib/Twig/Node.php delete mode 100644 inc/lib/Twig/Node/AutoEscape.php delete mode 100644 inc/lib/Twig/Node/Block.php delete mode 100644 inc/lib/Twig/Node/BlockReference.php delete mode 100644 inc/lib/Twig/Node/Body.php delete mode 100644 inc/lib/Twig/Node/CheckSecurity.php delete mode 100644 inc/lib/Twig/Node/Do.php delete mode 100644 inc/lib/Twig/Node/Embed.php delete mode 100644 inc/lib/Twig/Node/Expression.php delete mode 100644 inc/lib/Twig/Node/Expression/Array.php delete mode 100644 inc/lib/Twig/Node/Expression/AssignName.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Add.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/And.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/BitwiseAnd.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/BitwiseOr.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/BitwiseXor.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Concat.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Div.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/EndsWith.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Equal.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/FloorDiv.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Greater.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/GreaterEqual.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/In.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Less.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/LessEqual.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Matches.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Mod.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Mul.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/NotEqual.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/NotIn.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Or.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Power.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Range.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/StartsWith.php delete mode 100644 inc/lib/Twig/Node/Expression/Binary/Sub.php delete mode 100644 inc/lib/Twig/Node/Expression/BlockReference.php delete mode 100644 inc/lib/Twig/Node/Expression/Call.php delete mode 100644 inc/lib/Twig/Node/Expression/Conditional.php delete mode 100644 inc/lib/Twig/Node/Expression/Constant.php delete mode 100644 inc/lib/Twig/Node/Expression/ExtensionReference.php delete mode 100644 inc/lib/Twig/Node/Expression/Filter.php delete mode 100644 inc/lib/Twig/Node/Expression/Filter/Default.php delete mode 100644 inc/lib/Twig/Node/Expression/Function.php delete mode 100644 inc/lib/Twig/Node/Expression/GetAttr.php delete mode 100644 inc/lib/Twig/Node/Expression/MacroCall.php delete mode 100644 inc/lib/Twig/Node/Expression/MethodCall.php delete mode 100644 inc/lib/Twig/Node/Expression/Name.php delete mode 100644 inc/lib/Twig/Node/Expression/NullCoalesce.php delete mode 100644 inc/lib/Twig/Node/Expression/Parent.php delete mode 100644 inc/lib/Twig/Node/Expression/TempName.php delete mode 100644 inc/lib/Twig/Node/Expression/Test.php delete mode 100644 inc/lib/Twig/Node/Expression/Test/Constant.php delete mode 100644 inc/lib/Twig/Node/Expression/Test/Defined.php delete mode 100644 inc/lib/Twig/Node/Expression/Test/Divisibleby.php delete mode 100644 inc/lib/Twig/Node/Expression/Test/Even.php delete mode 100644 inc/lib/Twig/Node/Expression/Test/Null.php delete mode 100644 inc/lib/Twig/Node/Expression/Test/Odd.php delete mode 100644 inc/lib/Twig/Node/Expression/Test/Sameas.php delete mode 100644 inc/lib/Twig/Node/Expression/Unary.php delete mode 100644 inc/lib/Twig/Node/Expression/Unary/Neg.php delete mode 100644 inc/lib/Twig/Node/Expression/Unary/Not.php delete mode 100644 inc/lib/Twig/Node/Expression/Unary/Pos.php delete mode 100644 inc/lib/Twig/Node/Flush.php delete mode 100644 inc/lib/Twig/Node/For.php delete mode 100644 inc/lib/Twig/Node/ForLoop.php delete mode 100644 inc/lib/Twig/Node/If.php delete mode 100644 inc/lib/Twig/Node/Import.php delete mode 100644 inc/lib/Twig/Node/Include.php delete mode 100644 inc/lib/Twig/Node/Macro.php delete mode 100644 inc/lib/Twig/Node/Module.php delete mode 100644 inc/lib/Twig/Node/Print.php delete mode 100644 inc/lib/Twig/Node/Sandbox.php delete mode 100644 inc/lib/Twig/Node/SandboxedModule.php delete mode 100644 inc/lib/Twig/Node/SandboxedPrint.php delete mode 100644 inc/lib/Twig/Node/Set.php delete mode 100644 inc/lib/Twig/Node/SetTemp.php delete mode 100644 inc/lib/Twig/Node/Spaceless.php delete mode 100644 inc/lib/Twig/Node/Text.php delete mode 100644 inc/lib/Twig/Node/With.php delete mode 100644 inc/lib/Twig/NodeCaptureInterface.php delete mode 100644 inc/lib/Twig/NodeInterface.php delete mode 100644 inc/lib/Twig/NodeOutputInterface.php delete mode 100644 inc/lib/Twig/NodeTraverser.php delete mode 100644 inc/lib/Twig/NodeVisitor/Escaper.php delete mode 100644 inc/lib/Twig/NodeVisitor/Optimizer.php delete mode 100644 inc/lib/Twig/NodeVisitor/SafeAnalysis.php delete mode 100644 inc/lib/Twig/NodeVisitor/Sandbox.php delete mode 100644 inc/lib/Twig/NodeVisitorInterface.php delete mode 100644 inc/lib/Twig/Parser.php delete mode 100644 inc/lib/Twig/ParserInterface.php delete mode 100644 inc/lib/Twig/Profiler/Dumper/Base.php delete mode 100644 inc/lib/Twig/Profiler/Dumper/Blackfire.php delete mode 100644 inc/lib/Twig/Profiler/Dumper/Html.php delete mode 100644 inc/lib/Twig/Profiler/Dumper/Text.php delete mode 100644 inc/lib/Twig/Profiler/Node/EnterProfile.php delete mode 100644 inc/lib/Twig/Profiler/Node/LeaveProfile.php delete mode 100644 inc/lib/Twig/Profiler/NodeVisitor/Profiler.php delete mode 100644 inc/lib/Twig/Profiler/Profile.php delete mode 100644 inc/lib/Twig/RuntimeLoaderInterface.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityError.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityNotAllowedTagError.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityPolicy.php delete mode 100644 inc/lib/Twig/Sandbox/SecurityPolicyInterface.php delete mode 100644 inc/lib/Twig/SimpleFilter.php delete mode 100644 inc/lib/Twig/SimpleFunction.php delete mode 100644 inc/lib/Twig/SimpleTest.php delete mode 100644 inc/lib/Twig/Source.php delete mode 100644 inc/lib/Twig/SourceContextLoaderInterface.php delete mode 100644 inc/lib/Twig/Template.php delete mode 100644 inc/lib/Twig/TemplateInterface.php delete mode 100644 inc/lib/Twig/TemplateWrapper.php delete mode 100644 inc/lib/Twig/Test.php delete mode 100644 inc/lib/Twig/Test/Function.php delete mode 100644 inc/lib/Twig/Test/IntegrationTestCase.php delete mode 100644 inc/lib/Twig/Test/Method.php delete mode 100644 inc/lib/Twig/Test/Node.php delete mode 100644 inc/lib/Twig/Test/NodeTestCase.php delete mode 100644 inc/lib/Twig/TestCallableInterface.php delete mode 100644 inc/lib/Twig/TestInterface.php delete mode 100644 inc/lib/Twig/Token.php delete mode 100644 inc/lib/Twig/TokenParser.php delete mode 100644 inc/lib/Twig/TokenParser/AutoEscape.php delete mode 100644 inc/lib/Twig/TokenParser/Block.php delete mode 100644 inc/lib/Twig/TokenParser/Do.php delete mode 100644 inc/lib/Twig/TokenParser/Embed.php delete mode 100644 inc/lib/Twig/TokenParser/Extends.php delete mode 100644 inc/lib/Twig/TokenParser/Filter.php delete mode 100644 inc/lib/Twig/TokenParser/Flush.php delete mode 100644 inc/lib/Twig/TokenParser/For.php delete mode 100644 inc/lib/Twig/TokenParser/From.php delete mode 100644 inc/lib/Twig/TokenParser/If.php delete mode 100644 inc/lib/Twig/TokenParser/Import.php delete mode 100644 inc/lib/Twig/TokenParser/Include.php delete mode 100644 inc/lib/Twig/TokenParser/Macro.php delete mode 100644 inc/lib/Twig/TokenParser/Sandbox.php delete mode 100644 inc/lib/Twig/TokenParser/Set.php delete mode 100644 inc/lib/Twig/TokenParser/Spaceless.php delete mode 100644 inc/lib/Twig/TokenParser/Use.php delete mode 100644 inc/lib/Twig/TokenParser/With.php delete mode 100644 inc/lib/Twig/TokenParserBroker.php delete mode 100644 inc/lib/Twig/TokenParserBrokerInterface.php delete mode 100644 inc/lib/Twig/TokenParserInterface.php delete mode 100644 inc/lib/Twig/TokenStream.php delete mode 100644 inc/lib/Twig/Util/DeprecationCollector.php delete mode 100644 inc/lib/Twig/Util/TemplateDirIterator.php delete mode 100755 inc/lib/minify/FirePHP.php delete mode 100755 inc/lib/minify/HTTP/ConditionalGet.php delete mode 100755 inc/lib/minify/HTTP/Encoder.php delete mode 100755 inc/lib/minify/JSMin.php delete mode 100755 inc/lib/minify/JSMinPlus.php delete mode 100755 inc/lib/minify/Minify.php delete mode 100755 inc/lib/minify/Minify/Build.php delete mode 100755 inc/lib/minify/Minify/CSS/UriRewriter.php delete mode 100755 inc/lib/minify/Minify/Cache/APC.php delete mode 100755 inc/lib/minify/Minify/Cache/File.php delete mode 100755 inc/lib/minify/Minify/Cache/Memcache.php delete mode 100755 inc/lib/minify/Minify/Cache/ZendPlatform.php delete mode 100755 inc/lib/minify/Minify/CommentPreserver.php delete mode 100755 inc/lib/minify/Minify/Controller/Base.php delete mode 100755 inc/lib/minify/Minify/Controller/Files.php delete mode 100755 inc/lib/minify/Minify/Controller/Groups.php delete mode 100755 inc/lib/minify/Minify/Controller/MinApp.php delete mode 100755 inc/lib/minify/Minify/Controller/Page.php delete mode 100755 inc/lib/minify/Minify/Controller/Version1.php delete mode 100755 inc/lib/minify/Minify/HTML/Helper.php delete mode 100755 inc/lib/minify/Minify/JS/ClosureCompiler.php delete mode 100755 inc/lib/minify/Minify/Lines.php delete mode 100755 inc/lib/minify/Minify/Logger.php delete mode 100755 inc/lib/minify/Minify/Packer.php delete mode 100755 inc/lib/minify/Minify/Source.php delete mode 100755 inc/lib/minify/Minify/YUI/CssCompressor.java delete mode 100755 inc/lib/minify/Minify/YUI/CssCompressor.php delete mode 100755 inc/lib/minify/Minify/YUICompressor.php delete mode 100755 inc/lib/minify/MrClay/Cli.php delete mode 100755 inc/lib/minify/MrClay/Cli/Arg.php rename inc/lib/{Twig/Extensions => twig/extensions}/Extension/I18n.php (99%) rename inc/lib/{Twig/Extensions => twig/extensions}/Extension/Tinyboard.php (100%) rename inc/lib/{Twig/Extensions => twig/extensions}/Node/Trans.php (99%) rename inc/lib/{Twig/Extensions => twig/extensions}/TokenParser/Trans.php (99%) diff --git a/README.md b/README.md index 44826dc7..e5f8ead0 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,13 @@ We highly recommend you read the [vichan GitHub wiki](http://github.com/vichan-d Requirements ------------ -1. PHP >= 5.4. PHP 7.0 is explicitly supported. There is a PHP 8 capable branch. +1. PHP >= 5.4 (we do not actively check if this is still supported) + PHP 8.0 is explicitly supported. PHP 7.x should be compatable. 2. MySQL/MariaDB server >= 5.5.3 -3. [mbstring](http://www.php.net/manual/en/mbstring.installation.php) -4. [PHP GD](http://www.php.net/manual/en/intro.image.php) -5. [PHP PDO](http://www.php.net/manual/en/intro.pdo.php) +3. [Composer](https://getcomposer.org/) (To install various packages) +4. [mbstring](http://www.php.net/manual/en/mbstring.installation.php) +5. [PHP GD](http://www.php.net/manual/en/intro.image.php) +6. [PHP PDO](http://www.php.net/manual/en/intro.pdo.php) This should be compatible with all major web servers and operating systems. This code does not include an Apache ```.htaccess``` file nor does @@ -23,6 +25,7 @@ it need one. ### Recommended 1. ImageMagick (command-line ImageMagick or GraphicsMagick preferred). 2. [APC (Alternative PHP Cache)](http://php.net/manual/en/book.apc.php), + Redis, [XCache](http://xcache.lighttpd.net/) or [Memcached](http://www.php.net/manual/en/intro.memcached.php) @@ -42,9 +45,10 @@ Installation git clone git://git.leftypol.org/leftypol/leftypol.git -2. Navigate to ```install.php``` in your web browser and follow the +2. run ```composer install``` inside the directory +3. Navigate to ```install.php``` in your web browser and follow the prompts. -3. leftypol should now be installed. Log in to ```mod.php``` with the +4. leftypol should now be installed. Log in to ```mod.php``` with the default username and password combination: **admin / password**. Please remember to change the administrator account password. diff --git a/banned.php b/banned.php index a38b87c4..7e1f47f1 100644 --- a/banned.php +++ b/banned.php @@ -1,6 +1,5 @@ =5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5" - }, - "time": "2017-11-27T13:52:08+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" - }, - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.9", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/master" - }, - "time": "2017-02-26T11:10:40+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "791198a2c6254db10131eecfe8c06670700904db" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", - "reference": "791198a2c6254db10131eecfe8c06670700904db", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.2.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", - "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" - }, - "abandoned": true, - "time": "2017-11-27T05:48:46+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "5.7.27", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", - "reference": "b7803aeca3ccb99ad0a506fa80b64cd6a56bbc0c", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.6.2", - "phpunit/php-code-coverage": "^4.0.4", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "^3.2", - "sebastian/comparator": "^1.2.4", - "sebastian/diff": "^1.4.3", - "sebastian/environment": "^1.3.4 || ^2.0", - "sebastian/exporter": "~2.0", - "sebastian/global-state": "^1.1", - "sebastian/object-enumerator": "~2.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "^1.0.6|^2.0.1", - "symfony/yaml": "~2.1|~3.0|~4.0" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-xdebug": "*", - "phpunit/php-invoker": "~1.1" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/5.7.27" - }, - "time": "2018-02-01T05:50:59+00:00" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "3.4.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2 || ^2.0" - }, - "conflict": { - "phpunit/phpunit": "<5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.4" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "support": { - "irc": "irc://irc.freenode.net/phpunit", - "issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues", - "source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/3.4" - }, - "abandoned": true, - "time": "2017-06-30T09:13:00+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": "^8.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T08:15:22+00:00" - }, - { - "name": "sebastian/comparator", - "version": "1.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/1.2" - }, - "time": "2017-01-29T09:50:25+00:00" - }, - { - "name": "sebastian/diff", - "version": "1.4.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0" + "conflict": { + "ext-geoip": "*" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "3.7.*", + "satooshi/php-coveralls": "1.0.*" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "files": [ + "src/geoip.inc", + "src/geoipcity.inc", + "src/timezone.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "LGPL 2.1+" ], "authors": [ { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "MaxMind, Inc.", + "email": "support@maxmind.com", + "homepage": "http://www.maxmind.com/" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", + "description": "MaxMind GeoIP PHP API", + "homepage": "http://dev.maxmind.com/geoip/legacy/downloadable", "keywords": [ - "diff" + "geoip", + "geolocation", + "maxmind" ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/1.4" - }, - "time": "2017-05-22T07:24:03+00:00" + "time": "2016-05-16T19:06:50+00:00" }, { - "name": "sebastian/environment", - "version": "2.0.0", + "name": "gettext/gettext", + "version": "v1.1.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + "url": "https://github.com/php-gettext/Gettext.git", + "reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "url": "https://api.github.com/repos/php-gettext/Gettext/zipball/1bdf755a1b49f0614d6fc29f446df567eb62cd5c", + "reference": "1bdf755a1b49f0614d6fc29f446df567eb62cd5c", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.0" + "php": ">=5.3.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { - "classmap": [ - "src/" + "psr-0": { + "Gettext": "" + }, + "files": [ + "Gettext/translator_functions.php" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "AGPL-3.0" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Oscar Otero", + "email": "oom@oscarotero.com", + "homepage": "http://oscarotero.com", + "role": "Developer" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", + "description": "PHP - JS gettext conversor", + "homepage": "https://github.com/oscarotero/Gettext", "keywords": [ - "Xdebug", - "environment", - "hhvm" + "JS", + "gettext", + "i18n", + "translation" ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/master" - }, - "time": "2016-11-26T07:53:53+00:00" + "time": "2014-10-22T15:53:45+00:00" }, { - "name": "sebastian/exporter", - "version": "2.0.0", + "name": "lifo/ip", + "version": "v1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + "url": "https://github.com/lifo101/ip.git", + "reference": "b6a36dab288d7aea155698808bfc6649799fe413" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "url": "https://api.github.com/repos/lifo101/ip/zipball/b6a36dab288d7aea155698808bfc6649799fe413", + "reference": "b6a36dab288d7aea155698808bfc6649799fe413", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~2.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "ext-bcmath": "*", + "php": ">=5.3.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/master" - }, - "time": "2016-11-19T08:54:04+00:00" - }, - { - "name": "sebastian/global-state", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" + "psr-4": { + "Lifo\\IP\\": "src/" } }, - "autoload": { - "classmap": [ - "src/" - ] - }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Jason Morriss", + "email": "lifo2013@gmail.com" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", + "description": "IP address helper PHP library for working with IPv4 and IPv6 addresses", "keywords": [ - "global state" + "IP", + "ip address", + "ipv4", + "ipv6" ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/1.1.1" - }, - "time": "2015-10-12T03:26:01+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", - "shasum": "" - }, - "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~2.0" - }, - "require-dev": { - "phpunit/phpunit": "~5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/master" - }, - "time": "2017-02-18T15:18:39+00:00" + "time": "2020-04-02T11:09:10+00:00" }, { - "name": "sebastian/recursion-context", - "version": "2.0.0", + "name": "mrclay/minify", + "version": "2.3.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + "url": "https://github.com/mrclay/minify.git", + "reference": "1928e89208d28e91427b2f13b67acdbd8cd01ac9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "url": "https://api.github.com/repos/mrclay/minify/zipball/1928e89208d28e91427b2f13b67acdbd8cd01ac9", + "reference": "1928e89208d28e91427b2f13b67acdbd8cd01ac9", "shasum": "" }, "require": { - "php": ">=5.3.3" + "ext-pcre": "*", + "php": ">=5.2.1" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "tubalmartin/cssmin": "~2.4.8" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/master" - }, - "time": "2016-11-19T07:33:16+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", - "shasum": "" - }, - "require": { - "php": ">=5.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/master" - }, - "time": "2015-07-28T20:34:47+00:00" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" + "suggest": { + "tubalmartin/cssmin": "Support minify with CSSMin (YUI PHP port)" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, "autoload": { "classmap": [ - "src/" + "min/lib/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1327,31 +182,27 @@ ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "name": "Stephen Clay", + "email": "steve@mrclay.org", + "role": "Developer" } ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/master" - }, - "time": "2016-10-03T07:35:21+00:00" + "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", + "homepage": "http://code.google.com/p/minify/", + "time": "2017-11-03T21:04:01+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.20.0", + "version": "v1.23.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41" + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41", - "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", "shasum": "" }, "require": { @@ -1363,7 +214,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.23-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1400,9 +251,6 @@ "polyfill", "portable" ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.20.0" - }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -1417,131 +265,81 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2021-02-19T12:13:01+00:00" }, { - "name": "symfony/yaml", - "version": "v4.4.18", + "name": "twig/twig", + "version": "v1.44.4", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "bbce94f14d73732340740366fcbe63363663a403" + "url": "https://github.com/twigphp/Twig.git", + "reference": "4d400421528e9fa40caaffcf7824c172526dd99d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/bbce94f14d73732340740366fcbe63363663a403", - "reference": "bbce94f14d73732340740366fcbe63363663a403", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/4d400421528e9fa40caaffcf7824c172526dd99d", + "reference": "4d400421528e9fa40caaffcf7824c172526dd99d", "shasum": "" }, "require": { - "php": ">=7.1.3", - "symfony/polyfill-ctype": "~1.8" - }, - "conflict": { - "symfony/console": "<3.4" + "php": ">=7.2.5", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { - "symfony/console": "^3.4|^4.0|^5.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4.9|^5.0.9" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.44-dev" + } + }, "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" + "psr-0": { + "Twig_": "lib/" }, - "exclude-from-classmap": [ - "/Tests/" - ] + "psr-4": { + "Twig\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" } ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v4.4.18" - }, + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, { "url": "https://github.com/fabpot", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://tidelift.com/funding/github/packagist/twig/twig", "type": "tidelift" } ], - "time": "2020-12-08T16:59:59+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.9.1", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" - }, - "type": "library", - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozart/assert/issues", - "source": "https://github.com/webmozart/assert/tree/master" - }, - "time": "2020-07-08T17:02:28+00:00" + "time": "2021-05-16T12:11:20+00:00" } ], "packages-dev": [], @@ -1552,5 +350,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "1.1.0" } diff --git a/inc/anti-bot.php b/inc/anti-bot.php index b6be5e60..54c6d87b 100644 --- a/inc/anti-bot.php +++ b/inc/anti-bot.php @@ -233,66 +233,3 @@ function _create_antibot($board, $thread) { return $antibot; } -function checkSpam(array $extra_salt = array()) { - global $config, $pdo; - - if (!isset($_POST['hash'])) - return true; - - $hash = $_POST['hash']; - - if (!empty($extra_salt)) { - // create a salted hash of the "extra salt" - $extra_salt = implode(':', $extra_salt); - } else { - $extra_salt = ''; - } - - // Reconsturct the $inputs array - $inputs = array(); - - foreach ($_POST as $name => $value) { - if (in_array($name, $config['spam']['valid_inputs'])) - continue; - - $inputs[$name] = $value; - } - - // Sort the inputs in alphabetical order (A-Z) - ksort($inputs); - - $_hash = ''; - - // Iterate through each input - foreach ($inputs as $name => $value) { - print_err("-> " . $name . ' : ' . $value); - $_hash .= $name . '=' . $value; - } - - // Add a salt to the hash - $_hash .= $config['cookies']['salt']; - - // Use SHA1 for the hash - $_hash = sha1($_hash . $extra_salt); - - if ($hash != $_hash) { - print_err("Hash mismatch"); - return true; - } - - $query = prepare('SELECT `passed` FROM ``antispam`` WHERE `hash` = :hash'); - $query->bindValue(':hash', $hash); - $query->execute() or error(db_error($query)); - if ((($passed = $query->fetchColumn(0)) === false) || ($passed > $config['spam']['hidden_inputs_max_pass'])) { - // there was no database entry for this hash. most likely expired. - return true; - } - - return $hash; -} - -function incrementSpamHash($hash) { - $query = prepare('UPDATE ``antispam`` SET `passed` = `passed` + 1 WHERE `hash` = :hash'); - $query->bindValue(':hash', $hash); - $query->execute() or error(db_error($query)); -} diff --git a/inc/bans.php b/inc/bans.php index e629ddae..604aacb3 100644 --- a/inc/bans.php +++ b/inc/bans.php @@ -1,9 +1,5 @@ $value) { + if (in_array($name, $config['spam']['valid_inputs'])) + continue; + + $inputs[$name] = $value; + } + + // Sort the inputs in alphabetical order (A-Z) + ksort($inputs); + + $_hash = ''; + + // Iterate through each input + foreach ($inputs as $name => $value) { + print_err("-> " . $name . ' : ' . $value); + $_hash .= $name . '=' . $value; + } + + // Add a salt to the hash + $_hash .= $config['cookies']['salt']; + + // Use SHA1 for the hash + $_hash = sha1($_hash . $extra_salt); + + if ($hash != $_hash) { + print_err("Hash mismatch"); + return true; + } + + $query = prepare('SELECT `passed` FROM ``antispam`` WHERE `hash` = :hash'); + $query->bindValue(':hash', $hash); + $query->execute() or error(db_error($query)); + if ((($passed = $query->fetchColumn(0)) === false) || ($passed > $config['spam']['hidden_inputs_max_pass'])) { + // there was no database entry for this hash. most likely expired. + return true; + } + + return $hash; +} + +function incrementSpamHash($hash) { + $query = prepare('UPDATE ``antispam`` SET `passed` = `passed` + 1 WHERE `hash` = :hash'); + $query->bindValue(':hash', $hash); + $query->execute() or error(db_error($query)); +} + function buildIndex($global_api = "yes") { global $board, $config, $build_pages; @@ -1746,7 +1789,6 @@ function buildJavascript() { } if ($config['minify_js']) { - require_once 'inc/lib/minify/JSMin.php'; $script = JSMin::minify($script); } diff --git a/inc/lib/Twig/Autoloader.php b/inc/lib/Twig/Autoloader.php deleted file mode 100644 index 212af544..00000000 --- a/inc/lib/Twig/Autoloader.php +++ /dev/null @@ -1,54 +0,0 @@ - - * - * @deprecated since 1.21 and will be removed in 2.0. Use Composer instead. 2.0. - */ -class Twig_Autoloader -{ - /** - * Registers Twig_Autoloader as an SPL autoloader. - * - * @param bool $prepend whether to prepend the autoloader or not - */ - public static function register($prepend = false) - { - @trigger_error('Using Twig_Autoloader is deprecated since version 1.21. Use Composer instead.', E_USER_DEPRECATED); - - if (PHP_VERSION_ID < 50300) { - spl_autoload_register(array(__CLASS__, 'autoload')); - } else { - spl_autoload_register(array(__CLASS__, 'autoload'), true, $prepend); - } - } - - /** - * Handles autoloading of classes. - * - * @param string $class a class name - */ - public static function autoload($class) - { - if (0 !== strpos($class, 'Twig')) { - return; - } - - if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) { - require $file; - } - } -} diff --git a/inc/lib/Twig/BaseNodeVisitor.php b/inc/lib/Twig/BaseNodeVisitor.php deleted file mode 100644 index d8ef02fb..00000000 --- a/inc/lib/Twig/BaseNodeVisitor.php +++ /dev/null @@ -1,54 +0,0 @@ - - */ -abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface -{ - final public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) - { - if (!$node instanceof Twig_Node) { - throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.'); - } - - return $this->doEnterNode($node, $env); - } - - final public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) - { - if (!$node instanceof Twig_Node) { - throw new LogicException('Twig_BaseNodeVisitor only supports Twig_Node instances.'); - } - - return $this->doLeaveNode($node, $env); - } - - /** - * Called before child nodes are visited. - * - * @return Twig_Node The modified node - */ - abstract protected function doEnterNode(Twig_Node $node, Twig_Environment $env); - - /** - * Called after child nodes are visited. - * - * @return Twig_Node|false The modified node or false if the node must be removed - */ - abstract protected function doLeaveNode(Twig_Node $node, Twig_Environment $env); -} - -class_alias('Twig_BaseNodeVisitor', 'Twig\NodeVisitor\AbstractNodeVisitor', false); -class_exists('Twig_Environment'); -class_exists('Twig_Node'); diff --git a/inc/lib/Twig/Cache/Filesystem.php b/inc/lib/Twig/Cache/Filesystem.php deleted file mode 100644 index 65976282..00000000 --- a/inc/lib/Twig/Cache/Filesystem.php +++ /dev/null @@ -1,93 +0,0 @@ - - */ -class Twig_Cache_Filesystem implements Twig_CacheInterface -{ - const FORCE_BYTECODE_INVALIDATION = 1; - - private $directory; - private $options; - - /** - * @param $directory string The root cache directory - * @param $options int A set of options - */ - public function __construct($directory, $options = 0) - { - $this->directory = rtrim($directory, '\/').'/'; - $this->options = $options; - } - - public function generateKey($name, $className) - { - $hash = hash('sha256', $className); - - return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php'; - } - - public function load($key) - { - if (file_exists($key)) { - @include_once $key; - } - } - - public function write($key, $content) - { - $dir = dirname($key); - if (!is_dir($dir)) { - if (false === @mkdir($dir, 0777, true)) { - if (PHP_VERSION_ID >= 50300) { - clearstatcache(true, $dir); - } - if (!is_dir($dir)) { - throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir)); - } - } - } elseif (!is_writable($dir)) { - throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir)); - } - - $tmpFile = tempnam($dir, basename($key)); - if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) { - @chmod($key, 0666 & ~umask()); - - if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) { - // Compile cached file into bytecode cache - if (function_exists('opcache_invalidate')) { - opcache_invalidate($key, true); - } elseif (function_exists('apc_compile_file')) { - apc_compile_file($key); - } - } - - return; - } - - throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key)); - } - - public function getTimestamp($key) - { - if (!file_exists($key)) { - return 0; - } - - return (int) @filemtime($key); - } -} - -class_alias('Twig_Cache_Filesystem', 'Twig\Cache\FilesystemCache', false); diff --git a/inc/lib/Twig/Cache/Null.php b/inc/lib/Twig/Cache/Null.php deleted file mode 100644 index 69d1d2f9..00000000 --- a/inc/lib/Twig/Cache/Null.php +++ /dev/null @@ -1,40 +0,0 @@ - - */ -class Twig_Cache_Null implements Twig_CacheInterface -{ - public function generateKey($name, $className) - { - return ''; - } - - public function write($key, $content) - { - } - - public function load($key) - { - } - - public function getTimestamp($key) - { - return 0; - } -} - -class_alias('Twig_Cache_Null', 'Twig\Cache\NullCache', false); diff --git a/inc/lib/Twig/CacheInterface.php b/inc/lib/Twig/CacheInterface.php deleted file mode 100644 index 776808bf..00000000 --- a/inc/lib/Twig/CacheInterface.php +++ /dev/null @@ -1,58 +0,0 @@ - - */ -interface Twig_CacheInterface -{ - /** - * Generates a cache key for the given template class name. - * - * @param string $name The template name - * @param string $className The template class name - * - * @return string - */ - public function generateKey($name, $className); - - /** - * Writes the compiled template to cache. - * - * @param string $key The cache key - * @param string $content The template representation as a PHP class - */ - public function write($key, $content); - - /** - * Loads a template from the cache. - * - * @param string $key The cache key - */ - public function load($key); - - /** - * Returns the modification timestamp of a key. - * - * @param string $key The cache key - * - * @return int - */ - public function getTimestamp($key); -} - -class_alias('Twig_CacheInterface', 'Twig\Cache\CacheInterface', false); diff --git a/inc/lib/Twig/Compiler.php b/inc/lib/Twig/Compiler.php deleted file mode 100644 index 803eb896..00000000 --- a/inc/lib/Twig/Compiler.php +++ /dev/null @@ -1,286 +0,0 @@ - - */ -class Twig_Compiler implements Twig_CompilerInterface -{ - protected $lastLine; - protected $source; - protected $indentation; - protected $env; - protected $debugInfo = array(); - protected $sourceOffset; - protected $sourceLine; - protected $filename; - private $varNameSalt = 0; - - public function __construct(Twig_Environment $env) - { - $this->env = $env; - } - - /** - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - return $this->filename; - } - - /** - * Returns the environment instance related to this compiler. - * - * @return Twig_Environment - */ - public function getEnvironment() - { - return $this->env; - } - - /** - * Gets the current PHP code after compilation. - * - * @return string The PHP code - */ - public function getSource() - { - return $this->source; - } - - /** - * Compiles a node. - * - * @param Twig_NodeInterface $node The node to compile - * @param int $indentation The current indentation - * - * @return $this - */ - public function compile(Twig_NodeInterface $node, $indentation = 0) - { - $this->lastLine = null; - $this->source = ''; - $this->debugInfo = array(); - $this->sourceOffset = 0; - // source code starts at 1 (as we then increment it when we encounter new lines) - $this->sourceLine = 1; - $this->indentation = $indentation; - $this->varNameSalt = 0; - - if ($node instanceof Twig_Node_Module) { - // to be removed in 2.0 - $this->filename = $node->getTemplateName(); - } - - $node->compile($this); - - return $this; - } - - public function subcompile(Twig_NodeInterface $node, $raw = true) - { - if (false === $raw) { - $this->source .= str_repeat(' ', $this->indentation * 4); - } - - $node->compile($this); - - return $this; - } - - /** - * Adds a raw string to the compiled code. - * - * @param string $string The string - * - * @return $this - */ - public function raw($string) - { - $this->source .= $string; - - return $this; - } - - /** - * Writes a string to the compiled code by adding indentation. - * - * @return $this - */ - public function write() - { - $strings = func_get_args(); - foreach ($strings as $string) { - $this->source .= str_repeat(' ', $this->indentation * 4).$string; - } - - return $this; - } - - /** - * Appends an indentation to the current PHP code after compilation. - * - * @return $this - * - * @deprecated since 1.27 (to be removed in 2.0). - */ - public function addIndentation() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use write(\'\') instead.', E_USER_DEPRECATED); - - $this->source .= str_repeat(' ', $this->indentation * 4); - - return $this; - } - - /** - * Adds a quoted string to the compiled code. - * - * @param string $value The string - * - * @return $this - */ - public function string($value) - { - $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\")); - - return $this; - } - - /** - * Returns a PHP representation of a given value. - * - * @param mixed $value The value to convert - * - * @return $this - */ - public function repr($value) - { - if (is_int($value) || is_float($value)) { - if (false !== $locale = setlocale(LC_NUMERIC, '0')) { - setlocale(LC_NUMERIC, 'C'); - } - - $this->raw($value); - - if (false !== $locale) { - setlocale(LC_NUMERIC, $locale); - } - } elseif (null === $value) { - $this->raw('null'); - } elseif (is_bool($value)) { - $this->raw($value ? 'true' : 'false'); - } elseif (is_array($value)) { - $this->raw('array('); - $first = true; - foreach ($value as $key => $v) { - if (!$first) { - $this->raw(', '); - } - $first = false; - $this->repr($key); - $this->raw(' => '); - $this->repr($v); - } - $this->raw(')'); - } else { - $this->string($value); - } - - return $this; - } - - /** - * Adds debugging information. - * - * @return $this - */ - public function addDebugInfo(Twig_NodeInterface $node) - { - if ($node->getTemplateLine() != $this->lastLine) { - $this->write(sprintf("// line %d\n", $node->getTemplateLine())); - - // when mbstring.func_overload is set to 2 - // mb_substr_count() replaces substr_count() - // but they have different signatures! - if (((int) ini_get('mbstring.func_overload')) & 2) { - @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED); - - // this is much slower than the "right" version - $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n"); - } else { - $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); - } - $this->sourceOffset = strlen($this->source); - $this->debugInfo[$this->sourceLine] = $node->getTemplateLine(); - - $this->lastLine = $node->getTemplateLine(); - } - - return $this; - } - - public function getDebugInfo() - { - ksort($this->debugInfo); - - return $this->debugInfo; - } - - /** - * Indents the generated code. - * - * @param int $step The number of indentation to add - * - * @return $this - */ - public function indent($step = 1) - { - $this->indentation += $step; - - return $this; - } - - /** - * Outdents the generated code. - * - * @param int $step The number of indentation to remove - * - * @return $this - * - * @throws LogicException When trying to outdent too much so the indentation would become negative - */ - public function outdent($step = 1) - { - // can't outdent by more steps than the current indentation level - if ($this->indentation < $step) { - throw new LogicException('Unable to call outdent() as the indentation would become negative.'); - } - - $this->indentation -= $step; - - return $this; - } - - public function getVarName() - { - return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->varNameSalt++)); - } -} - -class_alias('Twig_Compiler', 'Twig\Compiler', false); -class_exists('Twig_Node'); diff --git a/inc/lib/Twig/CompilerInterface.php b/inc/lib/Twig/CompilerInterface.php deleted file mode 100644 index 42872c9c..00000000 --- a/inc/lib/Twig/CompilerInterface.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_CompilerInterface -{ - /** - * Compiles a node. - * - * @return $this - */ - public function compile(Twig_NodeInterface $node); - - /** - * Gets the current PHP code after compilation. - * - * @return string The PHP code - */ - public function getSource(); -} diff --git a/inc/lib/Twig/ContainerRuntimeLoader.php b/inc/lib/Twig/ContainerRuntimeLoader.php deleted file mode 100644 index 814ab58b..00000000 --- a/inc/lib/Twig/ContainerRuntimeLoader.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @author Robin Chalas - */ -class Twig_ContainerRuntimeLoader implements Twig_RuntimeLoaderInterface -{ - private $container; - - public function __construct(ContainerInterface $container) - { - $this->container = $container; - } - - public function load($class) - { - if ($this->container->has($class)) { - return $this->container->get($class); - } - } -} - -class_alias('Twig_ContainerRuntimeLoader', 'Twig\RuntimeLoader\ContainerRuntimeLoader', false); diff --git a/inc/lib/Twig/Environment.php b/inc/lib/Twig/Environment.php deleted file mode 100644 index b15f2aff..00000000 --- a/inc/lib/Twig/Environment.php +++ /dev/null @@ -1,1604 +0,0 @@ - - */ -class Twig_Environment -{ - const VERSION = '1.35.4-DEV'; - const VERSION_ID = 13504; - const MAJOR_VERSION = 1; - const MINOR_VERSION = 35; - const RELEASE_VERSION = 4; - const EXTRA_VERSION = 'DEV'; - - protected $charset; - protected $loader; - protected $debug; - protected $autoReload; - protected $cache; - protected $lexer; - protected $parser; - protected $compiler; - protected $baseTemplateClass; - protected $extensions; - protected $parsers; - protected $visitors; - protected $filters; - protected $tests; - protected $functions; - protected $globals; - protected $runtimeInitialized = false; - protected $extensionInitialized = false; - protected $loadedTemplates; - protected $strictVariables; - protected $unaryOperators; - protected $binaryOperators; - protected $templateClassPrefix = '__TwigTemplate_'; - protected $functionCallbacks = array(); - protected $filterCallbacks = array(); - protected $staging; - - private $originalCache; - private $bcWriteCacheFile = false; - private $bcGetCacheFilename = false; - private $lastModifiedExtension = 0; - private $extensionsByClass = array(); - private $runtimeLoaders = array(); - private $runtimes = array(); - private $optionsHash; - private $loading = array(); - - /** - * Constructor. - * - * Available options: - * - * * debug: When set to true, it automatically set "auto_reload" to true as - * well (default to false). - * - * * charset: The charset used by the templates (default to UTF-8). - * - * * base_template_class: The base template class to use for generated - * templates (default to Twig_Template). - * - * * cache: An absolute path where to store the compiled templates, - * a Twig_Cache_Interface implementation, - * or false to disable compilation cache (default). - * - * * auto_reload: Whether to reload the template if the original source changed. - * If you don't provide the auto_reload option, it will be - * determined automatically based on the debug value. - * - * * strict_variables: Whether to ignore invalid variables in templates - * (default to false). - * - * * autoescape: Whether to enable auto-escaping (default to html): - * * false: disable auto-escaping - * * true: equivalent to html - * * html, js: set the autoescaping to one of the supported strategies - * * name: set the autoescaping strategy based on the template name extension - * * PHP callback: a PHP callback that returns an escaping strategy based on the template "name" - * - * * optimizations: A flag that indicates which optimizations to apply - * (default to -1 which means that all optimizations are enabled; - * set it to 0 to disable). - * - * @param Twig_LoaderInterface $loader - * @param array $options An array of options - */ - public function __construct(Twig_LoaderInterface $loader = null, $options = array()) - { - if (null !== $loader) { - $this->setLoader($loader); - } else { - @trigger_error('Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated since version 1.21.', E_USER_DEPRECATED); - } - - $options = array_merge(array( - 'debug' => false, - 'charset' => 'UTF-8', - 'base_template_class' => 'Twig_Template', - 'strict_variables' => false, - 'autoescape' => 'html', - 'cache' => false, - 'auto_reload' => null, - 'optimizations' => -1, - ), $options); - - $this->debug = (bool) $options['debug']; - $this->charset = strtoupper($options['charset']); - $this->baseTemplateClass = $options['base_template_class']; - $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; - $this->strictVariables = (bool) $options['strict_variables']; - $this->setCache($options['cache']); - - $this->addExtension(new Twig_Extension_Core()); - $this->addExtension(new Twig_Extension_Escaper($options['autoescape'])); - $this->addExtension(new Twig_Extension_Optimizer($options['optimizations'])); - $this->staging = new Twig_Extension_Staging(); - - // For BC - if (is_string($this->originalCache)) { - $r = new ReflectionMethod($this, 'writeCacheFile'); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error('The Twig_Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - - $this->bcWriteCacheFile = true; - } - - $r = new ReflectionMethod($this, 'getCacheFilename'); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error('The Twig_Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - - $this->bcGetCacheFilename = true; - } - } - } - - /** - * Gets the base template class for compiled templates. - * - * @return string The base template class name - */ - public function getBaseTemplateClass() - { - return $this->baseTemplateClass; - } - - /** - * Sets the base template class for compiled templates. - * - * @param string $class The base template class name - */ - public function setBaseTemplateClass($class) - { - $this->baseTemplateClass = $class; - $this->updateOptionsHash(); - } - - /** - * Enables debugging mode. - */ - public function enableDebug() - { - $this->debug = true; - $this->updateOptionsHash(); - } - - /** - * Disables debugging mode. - */ - public function disableDebug() - { - $this->debug = false; - $this->updateOptionsHash(); - } - - /** - * Checks if debug mode is enabled. - * - * @return bool true if debug mode is enabled, false otherwise - */ - public function isDebug() - { - return $this->debug; - } - - /** - * Enables the auto_reload option. - */ - public function enableAutoReload() - { - $this->autoReload = true; - } - - /** - * Disables the auto_reload option. - */ - public function disableAutoReload() - { - $this->autoReload = false; - } - - /** - * Checks if the auto_reload option is enabled. - * - * @return bool true if auto_reload is enabled, false otherwise - */ - public function isAutoReload() - { - return $this->autoReload; - } - - /** - * Enables the strict_variables option. - */ - public function enableStrictVariables() - { - $this->strictVariables = true; - $this->updateOptionsHash(); - } - - /** - * Disables the strict_variables option. - */ - public function disableStrictVariables() - { - $this->strictVariables = false; - $this->updateOptionsHash(); - } - - /** - * Checks if the strict_variables option is enabled. - * - * @return bool true if strict_variables is enabled, false otherwise - */ - public function isStrictVariables() - { - return $this->strictVariables; - } - - /** - * Gets the current cache implementation. - * - * @param bool $original Whether to return the original cache option or the real cache instance - * - * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation, - * an absolute path to the compiled templates, - * or false to disable cache - */ - public function getCache($original = true) - { - return $original ? $this->originalCache : $this->cache; - } - - /** - * Sets the current cache implementation. - * - * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation, - * an absolute path to the compiled templates, - * or false to disable cache - */ - public function setCache($cache) - { - if (is_string($cache)) { - $this->originalCache = $cache; - $this->cache = new Twig_Cache_Filesystem($cache); - } elseif (false === $cache) { - $this->originalCache = $cache; - $this->cache = new Twig_Cache_Null(); - } elseif (null === $cache) { - @trigger_error('Using "null" as the cache strategy is deprecated since version 1.23 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - $this->originalCache = false; - $this->cache = new Twig_Cache_Null(); - } elseif ($cache instanceof Twig_CacheInterface) { - $this->originalCache = $this->cache = $cache; - } else { - throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.')); - } - } - - /** - * Gets the cache filename for a given template. - * - * @param string $name The template name - * - * @return string|false The cache file name or false when caching is disabled - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function getCacheFilename($name) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - $key = $this->cache->generateKey($name, $this->getTemplateClass($name)); - - return !$key ? false : $key; - } - - /** - * Gets the template class associated with the given string. - * - * The generated template class is based on the following parameters: - * - * * The cache key for the given template; - * * The currently enabled extensions; - * * Whether the Twig C extension is available or not; - * * PHP version; - * * Twig version; - * * Options with what environment was created. - * - * @param string $name The name for which to calculate the template class name - * @param int|null $index The index if it is an embedded template - * - * @return string The template class name - */ - public function getTemplateClass($name, $index = null) - { - $key = $this->getLoader()->getCacheKey($name).$this->optionsHash; - - return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index); - } - - /** - * Gets the template class prefix. - * - * @return string The template class prefix - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function getTemplateClassPrefix() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - return $this->templateClassPrefix; - } - - /** - * Renders a template. - * - * @param string $name The template name - * @param array $context An array of parameters to pass to the template - * - * @return string The rendered template - * - * @throws Twig_Error_Loader When the template cannot be found - * @throws Twig_Error_Syntax When an error occurred during compilation - * @throws Twig_Error_Runtime When an error occurred during rendering - */ - public function render($name, array $context = array()) - { - return $this->loadTemplate($name)->render($context); - } - - /** - * Displays a template. - * - * @param string $name The template name - * @param array $context An array of parameters to pass to the template - * - * @throws Twig_Error_Loader When the template cannot be found - * @throws Twig_Error_Syntax When an error occurred during compilation - * @throws Twig_Error_Runtime When an error occurred during rendering - */ - public function display($name, array $context = array()) - { - $this->loadTemplate($name)->display($context); - } - - /** - * Loads a template. - * - * @param string|Twig_TemplateWrapper|Twig_Template $name The template name - * - * @throws Twig_Error_Loader When the template cannot be found - * @throws Twig_Error_Runtime When a previously generated cache is corrupted - * @throws Twig_Error_Syntax When an error occurred during compilation - * - * @return Twig_TemplateWrapper - */ - public function load($name) - { - if ($name instanceof Twig_TemplateWrapper) { - return $name; - } - - if ($name instanceof Twig_Template) { - return new Twig_TemplateWrapper($this, $name); - } - - return new Twig_TemplateWrapper($this, $this->loadTemplate($name)); - } - - /** - * Loads a template internal representation. - * - * This method is for internal use only and should never be called - * directly. - * - * @param string $name The template name - * @param int $index The index if it is an embedded template - * - * @return Twig_TemplateInterface A template instance representing the given template name - * - * @throws Twig_Error_Loader When the template cannot be found - * @throws Twig_Error_Runtime When a previously generated cache is corrupted - * @throws Twig_Error_Syntax When an error occurred during compilation - * - * @internal - */ - public function loadTemplate($name, $index = null) - { - $cls = $mainCls = $this->getTemplateClass($name); - if (null !== $index) { - $cls .= '_'.$index; - } - - if (isset($this->loadedTemplates[$cls])) { - return $this->loadedTemplates[$cls]; - } - - if (!class_exists($cls, false)) { - if ($this->bcGetCacheFilename) { - $key = $this->getCacheFilename($name); - } else { - $key = $this->cache->generateKey($name, $mainCls); - } - - if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) { - $this->cache->load($key); - } - - if (!class_exists($cls, false)) { - $loader = $this->getLoader(); - if (!$loader instanceof Twig_SourceContextLoaderInterface) { - $source = new Twig_Source($loader->getSource($name), $name); - } else { - $source = $loader->getSourceContext($name); - } - - $content = $this->compileSource($source); - - if ($this->bcWriteCacheFile) { - $this->writeCacheFile($key, $content); - } else { - $this->cache->write($key, $content); - $this->cache->load($key); - } - - if (!class_exists($mainCls, false)) { - /* Last line of defense if either $this->bcWriteCacheFile was used, - * $this->cache is implemented as a no-op or we have a race condition - * where the cache was cleared between the above calls to write to and load from - * the cache. - */ - eval('?>'.$content); - } - } - - if (!class_exists($cls, false)) { - throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source); - } - } - - if (!$this->runtimeInitialized) { - $this->initRuntime(); - } - - if (isset($this->loading[$cls])) { - throw new Twig_Error_Runtime(sprintf('Circular reference detected for Twig template "%s", path: %s.', $name, implode(' -> ', array_merge($this->loading, array($name))))); - } - - $this->loading[$cls] = $name; - - try { - $this->loadedTemplates[$cls] = new $cls($this); - unset($this->loading[$cls]); - } catch (\Exception $e) { - unset($this->loading[$cls]); - - throw $e; - } - - return $this->loadedTemplates[$cls]; - } - - /** - * Creates a template from source. - * - * This method should not be used as a generic way to load templates. - * - * @param string $template The template name - * - * @return Twig_Template A template instance representing the given template name - * - * @throws Twig_Error_Loader When the template cannot be found - * @throws Twig_Error_Syntax When an error occurred during compilation - */ - public function createTemplate($template) - { - $name = sprintf('__string_template__%s', hash('sha256', $template, false)); - - $loader = new Twig_Loader_Chain(array( - new Twig_Loader_Array(array($name => $template)), - $current = $this->getLoader(), - )); - - $this->setLoader($loader); - try { - $template = $this->loadTemplate($name); - } catch (Exception $e) { - $this->setLoader($current); - - throw $e; - } catch (Throwable $e) { - $this->setLoader($current); - - throw $e; - } - $this->setLoader($current); - - return $template; - } - - /** - * Returns true if the template is still fresh. - * - * Besides checking the loader for freshness information, - * this method also checks if the enabled extensions have - * not changed. - * - * @param string $name The template name - * @param int $time The last modification time of the cached template - * - * @return bool true if the template is fresh, false otherwise - */ - public function isTemplateFresh($name, $time) - { - if (0 === $this->lastModifiedExtension) { - foreach ($this->extensions as $extension) { - $r = new ReflectionObject($extension); - if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) { - $this->lastModifiedExtension = $extensionTime; - } - } - } - - return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time); - } - - /** - * Tries to load a template consecutively from an array. - * - * Similar to loadTemplate() but it also accepts instances of Twig_Template and - * Twig_TemplateWrapper, and an array of templates where each is tried to be loaded. - * - * @param string|Twig_Template|Twig_TemplateWrapper|array $names A template or an array of templates to try consecutively - * - * @return Twig_Template|Twig_TemplateWrapper - * - * @throws Twig_Error_Loader When none of the templates can be found - * @throws Twig_Error_Syntax When an error occurred during compilation - */ - public function resolveTemplate($names) - { - if (!is_array($names)) { - $names = array($names); - } - - foreach ($names as $name) { - if ($name instanceof Twig_Template) { - return $name; - } - - if ($name instanceof Twig_TemplateWrapper) { - return $name; - } - - try { - return $this->loadTemplate($name); - } catch (Twig_Error_Loader $e) { - } - } - - if (1 === count($names)) { - throw $e; - } - - throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); - } - - /** - * Clears the internal template cache. - * - * @deprecated since 1.18.3 (to be removed in 2.0) - */ - public function clearTemplateCache() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.18.3 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - $this->loadedTemplates = array(); - } - - /** - * Clears the template cache files on the filesystem. - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function clearCacheFiles() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - if (is_string($this->originalCache)) { - foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - if ($file->isFile()) { - @unlink($file->getPathname()); - } - } - } - } - - /** - * Gets the Lexer instance. - * - * @return Twig_LexerInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getLexer() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->lexer) { - $this->lexer = new Twig_Lexer($this); - } - - return $this->lexer; - } - - public function setLexer(Twig_LexerInterface $lexer) - { - $this->lexer = $lexer; - } - - /** - * Tokenizes a source code. - * - * @param string|Twig_Source $source The template source code - * @param string $name The template name (deprecated) - * - * @return Twig_TokenStream - * - * @throws Twig_Error_Syntax When the code is syntactically wrong - */ - public function tokenize($source, $name = null) - { - if (!$source instanceof Twig_Source) { - @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Twig_Source($source, $name); - } - - if (null === $this->lexer) { - $this->lexer = new Twig_Lexer($this); - } - - return $this->lexer->tokenize($source); - } - - /** - * Gets the Parser instance. - * - * @return Twig_ParserInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getParser() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->parser) { - $this->parser = new Twig_Parser($this); - } - - return $this->parser; - } - - public function setParser(Twig_ParserInterface $parser) - { - $this->parser = $parser; - } - - /** - * Converts a token stream to a node tree. - * - * @return Twig_Node_Module - * - * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong - */ - public function parse(Twig_TokenStream $stream) - { - if (null === $this->parser) { - $this->parser = new Twig_Parser($this); - } - - return $this->parser->parse($stream); - } - - /** - * Gets the Compiler instance. - * - * @return Twig_CompilerInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getCompiler() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->compiler) { - $this->compiler = new Twig_Compiler($this); - } - - return $this->compiler; - } - - public function setCompiler(Twig_CompilerInterface $compiler) - { - $this->compiler = $compiler; - } - - /** - * Compiles a node and returns the PHP code. - * - * @return string The compiled PHP source code - */ - public function compile(Twig_NodeInterface $node) - { - if (null === $this->compiler) { - $this->compiler = new Twig_Compiler($this); - } - - return $this->compiler->compile($node)->getSource(); - } - - /** - * Compiles a template source code. - * - * @param string|Twig_Source $source The template source code - * @param string $name The template name (deprecated) - * - * @return string The compiled PHP source code - * - * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling - */ - public function compileSource($source, $name = null) - { - if (!$source instanceof Twig_Source) { - @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Twig_Source($source, $name); - } - - try { - return $this->compile($this->parse($this->tokenize($source))); - } catch (Twig_Error $e) { - $e->setSourceContext($source); - throw $e; - } catch (Exception $e) { - throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e); - } - } - - public function setLoader(Twig_LoaderInterface $loader) - { - if (!$loader instanceof Twig_SourceContextLoaderInterface && 0 !== strpos(get_class($loader), 'Mock_')) { - @trigger_error(sprintf('Twig loader "%s" should implement Twig_SourceContextLoaderInterface since version 1.27.', get_class($loader)), E_USER_DEPRECATED); - } - - $this->loader = $loader; - } - - /** - * Gets the Loader instance. - * - * @return Twig_LoaderInterface - */ - public function getLoader() - { - if (null === $this->loader) { - throw new LogicException('You must set a loader first.'); - } - - return $this->loader; - } - - /** - * Sets the default template charset. - * - * @param string $charset The default charset - */ - public function setCharset($charset) - { - $this->charset = strtoupper($charset); - } - - /** - * Gets the default template charset. - * - * @return string The default charset - */ - public function getCharset() - { - return $this->charset; - } - - /** - * Initializes the runtime environment. - * - * @deprecated since 1.23 (to be removed in 2.0) - */ - public function initRuntime() - { - $this->runtimeInitialized = true; - - foreach ($this->getExtensions() as $name => $extension) { - if (!$extension instanceof Twig_Extension_InitRuntimeInterface) { - $m = new ReflectionMethod($extension, 'initRuntime'); - - if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { - @trigger_error(sprintf('Defining the initRuntime() method in the "%s" extension is deprecated since version 1.23. Use the `needs_environment` option to get the Twig_Environment instance in filters, functions, or tests; or explicitly implement Twig_Extension_InitRuntimeInterface if needed (not recommended).', $name), E_USER_DEPRECATED); - } - } - - $extension->initRuntime($this); - } - } - - /** - * Returns true if the given extension is registered. - * - * @param string $class The extension class name - * - * @return bool Whether the extension is registered or not - */ - public function hasExtension($class) - { - $class = ltrim($class, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - return true; - } - - return isset($this->extensionsByClass[$class]); - } - - /** - * Adds a runtime loader. - */ - public function addRuntimeLoader(Twig_RuntimeLoaderInterface $loader) - { - $this->runtimeLoaders[] = $loader; - } - - /** - * Gets an extension by class name. - * - * @param string $class The extension class name - * - * @return Twig_ExtensionInterface - */ - public function getExtension($class) - { - $class = ltrim($class, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - return $this->extensions[$class]; - } - - if (!isset($this->extensionsByClass[$class])) { - throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class)); - } - - return $this->extensionsByClass[$class]; - } - - /** - * Returns the runtime implementation of a Twig element (filter/function/test). - * - * @param string $class A runtime class name - * - * @return object The runtime implementation - * - * @throws Twig_Error_Runtime When the template cannot be found - */ - public function getRuntime($class) - { - if (isset($this->runtimes[$class])) { - return $this->runtimes[$class]; - } - - foreach ($this->runtimeLoaders as $loader) { - if (null !== $runtime = $loader->load($class)) { - return $this->runtimes[$class] = $runtime; - } - } - - throw new Twig_Error_Runtime(sprintf('Unable to load the "%s" runtime.', $class)); - } - - public function addExtension(Twig_ExtensionInterface $extension) - { - if ($this->extensionInitialized) { - throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); - } - - $class = get_class($extension); - if ($class !== $extension->getName()) { - if (isset($this->extensions[$extension->getName()])) { - unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]); - @trigger_error(sprintf('The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.', $extension->getName()), E_USER_DEPRECATED); - } - } - - $this->lastModifiedExtension = 0; - $this->extensionsByClass[$class] = $extension; - $this->extensions[$extension->getName()] = $extension; - $this->updateOptionsHash(); - } - - /** - * Removes an extension by name. - * - * This method is deprecated and you should not use it. - * - * @param string $name The extension name - * - * @deprecated since 1.12 (to be removed in 2.0) - */ - public function removeExtension($name) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - if ($this->extensionInitialized) { - throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); - } - - $class = ltrim($name, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - unset($this->extensions[$class]); - } - - unset($this->extensions[$class]); - $this->updateOptionsHash(); - } - - /** - * Registers an array of extensions. - * - * @param array $extensions An array of extensions - */ - public function setExtensions(array $extensions) - { - foreach ($extensions as $extension) { - $this->addExtension($extension); - } - } - - /** - * Returns all registered extensions. - * - * @return Twig_ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on) - */ - public function getExtensions() - { - return $this->extensions; - } - - public function addTokenParser(Twig_TokenParserInterface $parser) - { - if ($this->extensionInitialized) { - throw new LogicException('Unable to add a token parser as extensions have already been initialized.'); - } - - $this->staging->addTokenParser($parser); - } - - /** - * Gets the registered Token Parsers. - * - * @return Twig_TokenParserBrokerInterface - * - * @internal - */ - public function getTokenParsers() - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->parsers; - } - - /** - * Gets registered tags. - * - * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes. - * - * @return Twig_TokenParserInterface[] - * - * @internal - */ - public function getTags() - { - $tags = array(); - foreach ($this->getTokenParsers()->getParsers() as $parser) { - if ($parser instanceof Twig_TokenParserInterface) { - $tags[$parser->getTag()] = $parser; - } - } - - return $tags; - } - - public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) - { - if ($this->extensionInitialized) { - throw new LogicException('Unable to add a node visitor as extensions have already been initialized.'); - } - - $this->staging->addNodeVisitor($visitor); - } - - /** - * Gets the registered Node Visitors. - * - * @return Twig_NodeVisitorInterface[] - * - * @internal - */ - public function getNodeVisitors() - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->visitors; - } - - /** - * Registers a Filter. - * - * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance - * @param Twig_FilterInterface|Twig_SimpleFilter $filter - */ - public function addFilter($name, $filter = null) - { - if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) { - throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter.'); - } - - if ($name instanceof Twig_SimpleFilter) { - $filter = $name; - $name = $filter->getName(); - } else { - @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFilter" instead when defining filter "%s".', __METHOD__, $name), E_USER_DEPRECATED); - } - - if ($this->extensionInitialized) { - throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addFilter($name, $filter); - } - - /** - * Get a filter by name. - * - * Subclasses may override this method and load filters differently; - * so no list of filters is available. - * - * @param string $name The filter name - * - * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist - * - * @internal - */ - public function getFilter($name) - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - if (isset($this->filters[$name])) { - return $this->filters[$name]; - } - - foreach ($this->filters as $pattern => $filter) { - $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); - - if ($count) { - if (preg_match('#^'.$pattern.'$#', $name, $matches)) { - array_shift($matches); - $filter->setArguments($matches); - - return $filter; - } - } - } - - foreach ($this->filterCallbacks as $callback) { - if (false !== $filter = call_user_func($callback, $name)) { - return $filter; - } - } - - return false; - } - - public function registerUndefinedFilterCallback($callable) - { - $this->filterCallbacks[] = $callable; - } - - /** - * Gets the registered Filters. - * - * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback. - * - * @return Twig_FilterInterface[] - * - * @see registerUndefinedFilterCallback - * - * @internal - */ - public function getFilters() - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->filters; - } - - /** - * Registers a Test. - * - * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance - * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance - */ - public function addTest($name, $test = null) - { - if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) { - throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest.'); - } - - if ($name instanceof Twig_SimpleTest) { - $test = $name; - $name = $test->getName(); - } else { - @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleTest" instead when defining test "%s".', __METHOD__, $name), E_USER_DEPRECATED); - } - - if ($this->extensionInitialized) { - throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addTest($name, $test); - } - - /** - * Gets the registered Tests. - * - * @return Twig_TestInterface[] - * - * @internal - */ - public function getTests() - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->tests; - } - - /** - * Gets a test by name. - * - * @param string $name The test name - * - * @return Twig_Test|false A Twig_Test instance or false if the test does not exist - * - * @internal - */ - public function getTest($name) - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - if (isset($this->tests[$name])) { - return $this->tests[$name]; - } - - return false; - } - - /** - * Registers a Function. - * - * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance - * @param Twig_FunctionInterface|Twig_SimpleFunction $function - */ - public function addFunction($name, $function = null) - { - if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) { - throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction.'); - } - - if ($name instanceof Twig_SimpleFunction) { - $function = $name; - $name = $function->getName(); - } else { - @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFunction" instead when defining function "%s".', __METHOD__, $name), E_USER_DEPRECATED); - } - - if ($this->extensionInitialized) { - throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addFunction($name, $function); - } - - /** - * Get a function by name. - * - * Subclasses may override this method and load functions differently; - * so no list of functions is available. - * - * @param string $name function name - * - * @return Twig_Function|false A Twig_Function instance or false if the function does not exist - * - * @internal - */ - public function getFunction($name) - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - if (isset($this->functions[$name])) { - return $this->functions[$name]; - } - - foreach ($this->functions as $pattern => $function) { - $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); - - if ($count) { - if (preg_match('#^'.$pattern.'$#', $name, $matches)) { - array_shift($matches); - $function->setArguments($matches); - - return $function; - } - } - } - - foreach ($this->functionCallbacks as $callback) { - if (false !== $function = call_user_func($callback, $name)) { - return $function; - } - } - - return false; - } - - public function registerUndefinedFunctionCallback($callable) - { - $this->functionCallbacks[] = $callable; - } - - /** - * Gets registered functions. - * - * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. - * - * @return Twig_FunctionInterface[] - * - * @see registerUndefinedFunctionCallback - * - * @internal - */ - public function getFunctions() - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->functions; - } - - /** - * Registers a Global. - * - * New globals can be added before compiling or rendering a template; - * but after, you can only update existing globals. - * - * @param string $name The global name - * @param mixed $value The global value - */ - public function addGlobal($name, $value) - { - if ($this->extensionInitialized || $this->runtimeInitialized) { - if (null === $this->globals) { - $this->globals = $this->initGlobals(); - } - - if (!array_key_exists($name, $this->globals)) { - // The deprecation notice must be turned into the following exception in Twig 2.0 - @trigger_error(sprintf('Registering global variable "%s" at runtime or when the extensions have already been initialized is deprecated since version 1.21.', $name), E_USER_DEPRECATED); - //throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); - } - } - - if ($this->extensionInitialized || $this->runtimeInitialized) { - // update the value - $this->globals[$name] = $value; - } else { - $this->staging->addGlobal($name, $value); - } - } - - /** - * Gets the registered Globals. - * - * @return array An array of globals - * - * @internal - */ - public function getGlobals() - { - if (!$this->runtimeInitialized && !$this->extensionInitialized) { - return $this->initGlobals(); - } - - if (null === $this->globals) { - $this->globals = $this->initGlobals(); - } - - return $this->globals; - } - - /** - * Merges a context with the defined globals. - * - * @param array $context An array representing the context - * - * @return array The context merged with the globals - */ - public function mergeGlobals(array $context) - { - // we don't use array_merge as the context being generally - // bigger than globals, this code is faster. - foreach ($this->getGlobals() as $key => $value) { - if (!array_key_exists($key, $context)) { - $context[$key] = $value; - } - } - - return $context; - } - - /** - * Gets the registered unary Operators. - * - * @return array An array of unary operators - * - * @internal - */ - public function getUnaryOperators() - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->unaryOperators; - } - - /** - * Gets the registered binary Operators. - * - * @return array An array of binary operators - * - * @internal - */ - public function getBinaryOperators() - { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->binaryOperators; - } - - /** - * @deprecated since 1.23 (to be removed in 2.0) - */ - public function computeAlternatives($name, $items) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - return Twig_Error_Syntax::computeAlternatives($name, $items); - } - - /** - * @internal - */ - protected function initGlobals() - { - $globals = array(); - foreach ($this->extensions as $name => $extension) { - if (!$extension instanceof Twig_Extension_GlobalsInterface) { - $m = new ReflectionMethod($extension, 'getGlobals'); - - if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { - @trigger_error(sprintf('Defining the getGlobals() method in the "%s" extension without explicitly implementing Twig_Extension_GlobalsInterface is deprecated since version 1.23.', $name), E_USER_DEPRECATED); - } - } - - $extGlob = $extension->getGlobals(); - if (!is_array($extGlob)) { - throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension))); - } - - $globals[] = $extGlob; - } - - $globals[] = $this->staging->getGlobals(); - - return call_user_func_array('array_merge', $globals); - } - - /** - * @internal - */ - protected function initExtensions() - { - if ($this->extensionInitialized) { - return; - } - - $this->parsers = new Twig_TokenParserBroker(array(), array(), false); - $this->filters = array(); - $this->functions = array(); - $this->tests = array(); - $this->visitors = array(); - $this->unaryOperators = array(); - $this->binaryOperators = array(); - - foreach ($this->extensions as $extension) { - $this->initExtension($extension); - } - $this->initExtension($this->staging); - // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception - $this->extensionInitialized = true; - } - - /** - * @internal - */ - protected function initExtension(Twig_ExtensionInterface $extension) - { - // filters - foreach ($extension->getFilters() as $name => $filter) { - if ($filter instanceof Twig_SimpleFilter) { - $name = $filter->getName(); - } else { - @trigger_error(sprintf('Using an instance of "%s" for filter "%s" is deprecated since version 1.21. Use Twig_SimpleFilter instead.', get_class($filter), $name), E_USER_DEPRECATED); - } - - $this->filters[$name] = $filter; - } - - // functions - foreach ($extension->getFunctions() as $name => $function) { - if ($function instanceof Twig_SimpleFunction) { - $name = $function->getName(); - } else { - @trigger_error(sprintf('Using an instance of "%s" for function "%s" is deprecated since version 1.21. Use Twig_SimpleFunction instead.', get_class($function), $name), E_USER_DEPRECATED); - } - - $this->functions[$name] = $function; - } - - // tests - foreach ($extension->getTests() as $name => $test) { - if ($test instanceof Twig_SimpleTest) { - $name = $test->getName(); - } else { - @trigger_error(sprintf('Using an instance of "%s" for test "%s" is deprecated since version 1.21. Use Twig_SimpleTest instead.', get_class($test), $name), E_USER_DEPRECATED); - } - - $this->tests[$name] = $test; - } - - // token parsers - foreach ($extension->getTokenParsers() as $parser) { - if ($parser instanceof Twig_TokenParserInterface) { - $this->parsers->addTokenParser($parser); - } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { - @trigger_error('Registering a Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.', E_USER_DEPRECATED); - - $this->parsers->addTokenParserBroker($parser); - } else { - throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances.'); - } - } - - // node visitors - foreach ($extension->getNodeVisitors() as $visitor) { - $this->visitors[] = $visitor; - } - - // operators - if ($operators = $extension->getOperators()) { - if (!is_array($operators)) { - throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', get_class($extension), is_object($operators) ? get_class($operators) : gettype($operators).(is_resource($operators) ? '' : '#'.$operators))); - } - - if (2 !== count($operators)) { - throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', get_class($extension), count($operators))); - } - - $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); - $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); - } - } - - /** - * @deprecated since 1.22 (to be removed in 2.0) - */ - protected function writeCacheFile($file, $content) - { - $this->cache->write($file, $content); - } - - private function updateOptionsHash() - { - $hashParts = array_merge( - array_keys($this->extensions), - array( - (int) function_exists('twig_template_get_attributes'), - PHP_MAJOR_VERSION, - PHP_MINOR_VERSION, - self::VERSION, - (int) $this->debug, - $this->baseTemplateClass, - (int) $this->strictVariables, - ) - ); - $this->optionsHash = implode(':', $hashParts); - } -} - -class_alias('Twig_Environment', 'Twig\Environment', false); diff --git a/inc/lib/Twig/Error.php b/inc/lib/Twig/Error.php deleted file mode 100644 index 787e0d09..00000000 --- a/inc/lib/Twig/Error.php +++ /dev/null @@ -1,363 +0,0 @@ - - */ -class Twig_Error extends Exception -{ - protected $lineno; - // to be renamed to name in 2.0 - protected $filename; - protected $rawMessage; - protected $previous; - - private $sourcePath; - private $sourceCode; - - /** - * Constructor. - * - * Set both the line number and the name to false to - * disable automatic guessing of the original template name - * and line number. - * - * Set the line number to -1 to enable its automatic guessing. - * Set the name to null to enable its automatic guessing. - * - * By default, automatic guessing is enabled. - * - * @param string $message The error message - * @param int $lineno The template line where the error occurred - * @param Twig_Source|string|null $source The source context where the error occurred - * @param Exception $previous The previous exception - */ - public function __construct($message, $lineno = -1, $source = null, Exception $previous = null) - { - if (null === $source) { - $name = null; - } elseif (!$source instanceof Twig_Source) { - // for compat with the Twig C ext., passing the template name as string is accepted - $name = $source; - } else { - $name = $source->getName(); - $this->sourceCode = $source->getCode(); - $this->sourcePath = $source->getPath(); - } - if (PHP_VERSION_ID < 50300) { - $this->previous = $previous; - parent::__construct(''); - } else { - parent::__construct('', 0, $previous); - } - - $this->lineno = $lineno; - $this->filename = $name; - - if (-1 === $lineno || null === $name || null === $this->sourcePath) { - $this->guessTemplateInfo(); - } - - $this->rawMessage = $message; - - $this->updateRepr(); - } - - /** - * Gets the raw message. - * - * @return string The raw message - */ - public function getRawMessage() - { - return $this->rawMessage; - } - - /** - * Gets the logical name where the error occurred. - * - * @return string The name - * - * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead. - */ - public function getTemplateFile() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->filename; - } - - /** - * Sets the logical name where the error occurred. - * - * @param string $name The name - * - * @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead. - */ - public function setTemplateFile($name) - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - $this->filename = $name; - - $this->updateRepr(); - } - - /** - * Gets the logical name where the error occurred. - * - * @return string The name - * - * @deprecated since 1.29 (to be removed in 2.0). Use getSourceContext() instead. - */ - public function getTemplateName() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->filename; - } - - /** - * Sets the logical name where the error occurred. - * - * @param string $name The name - * - * @deprecated since 1.29 (to be removed in 2.0). Use setSourceContext() instead. - */ - public function setTemplateName($name) - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - $this->filename = $name; - $this->sourceCode = $this->sourcePath = null; - - $this->updateRepr(); - } - - /** - * Gets the template line where the error occurred. - * - * @return int The template line - */ - public function getTemplateLine() - { - return $this->lineno; - } - - /** - * Sets the template line where the error occurred. - * - * @param int $lineno The template line - */ - public function setTemplateLine($lineno) - { - $this->lineno = $lineno; - - $this->updateRepr(); - } - - /** - * Gets the source context of the Twig template where the error occurred. - * - * @return Twig_Source|null - */ - public function getSourceContext() - { - return $this->filename ? new Twig_Source($this->sourceCode, $this->filename, $this->sourcePath) : null; - } - - /** - * Sets the source context of the Twig template where the error occurred. - */ - public function setSourceContext(Twig_Source $source = null) - { - if (null === $source) { - $this->sourceCode = $this->filename = $this->sourcePath = null; - } else { - $this->sourceCode = $source->getCode(); - $this->filename = $source->getName(); - $this->sourcePath = $source->getPath(); - } - - $this->updateRepr(); - } - - public function guess() - { - $this->guessTemplateInfo(); - $this->updateRepr(); - } - - /** - * For PHP < 5.3.0, provides access to the getPrevious() method. - * - * @param string $method The method name - * @param array $arguments The parameters to be passed to the method - * - * @return Exception The previous exception or null - * - * @throws BadMethodCallException - */ - public function __call($method, $arguments) - { - if ('getprevious' == strtolower($method)) { - return $this->previous; - } - - throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method)); - } - - public function appendMessage($rawMessage) - { - $this->rawMessage .= $rawMessage; - $this->updateRepr(); - } - - /** - * @internal - */ - protected function updateRepr() - { - $this->message = $this->rawMessage; - - if ($this->sourcePath && $this->lineno > 0) { - $this->file = $this->sourcePath; - $this->line = $this->lineno; - - return; - } - - $dot = false; - if ('.' === substr($this->message, -1)) { - $this->message = substr($this->message, 0, -1); - $dot = true; - } - - $questionMark = false; - if ('?' === substr($this->message, -1)) { - $this->message = substr($this->message, 0, -1); - $questionMark = true; - } - - if ($this->filename) { - if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) { - $name = sprintf('"%s"', $this->filename); - } else { - $name = json_encode($this->filename); - } - $this->message .= sprintf(' in %s', $name); - } - - if ($this->lineno && $this->lineno >= 0) { - $this->message .= sprintf(' at line %d', $this->lineno); - } - - if ($dot) { - $this->message .= '.'; - } - - if ($questionMark) { - $this->message .= '?'; - } - } - - /** - * @internal - */ - protected function guessTemplateInfo() - { - $template = null; - $templateClass = null; - - if (PHP_VERSION_ID >= 50306) { - $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT); - } else { - $backtrace = debug_backtrace(); - } - - foreach ($backtrace as $trace) { - if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) { - $currentClass = get_class($trace['object']); - $isEmbedContainer = 0 === strpos($templateClass, $currentClass); - if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) { - $template = $trace['object']; - $templateClass = get_class($trace['object']); - } - } - } - - // update template name - if (null !== $template && null === $this->filename) { - $this->filename = $template->getTemplateName(); - } - - // update template path if any - if (null !== $template && null === $this->sourcePath) { - $src = $template->getSourceContext(); - $this->sourceCode = $src->getCode(); - $this->sourcePath = $src->getPath(); - } - - if (null === $template || $this->lineno > -1) { - return; - } - - $r = new ReflectionObject($template); - $file = $r->getFileName(); - - $exceptions = array($e = $this); - while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) { - $exceptions[] = $e; - } - - while ($e = array_pop($exceptions)) { - $traces = $e->getTrace(); - array_unshift($traces, array('file' => $e->getFile(), 'line' => $e->getLine())); - - while ($trace = array_shift($traces)) { - if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { - continue; - } - - foreach ($template->getDebugInfo() as $codeLine => $templateLine) { - if ($codeLine <= $trace['line']) { - // update template line - $this->lineno = $templateLine; - - return; - } - } - } - } - } -} - -class_alias('Twig_Error', 'Twig\Error\Error', false); -class_exists('Twig_Source'); diff --git a/inc/lib/Twig/Error/Loader.php b/inc/lib/Twig/Error/Loader.php deleted file mode 100644 index df566dd7..00000000 --- a/inc/lib/Twig/Error/Loader.php +++ /dev/null @@ -1,40 +0,0 @@ - - */ -class Twig_Error_Loader extends Twig_Error -{ - public function __construct($message, $lineno = -1, $source = null, Exception $previous = null) - { - if (PHP_VERSION_ID < 50300) { - $this->previous = $previous; - Exception::__construct(''); - } else { - Exception::__construct('', 0, $previous); - } - $this->appendMessage($message); - $this->setTemplateLine(false); - } -} - -class_alias('Twig_Error_Loader', 'Twig\Error\LoaderError', false); diff --git a/inc/lib/Twig/Error/Runtime.php b/inc/lib/Twig/Error/Runtime.php deleted file mode 100644 index 3b24ad3a..00000000 --- a/inc/lib/Twig/Error/Runtime.php +++ /dev/null @@ -1,22 +0,0 @@ - - */ -class Twig_Error_Runtime extends Twig_Error -{ -} - -class_alias('Twig_Error_Runtime', 'Twig\Error\RuntimeError', false); diff --git a/inc/lib/Twig/Error/Syntax.php b/inc/lib/Twig/Error/Syntax.php deleted file mode 100644 index 9d09f217..00000000 --- a/inc/lib/Twig/Error/Syntax.php +++ /dev/null @@ -1,55 +0,0 @@ - - */ -class Twig_Error_Syntax extends Twig_Error -{ - /** - * Tweaks the error message to include suggestions. - * - * @param string $name The original name of the item that does not exist - * @param array $items An array of possible items - */ - public function addSuggestions($name, array $items) - { - if (!$alternatives = self::computeAlternatives($name, $items)) { - return; - } - - $this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', $alternatives))); - } - - /** - * @internal - * - * To be merged with the addSuggestions() method in 2.0. - */ - public static function computeAlternatives($name, $items) - { - $alternatives = array(); - foreach ($items as $item) { - $lev = levenshtein($name, $item); - if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { - $alternatives[$item] = $lev; - } - } - asort($alternatives); - - return array_keys($alternatives); - } -} - -class_alias('Twig_Error_Syntax', 'Twig\Error\SyntaxError', false); diff --git a/inc/lib/Twig/ExistsLoaderInterface.php b/inc/lib/Twig/ExistsLoaderInterface.php deleted file mode 100644 index 968cb21a..00000000 --- a/inc/lib/Twig/ExistsLoaderInterface.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_ExistsLoaderInterface -{ - /** - * Check if we have the source code of a template, given its name. - * - * @param string $name The name of the template to check if we can load - * - * @return bool If the template source code is handled by this loader or not - */ - public function exists($name); -} - -class_alias('Twig_ExistsLoaderInterface', 'Twig\Loader\ExistsLoaderInterface', false); diff --git a/inc/lib/Twig/ExpressionParser.php b/inc/lib/Twig/ExpressionParser.php deleted file mode 100644 index fe4a9b4a..00000000 --- a/inc/lib/Twig/ExpressionParser.php +++ /dev/null @@ -1,744 +0,0 @@ - - * - * @internal - */ -class Twig_ExpressionParser -{ - const OPERATOR_LEFT = 1; - const OPERATOR_RIGHT = 2; - - protected $parser; - protected $unaryOperators; - protected $binaryOperators; - - private $env; - - public function __construct(Twig_Parser $parser, $env = null) - { - $this->parser = $parser; - - if ($env instanceof Twig_Environment) { - $this->env = $env; - $this->unaryOperators = $env->getUnaryOperators(); - $this->binaryOperators = $env->getBinaryOperators(); - } else { - @trigger_error('Passing the operators as constructor arguments to '.__METHOD__.' is deprecated since version 1.27. Pass the environment instead.', E_USER_DEPRECATED); - - $this->env = $parser->getEnvironment(); - $this->unaryOperators = func_get_arg(1); - $this->binaryOperators = func_get_arg(2); - } - } - - public function parseExpression($precedence = 0) - { - $expr = $this->getPrimary(); - $token = $this->parser->getCurrentToken(); - while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) { - $op = $this->binaryOperators[$token->getValue()]; - $this->parser->getStream()->next(); - - if ('is not' === $token->getValue()) { - $expr = $this->parseNotTestExpression($expr); - } elseif ('is' === $token->getValue()) { - $expr = $this->parseTestExpression($expr); - } elseif (isset($op['callable'])) { - $expr = call_user_func($op['callable'], $this->parser, $expr); - } else { - $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); - $class = $op['class']; - $expr = new $class($expr, $expr1, $token->getLine()); - } - - $token = $this->parser->getCurrentToken(); - } - - if (0 === $precedence) { - return $this->parseConditionalExpression($expr); - } - - return $expr; - } - - protected function getPrimary() - { - $token = $this->parser->getCurrentToken(); - - if ($this->isUnary($token)) { - $operator = $this->unaryOperators[$token->getValue()]; - $this->parser->getStream()->next(); - $expr = $this->parseExpression($operator['precedence']); - $class = $operator['class']; - - return $this->parsePostfixExpression(new $class($expr, $token->getLine())); - } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) { - $this->parser->getStream()->next(); - $expr = $this->parseExpression(); - $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); - - return $this->parsePostfixExpression($expr); - } - - return $this->parsePrimaryExpression(); - } - - protected function parseConditionalExpression($expr) - { - while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) { - if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { - $expr2 = $this->parseExpression(); - if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { - $expr3 = $this->parseExpression(); - } else { - $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine()); - } - } else { - $expr2 = $expr; - $expr3 = $this->parseExpression(); - } - - $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); - } - - return $expr; - } - - protected function isUnary(Twig_Token $token) - { - return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); - } - - protected function isBinary(Twig_Token $token) - { - return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); - } - - public function parsePrimaryExpression() - { - $token = $this->parser->getCurrentToken(); - switch ($token->getType()) { - case Twig_Token::NAME_TYPE: - $this->parser->getStream()->next(); - switch ($token->getValue()) { - case 'true': - case 'TRUE': - $node = new Twig_Node_Expression_Constant(true, $token->getLine()); - break; - - case 'false': - case 'FALSE': - $node = new Twig_Node_Expression_Constant(false, $token->getLine()); - break; - - case 'none': - case 'NONE': - case 'null': - case 'NULL': - $node = new Twig_Node_Expression_Constant(null, $token->getLine()); - break; - - default: - if ('(' === $this->parser->getCurrentToken()->getValue()) { - $node = $this->getFunctionNode($token->getValue(), $token->getLine()); - } else { - $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); - } - } - break; - - case Twig_Token::NUMBER_TYPE: - $this->parser->getStream()->next(); - $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); - break; - - case Twig_Token::STRING_TYPE: - case Twig_Token::INTERPOLATION_START_TYPE: - $node = $this->parseStringExpression(); - break; - - case Twig_Token::OPERATOR_TYPE: - if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) { - // in this context, string operators are variable names - $this->parser->getStream()->next(); - $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); - break; - } elseif (isset($this->unaryOperators[$token->getValue()])) { - $class = $this->unaryOperators[$token->getValue()]['class']; - - $ref = new ReflectionClass($class); - $negClass = 'Twig_Node_Expression_Unary_Neg'; - $posClass = 'Twig_Node_Expression_Unary_Pos'; - if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) { - throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); - } - - $this->parser->getStream()->next(); - $expr = $this->parsePrimaryExpression(); - - $node = new $class($expr, $token->getLine()); - break; - } - - // no break - default: - if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) { - $node = $this->parseArrayExpression(); - } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { - $node = $this->parseHashExpression(); - } elseif ($token->test(Twig_Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) { - throw new Twig_Error_Syntax(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); - } else { - throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); - } - } - - return $this->parsePostfixExpression($node); - } - - public function parseStringExpression() - { - $stream = $this->parser->getStream(); - - $nodes = array(); - // a string cannot be followed by another string in a single expression - $nextCanBeString = true; - while (true) { - if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) { - $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); - $nextCanBeString = false; - } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) { - $nodes[] = $this->parseExpression(); - $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); - $nextCanBeString = true; - } else { - break; - } - } - - $expr = array_shift($nodes); - foreach ($nodes as $node) { - $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getTemplateLine()); - } - - return $expr; - } - - public function parseArrayExpression() - { - $stream = $this->parser->getStream(); - $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected'); - - $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); - $first = true; - while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { - if (!$first) { - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma'); - - // trailing ,? - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { - break; - } - } - $first = false; - - $node->addElement($this->parseExpression()); - } - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed'); - - return $node; - } - - public function parseHashExpression() - { - $stream = $this->parser->getStream(); - $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); - - $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); - $first = true; - while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { - if (!$first) { - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); - - // trailing ,? - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { - break; - } - } - $first = false; - - // a hash key can be: - // - // * a number -- 12 - // * a string -- 'a' - // * a name, which is equivalent to a string -- a - // * an expression, which must be enclosed in parentheses -- (1 + 2) - if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) { - $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); - } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { - $key = $this->parseExpression(); - } else { - $current = $stream->getCurrent(); - - throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext()); - } - - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); - $value = $this->parseExpression(); - - $node->addElement($value, $key); - } - $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed'); - - return $node; - } - - public function parsePostfixExpression($node) - { - while (true) { - $token = $this->parser->getCurrentToken(); - if (Twig_Token::PUNCTUATION_TYPE == $token->getType()) { - if ('.' == $token->getValue() || '[' == $token->getValue()) { - $node = $this->parseSubscriptExpression($node); - } elseif ('|' == $token->getValue()) { - $node = $this->parseFilterExpression($node); - } else { - break; - } - } else { - break; - } - } - - return $node; - } - - public function getFunctionNode($name, $line) - { - switch ($name) { - case 'parent': - $this->parseArguments(); - if (!count($this->parser->getBlockStack())) { - throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext()); - } - - if (!$this->parser->getParent() && !$this->parser->hasTraits()) { - throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext()); - } - - return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); - case 'block': - $args = $this->parseArguments(); - if (count($args) < 1) { - throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext()); - } - - return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line); - case 'attribute': - $args = $this->parseArguments(); - if (count($args) < 2) { - throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext()); - } - - return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line); - default: - if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { - $arguments = new Twig_Node_Expression_Array(array(), $line); - foreach ($this->parseArguments() as $n) { - $arguments->addElement($n); - } - - $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line); - $node->setAttribute('safe', true); - - return $node; - } - - $args = $this->parseArguments(true); - $class = $this->getFunctionNodeClass($name, $line); - - return new $class($name, $args, $line); - } - } - - public function parseSubscriptExpression($node) - { - $stream = $this->parser->getStream(); - $token = $stream->next(); - $lineno = $token->getLine(); - $arguments = new Twig_Node_Expression_Array(array(), $lineno); - $type = Twig_Template::ANY_CALL; - if ('.' == $token->getValue()) { - $token = $stream->next(); - if ( - Twig_Token::NAME_TYPE == $token->getType() - || - Twig_Token::NUMBER_TYPE == $token->getType() - || - (Twig_Token::OPERATOR_TYPE == $token->getType() && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue())) - ) { - $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno); - - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { - $type = Twig_Template::METHOD_CALL; - foreach ($this->parseArguments() as $n) { - $arguments->addElement($n); - } - } - } else { - throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext()); - } - - if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { - if (!$arg instanceof Twig_Node_Expression_Constant) { - throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext()); - } - - $name = $arg->getAttribute('value'); - - if ($this->parser->isReservedMacroName($name)) { - throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()); - } - - $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno); - $node->setAttribute('safe', true); - - return $node; - } - } else { - $type = Twig_Template::ARRAY_CALL; - - // slice? - $slice = false; - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { - $slice = true; - $arg = new Twig_Node_Expression_Constant(0, $token->getLine()); - } else { - $arg = $this->parseExpression(); - } - - if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { - $slice = true; - } - - if ($slice) { - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { - $length = new Twig_Node_Expression_Constant(null, $token->getLine()); - } else { - $length = $this->parseExpression(); - } - - $class = $this->getFilterNodeClass('slice', $token->getLine()); - $arguments = new Twig_Node(array($arg, $length)); - $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); - - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); - - return $filter; - } - - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); - } - - return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); - } - - public function parseFilterExpression($node) - { - $this->parser->getStream()->next(); - - return $this->parseFilterExpressionRaw($node); - } - - public function parseFilterExpressionRaw($node, $tag = null) - { - while (true) { - $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE); - - $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); - if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) { - $arguments = new Twig_Node(); - } else { - $arguments = $this->parseArguments(true); - } - - $class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine()); - - $node = new $class($node, $name, $arguments, $token->getLine(), $tag); - - if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) { - break; - } - - $this->parser->getStream()->next(); - } - - return $node; - } - - /** - * Parses arguments. - * - * @param bool $namedArguments Whether to allow named arguments or not - * @param bool $definition Whether we are parsing arguments for a function definition - * - * @return Twig_Node - * - * @throws Twig_Error_Syntax - */ - public function parseArguments($namedArguments = false, $definition = false) - { - $args = array(); - $stream = $this->parser->getStream(); - - $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); - while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { - if (!empty($args)) { - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); - } - - if ($definition) { - $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name'); - $value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine()); - } else { - $value = $this->parseExpression(); - } - - $name = null; - if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) { - if (!$value instanceof Twig_Node_Expression_Name) { - throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext()); - } - $name = $value->getAttribute('name'); - - if ($definition) { - $value = $this->parsePrimaryExpression(); - - if (!$this->checkConstantExpression($value)) { - throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $stream->getSourceContext()); - } - } else { - $value = $this->parseExpression(); - } - } - - if ($definition) { - if (null === $name) { - $name = $value->getAttribute('name'); - $value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine()); - } - $args[$name] = $value; - } else { - if (null === $name) { - $args[] = $value; - } else { - $args[$name] = $value; - } - } - } - $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); - - return new Twig_Node($args); - } - - public function parseAssignmentExpression() - { - $stream = $this->parser->getStream(); - $targets = array(); - while (true) { - $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); - $value = $token->getValue(); - if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) { - throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext()); - } - $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine()); - - if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { - break; - } - } - - return new Twig_Node($targets); - } - - public function parseMultitargetExpression() - { - $targets = array(); - while (true) { - $targets[] = $this->parseExpression(); - if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { - break; - } - } - - return new Twig_Node($targets); - } - - private function parseNotTestExpression(Twig_NodeInterface $node) - { - return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine()); - } - - private function parseTestExpression(Twig_NodeInterface $node) - { - $stream = $this->parser->getStream(); - list($name, $test) = $this->getTest($node->getTemplateLine()); - - $class = $this->getTestNodeClass($test); - $arguments = null; - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { - $arguments = $this->parser->getExpressionParser()->parseArguments(true); - } - - return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine()); - } - - private function getTest($line) - { - $stream = $this->parser->getStream(); - $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - - if ($test = $this->env->getTest($name)) { - return array($name, $test); - } - - if ($stream->test(Twig_Token::NAME_TYPE)) { - // try 2-words tests - $name = $name.' '.$this->parser->getCurrentToken()->getValue(); - - if ($test = $this->env->getTest($name)) { - $stream->next(); - - return array($name, $test); - } - } - - $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext()); - $e->addSuggestions($name, array_keys($this->env->getTests())); - - throw $e; - } - - private function getTestNodeClass($test) - { - if ($test instanceof Twig_SimpleTest && $test->isDeprecated()) { - $stream = $this->parser->getStream(); - $message = sprintf('Twig Test "%s" is deprecated', $test->getName()); - if (!is_bool($test->getDeprecatedVersion())) { - $message .= sprintf(' since version %s', $test->getDeprecatedVersion()); - } - if ($test->getAlternative()) { - $message .= sprintf('. Use "%s" instead', $test->getAlternative()); - } - $src = $stream->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine()); - - @trigger_error($message, E_USER_DEPRECATED); - } - - if ($test instanceof Twig_SimpleTest) { - return $test->getNodeClass(); - } - - return $test instanceof Twig_Test_Node ? $test->getClass() : 'Twig_Node_Expression_Test'; - } - - protected function getFunctionNodeClass($name, $line) - { - if (false === $function = $this->env->getFunction($name)) { - $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext()); - $e->addSuggestions($name, array_keys($this->env->getFunctions())); - - throw $e; - } - - if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) { - $message = sprintf('Twig Function "%s" is deprecated', $function->getName()); - if (!is_bool($function->getDeprecatedVersion())) { - $message .= sprintf(' since version %s', $function->getDeprecatedVersion()); - } - if ($function->getAlternative()) { - $message .= sprintf('. Use "%s" instead', $function->getAlternative()); - } - $src = $this->parser->getStream()->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line); - - @trigger_error($message, E_USER_DEPRECATED); - } - - if ($function instanceof Twig_SimpleFunction) { - return $function->getNodeClass(); - } - - return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function'; - } - - protected function getFilterNodeClass($name, $line) - { - if (false === $filter = $this->env->getFilter($name)) { - $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext()); - $e->addSuggestions($name, array_keys($this->env->getFilters())); - - throw $e; - } - - if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) { - $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName()); - if (!is_bool($filter->getDeprecatedVersion())) { - $message .= sprintf(' since version %s', $filter->getDeprecatedVersion()); - } - if ($filter->getAlternative()) { - $message .= sprintf('. Use "%s" instead', $filter->getAlternative()); - } - $src = $this->parser->getStream()->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line); - - @trigger_error($message, E_USER_DEPRECATED); - } - - if ($filter instanceof Twig_SimpleFilter) { - return $filter->getNodeClass(); - } - - return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter'; - } - - // checks that the node only contains "constant" elements - protected function checkConstantExpression(Twig_NodeInterface $node) - { - if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array - || $node instanceof Twig_Node_Expression_Unary_Neg || $node instanceof Twig_Node_Expression_Unary_Pos - )) { - return false; - } - - foreach ($node as $n) { - if (!$this->checkConstantExpression($n)) { - return false; - } - } - - return true; - } -} - -class_alias('Twig_ExpressionParser', 'Twig\ExpressionParser', false); diff --git a/inc/lib/Twig/Extension.php b/inc/lib/Twig/Extension.php deleted file mode 100644 index 38084495..00000000 --- a/inc/lib/Twig/Extension.php +++ /dev/null @@ -1,69 +0,0 @@ -escapers[$strategy] = $callable; - } - - /** - * Gets all defined escapers. - * - * @return array An array of escapers - */ - public function getEscapers() - { - return $this->escapers; - } - - /** - * Sets the default format to be used by the date filter. - * - * @param string $format The default date format string - * @param string $dateIntervalFormat The default date interval format string - */ - public function setDateFormat($format = null, $dateIntervalFormat = null) - { - if (null !== $format) { - $this->dateFormats[0] = $format; - } - - if (null !== $dateIntervalFormat) { - $this->dateFormats[1] = $dateIntervalFormat; - } - } - - /** - * Gets the default format to be used by the date filter. - * - * @return array The default date format string and the default date interval format string - */ - public function getDateFormat() - { - return $this->dateFormats; - } - - /** - * Sets the default timezone to be used by the date filter. - * - * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object - */ - public function setTimezone($timezone) - { - $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); - } - - /** - * Gets the default timezone to be used by the date filter. - * - * @return DateTimeZone The default timezone currently in use - */ - public function getTimezone() - { - if (null === $this->timezone) { - $this->timezone = new DateTimeZone(date_default_timezone_get()); - } - - return $this->timezone; - } - - /** - * Sets the default format to be used by the number_format filter. - * - * @param int $decimal the number of decimal places to use - * @param string $decimalPoint the character(s) to use for the decimal point - * @param string $thousandSep the character(s) to use for the thousands separator - */ - public function setNumberFormat($decimal, $decimalPoint, $thousandSep) - { - $this->numberFormat = array($decimal, $decimalPoint, $thousandSep); - } - - /** - * Get the default format used by the number_format filter. - * - * @return array The arguments for number_format() - */ - public function getNumberFormat() - { - return $this->numberFormat; - } - - public function getTokenParsers() - { - return array( - new Twig_TokenParser_For(), - new Twig_TokenParser_If(), - new Twig_TokenParser_Extends(), - new Twig_TokenParser_Include(), - new Twig_TokenParser_Block(), - new Twig_TokenParser_Use(), - new Twig_TokenParser_Filter(), - new Twig_TokenParser_Macro(), - new Twig_TokenParser_Import(), - new Twig_TokenParser_From(), - new Twig_TokenParser_Set(), - new Twig_TokenParser_Spaceless(), - new Twig_TokenParser_Flush(), - new Twig_TokenParser_Do(), - new Twig_TokenParser_Embed(), - new Twig_TokenParser_With(), - ); - } - - public function getFilters() - { - $filters = array( - // formatting filters - new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('format', 'sprintf'), - new Twig_SimpleFilter('replace', 'twig_replace_filter'), - new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('abs', 'abs'), - new Twig_SimpleFilter('round', 'twig_round'), - - // encoding - new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'), - new Twig_SimpleFilter('json_encode', 'twig_jsonencode_filter'), - new Twig_SimpleFilter('convert_encoding', 'twig_convert_encoding'), - - // string filters - new Twig_SimpleFilter('title', 'twig_title_string_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('capitalize', 'twig_capitalize_string_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('upper', 'strtoupper'), - new Twig_SimpleFilter('lower', 'strtolower'), - new Twig_SimpleFilter('striptags', 'strip_tags'), - new Twig_SimpleFilter('trim', 'twig_trim_filter'), - new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), - - // array helpers - new Twig_SimpleFilter('join', 'twig_join_filter'), - new Twig_SimpleFilter('split', 'twig_split_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('sort', 'twig_sort_filter'), - new Twig_SimpleFilter('merge', 'twig_array_merge'), - new Twig_SimpleFilter('batch', 'twig_array_batch'), - - // string/array filters - new Twig_SimpleFilter('reverse', 'twig_reverse_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('length', 'twig_length_filter', array('needs_environment' => true)), - new Twig_SimpleFilter('slice', 'twig_slice', array('needs_environment' => true)), - new Twig_SimpleFilter('first', 'twig_first', array('needs_environment' => true)), - new Twig_SimpleFilter('last', 'twig_last', array('needs_environment' => true)), - - // iteration and runtime - new Twig_SimpleFilter('default', '_twig_default_filter', array('node_class' => 'Twig_Node_Expression_Filter_Default')), - new Twig_SimpleFilter('keys', 'twig_get_array_keys_filter'), - - // escaping - new Twig_SimpleFilter('escape', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), - new Twig_SimpleFilter('e', 'twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), - ); - - if (function_exists('mb_get_info')) { - $filters[] = new Twig_SimpleFilter('upper', 'twig_upper_filter', array('needs_environment' => true)); - $filters[] = new Twig_SimpleFilter('lower', 'twig_lower_filter', array('needs_environment' => true)); - } - - return $filters; - } - - public function getFunctions() - { - return array( - new Twig_SimpleFunction('max', 'max'), - new Twig_SimpleFunction('min', 'min'), - new Twig_SimpleFunction('range', 'range'), - new Twig_SimpleFunction('constant', 'twig_constant'), - new Twig_SimpleFunction('cycle', 'twig_cycle'), - new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)), - new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)), - new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))), - new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))), - ); - } - - public function getTests() - { - return array( - new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')), - new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')), - new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')), - new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas', 'deprecated' => '1.21', 'alternative' => 'same as')), - new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')), - new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), - new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), - new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby', 'deprecated' => '1.21', 'alternative' => 'divisible by')), - new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')), - new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')), - new Twig_SimpleTest('empty', 'twig_test_empty'), - new Twig_SimpleTest('iterable', 'twig_test_iterable'), - ); - } - - public function getOperators() - { - return array( - array( - 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), - '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'), - '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'), - ), - array( - 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'is' => array('precedence' => 100, 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'is not' => array('precedence' => 100, 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), - '??' => array('precedence' => 300, 'class' => 'Twig_Node_Expression_NullCoalesce', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), - ), - ); - } - - public function getName() - { - return 'core'; - } -} - -/** - * Cycles over a value. - * - * @param ArrayAccess|array $values - * @param int $position The cycle position - * - * @return string The next value in the cycle - */ -function twig_cycle($values, $position) -{ - if (!is_array($values) && !$values instanceof ArrayAccess) { - return $values; - } - - return $values[$position % count($values)]; -} - -/** - * Returns a random value depending on the supplied parameter type: - * - a random item from a Traversable or array - * - a random character from a string - * - a random integer between 0 and the integer parameter. - * - * @param Twig_Environment $env - * @param Traversable|array|int|float|string $values The values to pick a random item from - * - * @throws Twig_Error_Runtime when $values is an empty array (does not apply to an empty string which is returned as is) - * - * @return mixed A random value from the given sequence - */ -function twig_random(Twig_Environment $env, $values = null) -{ - if (null === $values) { - return mt_rand(); - } - - if (is_int($values) || is_float($values)) { - return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values); - } - - if ($values instanceof Traversable) { - $values = iterator_to_array($values); - } elseif (is_string($values)) { - if ('' === $values) { - return ''; - } - if (null !== $charset = $env->getCharset()) { - if ('UTF-8' !== $charset) { - $values = twig_convert_encoding($values, 'UTF-8', $charset); - } - - // unicode version of str_split() - // split at all positions, but not after the start and not before the end - $values = preg_split('/(? $value) { - $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); - } - } - } else { - return $values[mt_rand(0, strlen($values) - 1)]; - } - } - - if (!is_array($values)) { - return $values; - } - - if (0 === count($values)) { - throw new Twig_Error_Runtime('The random function cannot pick from an empty array.'); - } - - return $values[array_rand($values, 1)]; -} - -/** - * Converts a date to the given format. - * - *
- *   {{ post.published_at|date("m/d/Y") }}
- * 
- * - * @param Twig_Environment $env - * @param DateTime|DateTimeInterface|DateInterval|string $date A date - * @param string|null $format The target format, null to use the default - * @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged - * - * @return string The formatted date - */ -function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null) -{ - if (null === $format) { - $formats = $env->getExtension('Twig_Extension_Core')->getDateFormat(); - $format = $date instanceof DateInterval ? $formats[1] : $formats[0]; - } - - if ($date instanceof DateInterval) { - return $date->format($format); - } - - return twig_date_converter($env, $date, $timezone)->format($format); -} - -/** - * Returns a new date object modified. - * - *
- *   {{ post.published_at|date_modify("-1day")|date("m/d/Y") }}
- * 
- * - * @param Twig_Environment $env - * @param DateTime|string $date A date - * @param string $modifier A modifier string - * - * @return DateTime A new date object - */ -function twig_date_modify_filter(Twig_Environment $env, $date, $modifier) -{ - $date = twig_date_converter($env, $date, false); - $resultDate = $date->modify($modifier); - - // This is a hack to ensure PHP 5.2 support and support for DateTimeImmutable - // DateTime::modify does not return the modified DateTime object < 5.3.0 - // and DateTimeImmutable does not modify $date. - return null === $resultDate ? $date : $resultDate; -} - -/** - * Converts an input to a DateTime instance. - * - *
- *    {% if date(user.created_at) < date('+2days') %}
- *      {# do something #}
- *    {% endif %}
- * 
- * - * @param Twig_Environment $env - * @param DateTime|DateTimeInterface|string|null $date A date - * @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged - * - * @return DateTime A DateTime instance - */ -function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null) -{ - // determine the timezone - if (false !== $timezone) { - if (null === $timezone) { - $timezone = $env->getExtension('Twig_Extension_Core')->getTimezone(); - } elseif (!$timezone instanceof DateTimeZone) { - $timezone = new DateTimeZone($timezone); - } - } - - // immutable dates - if ($date instanceof DateTimeImmutable) { - return false !== $timezone ? $date->setTimezone($timezone) : $date; - } - - if ($date instanceof DateTime || $date instanceof DateTimeInterface) { - $date = clone $date; - if (false !== $timezone) { - $date->setTimezone($timezone); - } - - return $date; - } - - if (null === $date || 'now' === $date) { - return new DateTime($date, false !== $timezone ? $timezone : $env->getExtension('Twig_Extension_Core')->getTimezone()); - } - - $asString = (string) $date; - if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { - $date = new DateTime('@'.$date); - } else { - $date = new DateTime($date, $env->getExtension('Twig_Extension_Core')->getTimezone()); - } - - if (false !== $timezone) { - $date->setTimezone($timezone); - } - - return $date; -} - -/** - * Replaces strings within a string. - * - * @param string $str String to replace in - * @param array|Traversable $from Replace values - * @param string|null $to Replace to, deprecated (@see https://secure.php.net/manual/en/function.strtr.php) - * - * @return string - */ -function twig_replace_filter($str, $from, $to = null) -{ - if ($from instanceof Traversable) { - $from = iterator_to_array($from); - } elseif (is_string($from) && is_string($to)) { - @trigger_error('Using "replace" with character by character replacement is deprecated since version 1.22 and will be removed in Twig 2.0', E_USER_DEPRECATED); - - return strtr($str, $from, $to); - } elseif (!is_array($from)) { - throw new Twig_Error_Runtime(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', is_object($from) ? get_class($from) : gettype($from))); - } - - return strtr($str, $from); -} - -/** - * Rounds a number. - * - * @param int|float $value The value to round - * @param int|float $precision The rounding precision - * @param string $method The method to use for rounding - * - * @return int|float The rounded number - */ -function twig_round($value, $precision = 0, $method = 'common') -{ - if ('common' == $method) { - return round($value, $precision); - } - - if ('ceil' != $method && 'floor' != $method) { - throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.'); - } - - return $method($value * pow(10, $precision)) / pow(10, $precision); -} - -/** - * Number format filter. - * - * All of the formatting options can be left null, in that case the defaults will - * be used. Supplying any of the parameters will override the defaults set in the - * environment object. - * - * @param Twig_Environment $env - * @param mixed $number A float/int/string of the number to format - * @param int $decimal the number of decimal points to display - * @param string $decimalPoint the character(s) to use for the decimal point - * @param string $thousandSep the character(s) to use for the thousands separator - * - * @return string The formatted number - */ -function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null) -{ - $defaults = $env->getExtension('Twig_Extension_Core')->getNumberFormat(); - if (null === $decimal) { - $decimal = $defaults[0]; - } - - if (null === $decimalPoint) { - $decimalPoint = $defaults[1]; - } - - if (null === $thousandSep) { - $thousandSep = $defaults[2]; - } - - return number_format((float) $number, $decimal, $decimalPoint, $thousandSep); -} - -/** - * URL encodes (RFC 3986) a string as a path segment or an array as a query string. - * - * @param string|array $url A URL or an array of query parameters - * - * @return string The URL encoded value - */ -function twig_urlencode_filter($url) -{ - if (is_array($url)) { - if (defined('PHP_QUERY_RFC3986')) { - return http_build_query($url, '', '&', PHP_QUERY_RFC3986); - } - - return http_build_query($url, '', '&'); - } - - return rawurlencode($url); -} - -if (PHP_VERSION_ID < 50300) { - /** - * JSON encodes a variable. - * - * @param mixed $value the value to encode - * @param int $options Not used on PHP 5.2.x - * - * @return mixed The JSON encoded value - */ - function twig_jsonencode_filter($value, $options = 0) - { - if ($value instanceof Twig_Markup) { - $value = (string) $value; - } elseif (is_array($value)) { - array_walk_recursive($value, '_twig_markup2string'); - } - - return json_encode($value); - } -} else { - /** - * JSON encodes a variable. - * - * @param mixed $value the value to encode - * @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT - * - * @return mixed The JSON encoded value - */ - function twig_jsonencode_filter($value, $options = 0) - { - if ($value instanceof Twig_Markup) { - $value = (string) $value; - } elseif (is_array($value)) { - array_walk_recursive($value, '_twig_markup2string'); - } - - return json_encode($value, $options); - } -} - -function _twig_markup2string(&$value) -{ - if ($value instanceof Twig_Markup) { - $value = (string) $value; - } -} - -/** - * Merges an array with another one. - * - *
- *  {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
- *
- *  {% set items = items|merge({ 'peugeot': 'car' }) %}
- *
- *  {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
- * 
- * - * @param array|Traversable $arr1 An array - * @param array|Traversable $arr2 An array - * - * @return array The merged array - */ -function twig_array_merge($arr1, $arr2) -{ - if ($arr1 instanceof Traversable) { - $arr1 = iterator_to_array($arr1); - } elseif (!is_array($arr1)) { - throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as first argument.', gettype($arr1))); - } - - if ($arr2 instanceof Traversable) { - $arr2 = iterator_to_array($arr2); - } elseif (!is_array($arr2)) { - throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as second argument.', gettype($arr2))); - } - - return array_merge($arr1, $arr2); -} - -/** - * Slices a variable. - * - * @param Twig_Environment $env - * @param mixed $item A variable - * @param int $start Start of the slice - * @param int $length Size of the slice - * @param bool $preserveKeys Whether to preserve key or not (when the input is an array) - * - * @return mixed The sliced variable - */ -function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false) -{ - if ($item instanceof Traversable) { - while ($item instanceof IteratorAggregate) { - $item = $item->getIterator(); - } - - if ($start >= 0 && $length >= 0 && $item instanceof Iterator) { - try { - return iterator_to_array(new LimitIterator($item, $start, null === $length ? -1 : $length), $preserveKeys); - } catch (OutOfBoundsException $exception) { - return array(); - } - } - - $item = iterator_to_array($item, $preserveKeys); - } - - if (is_array($item)) { - return array_slice($item, $start, $length, $preserveKeys); - } - - $item = (string) $item; - - if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) { - return (string) mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset); - } - - return (string) (null === $length ? substr($item, $start) : substr($item, $start, $length)); -} - -/** - * Returns the first element of the item. - * - * @param Twig_Environment $env - * @param mixed $item A variable - * - * @return mixed The first element of the item - */ -function twig_first(Twig_Environment $env, $item) -{ - $elements = twig_slice($env, $item, 0, 1, false); - - return is_string($elements) ? $elements : current($elements); -} - -/** - * Returns the last element of the item. - * - * @param Twig_Environment $env - * @param mixed $item A variable - * - * @return mixed The last element of the item - */ -function twig_last(Twig_Environment $env, $item) -{ - $elements = twig_slice($env, $item, -1, 1, false); - - return is_string($elements) ? $elements : current($elements); -} - -/** - * Joins the values to a string. - * - * The separator between elements is an empty string per default, you can define it with the optional parameter. - * - *
- *  {{ [1, 2, 3]|join('|') }}
- *  {# returns 1|2|3 #}
- *
- *  {{ [1, 2, 3]|join }}
- *  {# returns 123 #}
- * 
- * - * @param array $value An array - * @param string $glue The separator - * - * @return string The concatenated string - */ -function twig_join_filter($value, $glue = '') -{ - if ($value instanceof Traversable) { - $value = iterator_to_array($value, false); - } - - return implode($glue, (array) $value); -} - -/** - * Splits the string into an array. - * - *
- *  {{ "one,two,three"|split(',') }}
- *  {# returns [one, two, three] #}
- *
- *  {{ "one,two,three,four,five"|split(',', 3) }}
- *  {# returns [one, two, "three,four,five"] #}
- *
- *  {{ "123"|split('') }}
- *  {# returns [1, 2, 3] #}
- *
- *  {{ "aabbcc"|split('', 2) }}
- *  {# returns [aa, bb, cc] #}
- * 
- * - * @param Twig_Environment $env - * @param string $value A string - * @param string $delimiter The delimiter - * @param int $limit The limit - * - * @return array The split string as an array - */ -function twig_split_filter(Twig_Environment $env, $value, $delimiter, $limit = null) -{ - if (!empty($delimiter)) { - return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit); - } - - if (!function_exists('mb_get_info') || null === $charset = $env->getCharset()) { - return str_split($value, null === $limit ? 1 : $limit); - } - - if ($limit <= 1) { - return preg_split('/(? - * {% for key in array|keys %} - * {# ... #} - * {% endfor %} - * - * - * @param array $array An array - * - * @return array The keys - */ -function twig_get_array_keys_filter($array) -{ - if ($array instanceof Traversable) { - while ($array instanceof IteratorAggregate) { - $array = $array->getIterator(); - } - - if ($array instanceof Iterator) { - $keys = array(); - $array->rewind(); - while ($array->valid()) { - $keys[] = $array->key(); - $array->next(); - } - - return $keys; - } - - $keys = array(); - foreach ($array as $key => $item) { - $keys[] = $key; - } - - return $keys; - } - - if (!is_array($array)) { - return array(); - } - - return array_keys($array); -} - -/** - * Reverses a variable. - * - * @param Twig_Environment $env - * @param array|Traversable|string $item An array, a Traversable instance, or a string - * @param bool $preserveKeys Whether to preserve key or not - * - * @return mixed The reversed input - */ -function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false) -{ - if ($item instanceof Traversable) { - return array_reverse(iterator_to_array($item), $preserveKeys); - } - - if (is_array($item)) { - return array_reverse($item, $preserveKeys); - } - - if (null !== $charset = $env->getCharset()) { - $string = (string) $item; - - if ('UTF-8' !== $charset) { - $item = twig_convert_encoding($string, 'UTF-8', $charset); - } - - preg_match_all('/./us', $item, $matches); - - $string = implode('', array_reverse($matches[0])); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - } - - return strrev((string) $item); -} - -/** - * Sorts an array. - * - * @param array|Traversable $array - * - * @return array - */ -function twig_sort_filter($array) -{ - if ($array instanceof Traversable) { - $array = iterator_to_array($array); - } elseif (!is_array($array)) { - throw new Twig_Error_Runtime(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', gettype($array))); - } - - asort($array); - - return $array; -} - -/** - * @internal - */ -function twig_in_filter($value, $compare) -{ - if (is_array($compare)) { - return in_array($value, $compare, is_object($value) || is_resource($value)); - } elseif (is_string($compare) && (is_string($value) || is_int($value) || is_float($value))) { - return '' === $value || false !== strpos($compare, (string) $value); - } elseif ($compare instanceof Traversable) { - if (is_object($value) || is_resource($value)) { - foreach ($compare as $item) { - if ($item === $value) { - return true; - } - } - } else { - foreach ($compare as $item) { - if ($item == $value) { - return true; - } - } - } - - return false; - } - - return false; -} - -/** - * Returns a trimmed string. - * - * @return string - * - * @throws Twig_Error_Runtime When an invalid trimming side is used (not a string or not 'left', 'right', or 'both') - */ -function twig_trim_filter($string, $characterMask = null, $side = 'both') -{ - if (null === $characterMask) { - $characterMask = " \t\n\r\0\x0B"; - } - - switch ($side) { - case 'both': - return trim($string, $characterMask); - case 'left': - return ltrim($string, $characterMask); - case 'right': - return rtrim($string, $characterMask); - default: - throw new Twig_Error_Runtime('Trimming side must be "left", "right" or "both".'); - } -} - -/** - * Escapes a string. - * - * @param Twig_Environment $env - * @param mixed $string The value to be escaped - * @param string $strategy The escaping strategy - * @param string $charset The charset - * @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false) - * - * @return string - */ -function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) -{ - if ($autoescape && $string instanceof Twig_Markup) { - return $string; - } - - if (!is_string($string)) { - if (is_object($string) && method_exists($string, '__toString')) { - $string = (string) $string; - } elseif (in_array($strategy, array('html', 'js', 'css', 'html_attr', 'url'))) { - return $string; - } - } - - if (null === $charset) { - $charset = $env->getCharset(); - } - - switch ($strategy) { - case 'html': - // see https://secure.php.net/htmlspecialchars - - // Using a static variable to avoid initializing the array - // each time the function is called. Moving the declaration on the - // top of the function slow downs other escaping strategies. - static $htmlspecialcharsCharsets = array( - 'ISO-8859-1' => true, 'ISO8859-1' => true, - 'ISO-8859-15' => true, 'ISO8859-15' => true, - 'utf-8' => true, 'UTF-8' => true, - 'CP866' => true, 'IBM866' => true, '866' => true, - 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true, - '1251' => true, - 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true, - 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true, - 'BIG5' => true, '950' => true, - 'GB2312' => true, '936' => true, - 'BIG5-HKSCS' => true, - 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true, - 'EUC-JP' => true, 'EUCJP' => true, - 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true, - ); - - if (isset($htmlspecialcharsCharsets[$charset])) { - return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); - } - - if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) { - // cache the lowercase variant for future iterations - $htmlspecialcharsCharsets[$charset] = true; - - return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); - } - - $string = twig_convert_encoding($string, 'UTF-8', $charset); - $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); - - return twig_convert_encoding($string, $charset, 'UTF-8'); - - case 'js': - // escape all non-alphanumeric characters - // into their \x or \uHHHH representations - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, 'UTF-8', $charset); - } - - if (0 == strlen($string) ? false : 1 !== preg_match('/^./su', $string)) { - throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); - } - - $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - - case 'css': - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, 'UTF-8', $charset); - } - - if (0 == strlen($string) ? false : 1 !== preg_match('/^./su', $string)) { - throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); - } - - $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - - case 'html_attr': - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, 'UTF-8', $charset); - } - - if (0 == strlen($string) ? false : 1 !== preg_match('/^./su', $string)) { - throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); - } - - $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - - case 'url': - if (PHP_VERSION_ID < 50300) { - return str_replace('%7E', '~', rawurlencode($string)); - } - - return rawurlencode($string); - - default: - static $escapers; - - if (null === $escapers) { - $escapers = $env->getExtension('Twig_Extension_Core')->getEscapers(); - } - - if (isset($escapers[$strategy])) { - return call_user_func($escapers[$strategy], $env, $string, $charset); - } - - $validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers))); - - throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies)); - } -} - -/** - * @internal - */ -function twig_escape_filter_is_safe(Twig_Node $filterArgs) -{ - foreach ($filterArgs as $arg) { - if ($arg instanceof Twig_Node_Expression_Constant) { - return array($arg->getAttribute('value')); - } - - return array(); - } - - return array('html'); -} - -if (function_exists('mb_convert_encoding')) { - function twig_convert_encoding($string, $to, $from) - { - return mb_convert_encoding($string, $to, $from); - } -} elseif (function_exists('iconv')) { - function twig_convert_encoding($string, $to, $from) - { - return iconv($from, $to, $string); - } -} else { - function twig_convert_encoding($string, $to, $from) - { - throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); - } -} - -function _twig_escape_js_callback($matches) -{ - $char = $matches[0]; - - /* - * A few characters have short escape sequences in JSON and JavaScript. - * Escape sequences supported only by JavaScript, not JSON, are ommitted. - * \" is also supported but omitted, because the resulting string is not HTML safe. - */ - static $shortMap = array( - '\\' => '\\\\', - '/' => '\\/', - "\x08" => '\b', - "\x0C" => '\f', - "\x0A" => '\n', - "\x0D" => '\r', - "\x09" => '\t', - ); - - if (isset($shortMap[$char])) { - return $shortMap[$char]; - } - - // \uHHHH - $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); - $char = strtoupper(bin2hex($char)); - - if (4 >= strlen($char)) { - return sprintf('\u%04s', $char); - } - - return sprintf('\u%04s\u%04s', substr($char, 0, -4), substr($char, -4)); -} - -function _twig_escape_css_callback($matches) -{ - $char = $matches[0]; - - // \xHH - if (!isset($char[1])) { - $hex = ltrim(strtoupper(bin2hex($char)), '0'); - if (0 === strlen($hex)) { - $hex = '0'; - } - - return '\\'.$hex.' '; - } - - // \uHHHH - $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); - - return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' '; -} - -/** - * This function is adapted from code coming from Zend Framework. - * - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com) - * @license https://framework.zend.com/license/new-bsd New BSD License - */ -function _twig_escape_html_attr_callback($matches) -{ - /* - * While HTML supports far more named entities, the lowest common denominator - * has become HTML5's XML Serialisation which is restricted to the those named - * entities that XML supports. Using HTML entities would result in this error: - * XML Parsing Error: undefined entity - */ - static $entityMap = array( - 34 => 'quot', /* quotation mark */ - 38 => 'amp', /* ampersand */ - 60 => 'lt', /* less-than sign */ - 62 => 'gt', /* greater-than sign */ - ); - - $chr = $matches[0]; - $ord = ord($chr); - - /* - * The following replaces characters undefined in HTML with the - * hex entity for the Unicode replacement character. - */ - if (($ord <= 0x1f && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7f && $ord <= 0x9f)) { - return '�'; - } - - /* - * Check if the current character to escape has a name entity we should - * replace it with while grabbing the hex value of the character. - */ - if (1 == strlen($chr)) { - $hex = strtoupper(substr('00'.bin2hex($chr), -2)); - } else { - $chr = twig_convert_encoding($chr, 'UTF-16BE', 'UTF-8'); - $hex = strtoupper(substr('0000'.bin2hex($chr), -4)); - } - - $int = hexdec($hex); - if (array_key_exists($int, $entityMap)) { - return sprintf('&%s;', $entityMap[$int]); - } - - /* - * Per OWASP recommendations, we'll use hex entities for any other - * characters where a named entity does not exist. - */ - return sprintf('&#x%s;', $hex); -} - -// add multibyte extensions if possible -if (function_exists('mb_get_info')) { - /** - * Returns the length of a variable. - * - * @param Twig_Environment $env - * @param mixed $thing A variable - * - * @return int The length of the value - */ - function twig_length_filter(Twig_Environment $env, $thing) - { - if (null === $thing) { - return 0; - } - - if (is_scalar($thing)) { - return mb_strlen($thing, $env->getCharset()); - } - - if ($thing instanceof \SimpleXMLElement) { - return count($thing); - } - - if (is_object($thing) && method_exists($thing, '__toString') && !$thing instanceof \Countable) { - return mb_strlen((string) $thing, $env->getCharset()); - } - - if ($thing instanceof \Countable || is_array($thing)) { - return count($thing); - } - - if ($thing instanceof \IteratorAggregate) { - return iterator_count($thing); - } - - return 1; - } - - /** - * Converts a string to uppercase. - * - * @param Twig_Environment $env - * @param string $string A string - * - * @return string The uppercased string - */ - function twig_upper_filter(Twig_Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtoupper($string, $charset); - } - - return strtoupper($string); - } - - /** - * Converts a string to lowercase. - * - * @param Twig_Environment $env - * @param string $string A string - * - * @return string The lowercased string - */ - function twig_lower_filter(Twig_Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtolower($string, $charset); - } - - return strtolower($string); - } - - /** - * Returns a titlecased string. - * - * @param Twig_Environment $env - * @param string $string A string - * - * @return string The titlecased string - */ - function twig_title_string_filter(Twig_Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_convert_case($string, MB_CASE_TITLE, $charset); - } - - return ucwords(strtolower($string)); - } - - /** - * Returns a capitalized string. - * - * @param Twig_Environment $env - * @param string $string A string - * - * @return string The capitalized string - */ - function twig_capitalize_string_filter(Twig_Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset); - } - - return ucfirst(strtolower($string)); - } -} -// and byte fallback -else { - /** - * Returns the length of a variable. - * - * @param Twig_Environment $env - * @param mixed $thing A variable - * - * @return int The length of the value - */ - function twig_length_filter(Twig_Environment $env, $thing) - { - if (null === $thing) { - return 0; - } - - if (is_scalar($thing)) { - return strlen($thing); - } - - if ($thing instanceof \SimpleXMLElement) { - return count($thing); - } - - if (is_object($thing) && method_exists($thing, '__toString') && !$thing instanceof \Countable) { - return strlen((string) $thing); - } - - if ($thing instanceof \Countable || is_array($thing)) { - return count($thing); - } - - if ($thing instanceof \IteratorAggregate) { - return iterator_count($thing); - } - - return 1; - } - - /** - * Returns a titlecased string. - * - * @param Twig_Environment $env - * @param string $string A string - * - * @return string The titlecased string - */ - function twig_title_string_filter(Twig_Environment $env, $string) - { - return ucwords(strtolower($string)); - } - - /** - * Returns a capitalized string. - * - * @param Twig_Environment $env - * @param string $string A string - * - * @return string The capitalized string - */ - function twig_capitalize_string_filter(Twig_Environment $env, $string) - { - return ucfirst(strtolower($string)); - } -} - -/** - * @internal - */ -function twig_ensure_traversable($seq) -{ - if ($seq instanceof Traversable || is_array($seq)) { - return $seq; - } - - return array(); -} - -/** - * Checks if a variable is empty. - * - *
- * {# evaluates to true if the foo variable is null, false, or the empty string #}
- * {% if foo is empty %}
- *     {# ... #}
- * {% endif %}
- * 
- * - * @param mixed $value A variable - * - * @return bool true if the value is empty, false otherwise - */ -function twig_test_empty($value) -{ - if ($value instanceof Countable) { - return 0 == count($value); - } - - if (is_object($value) && method_exists($value, '__toString')) { - return '' === (string) $value; - } - - return '' === $value || false === $value || null === $value || array() === $value; -} - -/** - * Checks if a variable is traversable. - * - *
- * {# evaluates to true if the foo variable is an array or a traversable object #}
- * {% if foo is iterable %}
- *     {# ... #}
- * {% endif %}
- * 
- * - * @param mixed $value A variable - * - * @return bool true if the value is traversable - */ -function twig_test_iterable($value) -{ - return $value instanceof Traversable || is_array($value); -} - -/** - * Renders a template. - * - * @param Twig_Environment $env - * @param array $context - * @param string|array $template The template to render or an array of templates to try consecutively - * @param array $variables The variables to pass to the template - * @param bool $withContext - * @param bool $ignoreMissing Whether to ignore missing templates or not - * @param bool $sandboxed Whether to sandbox the template or not - * - * @return string The rendered template - */ -function twig_include(Twig_Environment $env, $context, $template, $variables = array(), $withContext = true, $ignoreMissing = false, $sandboxed = false) -{ - $alreadySandboxed = false; - $sandbox = null; - if ($withContext) { - $variables = array_merge($context, $variables); - } - - if ($isSandboxed = $sandboxed && $env->hasExtension('Twig_Extension_Sandbox')) { - $sandbox = $env->getExtension('Twig_Extension_Sandbox'); - if (!$alreadySandboxed = $sandbox->isSandboxed()) { - $sandbox->enableSandbox(); - } - } - - $result = null; - try { - $result = $env->resolveTemplate($template)->render($variables); - } catch (Twig_Error_Loader $e) { - if (!$ignoreMissing) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - throw $e; - } - } catch (Throwable $e) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - throw $e; - } catch (Exception $e) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - throw $e; - } - - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - return $result; -} - -/** - * Returns a template content without rendering it. - * - * @param Twig_Environment $env - * @param string $name The template name - * @param bool $ignoreMissing Whether to ignore missing templates or not - * - * @return string The template source - */ -function twig_source(Twig_Environment $env, $name, $ignoreMissing = false) -{ - $loader = $env->getLoader(); - try { - if (!$loader instanceof Twig_SourceContextLoaderInterface) { - return $loader->getSource($name); - } else { - return $loader->getSourceContext($name)->getCode(); - } - } catch (Twig_Error_Loader $e) { - if (!$ignoreMissing) { - throw $e; - } - } -} - -/** - * Provides the ability to get constants from instances as well as class/global constants. - * - * @param string $constant The name of the constant - * @param null|object $object The object to get the constant from - * - * @return string - */ -function twig_constant($constant, $object = null) -{ - if (null !== $object) { - $constant = get_class($object).'::'.$constant; - } - - return constant($constant); -} - -/** - * Checks if a constant exists. - * - * @param string $constant The name of the constant - * @param null|object $object The object to get the constant from - * - * @return bool - */ -function twig_constant_is_defined($constant, $object = null) -{ - if (null !== $object) { - $constant = get_class($object).'::'.$constant; - } - - return defined($constant); -} - -/** - * Batches item. - * - * @param array $items An array of items - * @param int $size The size of the batch - * @param mixed $fill A value used to fill missing items - * - * @return array - */ -function twig_array_batch($items, $size, $fill = null) -{ - if ($items instanceof Traversable) { - $items = iterator_to_array($items, false); - } - - $size = ceil($size); - - $result = array_chunk($items, $size, true); - - if (null !== $fill && !empty($result)) { - $last = count($result) - 1; - if ($fillCount = $size - count($result[$last])) { - $result[$last] = array_merge( - $result[$last], - array_fill(0, $fillCount, $fill) - ); - } - } - - return $result; -} - -class_alias('Twig_Extension_Core', 'Twig\Extension\CoreExtension', false); diff --git a/inc/lib/Twig/Extension/Debug.php b/inc/lib/Twig/Extension/Debug.php deleted file mode 100644 index d0cd1962..00000000 --- a/inc/lib/Twig/Extension/Debug.php +++ /dev/null @@ -1,67 +0,0 @@ - $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)), - ); - } - - public function getName() - { - return 'debug'; - } -} - -function twig_var_dump(Twig_Environment $env, $context) -{ - if (!$env->isDebug()) { - return; - } - - ob_start(); - - $count = func_num_args(); - if (2 === $count) { - $vars = array(); - foreach ($context as $key => $value) { - if (!$value instanceof Twig_Template) { - $vars[$key] = $value; - } - } - - var_dump($vars); - } else { - for ($i = 2; $i < $count; ++$i) { - var_dump(func_get_arg($i)); - } - } - - return ob_get_clean(); -} - -class_alias('Twig_Extension_Debug', 'Twig\Extension\DebugExtension', false); diff --git a/inc/lib/Twig/Extension/Escaper.php b/inc/lib/Twig/Extension/Escaper.php deleted file mode 100644 index 46c2d84b..00000000 --- a/inc/lib/Twig/Extension/Escaper.php +++ /dev/null @@ -1,112 +0,0 @@ -setDefaultStrategy($defaultStrategy); - } - - public function getTokenParsers() - { - return array(new Twig_TokenParser_AutoEscape()); - } - - public function getNodeVisitors() - { - return array(new Twig_NodeVisitor_Escaper()); - } - - public function getFilters() - { - return array( - new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))), - ); - } - - /** - * Sets the default strategy to use when not defined by the user. - * - * The strategy can be a valid PHP callback that takes the template - * name as an argument and returns the strategy to use. - * - * @param string|false|callable $defaultStrategy An escaping strategy - */ - public function setDefaultStrategy($defaultStrategy) - { - // for BC - if (true === $defaultStrategy) { - @trigger_error('Using "true" as the default strategy is deprecated since version 1.21. Use "html" instead.', E_USER_DEPRECATED); - - $defaultStrategy = 'html'; - } - - if ('filename' === $defaultStrategy) { - @trigger_error('Using "filename" as the default strategy is deprecated since version 1.27. Use "name" instead.', E_USER_DEPRECATED); - - $defaultStrategy = 'name'; - } - - if ('name' === $defaultStrategy) { - $defaultStrategy = array('Twig_FileExtensionEscapingStrategy', 'guess'); - } - - $this->defaultStrategy = $defaultStrategy; - } - - /** - * Gets the default strategy to use when not defined by the user. - * - * @param string $name The template name - * - * @return string|false The default strategy to use for the template - */ - public function getDefaultStrategy($name) - { - // disable string callables to avoid calling a function named html or js, - // or any other upcoming escaping strategy - if (!is_string($this->defaultStrategy) && false !== $this->defaultStrategy) { - return call_user_func($this->defaultStrategy, $name); - } - - return $this->defaultStrategy; - } - - public function getName() - { - return 'escaper'; - } -} - -/** - * Marks a variable as being safe. - * - * @param string $string A PHP variable - * - * @return string - */ -function twig_raw_filter($string) -{ - return $string; -} - -class_alias('Twig_Extension_Escaper', 'Twig\Extension\EscaperExtension', false); diff --git a/inc/lib/Twig/Extension/GlobalsInterface.php b/inc/lib/Twig/Extension/GlobalsInterface.php deleted file mode 100644 index 922cd2c9..00000000 --- a/inc/lib/Twig/Extension/GlobalsInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ -interface Twig_Extension_GlobalsInterface -{ -} - -class_alias('Twig_Extension_GlobalsInterface', 'Twig\Extension\GlobalsInterface', false); diff --git a/inc/lib/Twig/Extension/InitRuntimeInterface.php b/inc/lib/Twig/Extension/InitRuntimeInterface.php deleted file mode 100644 index 1549862f..00000000 --- a/inc/lib/Twig/Extension/InitRuntimeInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ -interface Twig_Extension_InitRuntimeInterface -{ -} - -class_alias('Twig_Extension_InitRuntimeInterface', 'Twig\Extension\InitRuntimeInterface', false); diff --git a/inc/lib/Twig/Extension/Optimizer.php b/inc/lib/Twig/Extension/Optimizer.php deleted file mode 100644 index 6c62e3ef..00000000 --- a/inc/lib/Twig/Extension/Optimizer.php +++ /dev/null @@ -1,35 +0,0 @@ -optimizers = $optimizers; - } - - public function getNodeVisitors() - { - return array(new Twig_NodeVisitor_Optimizer($this->optimizers)); - } - - public function getName() - { - return 'optimizer'; - } -} - -class_alias('Twig_Extension_Optimizer', 'Twig\Extension\OptimizerExtension', false); diff --git a/inc/lib/Twig/Extension/Profiler.php b/inc/lib/Twig/Extension/Profiler.php deleted file mode 100644 index fcfc002b..00000000 --- a/inc/lib/Twig/Extension/Profiler.php +++ /dev/null @@ -1,49 +0,0 @@ -actives[] = $profile; - } - - public function enter(Twig_Profiler_Profile $profile) - { - $this->actives[0]->addProfile($profile); - array_unshift($this->actives, $profile); - } - - public function leave(Twig_Profiler_Profile $profile) - { - $profile->leave(); - array_shift($this->actives); - - if (1 === count($this->actives)) { - $this->actives[0]->leave(); - } - } - - public function getNodeVisitors() - { - return array(new Twig_Profiler_NodeVisitor_Profiler(get_class($this))); - } - - public function getName() - { - return 'profiler'; - } -} - -class_alias('Twig_Extension_Profiler', 'Twig\Extension\ProfilerExtension', false); -class_exists('Twig_Profiler_Profile'); diff --git a/inc/lib/Twig/Extension/Sandbox.php b/inc/lib/Twig/Extension/Sandbox.php deleted file mode 100644 index 5cb80a71..00000000 --- a/inc/lib/Twig/Extension/Sandbox.php +++ /dev/null @@ -1,103 +0,0 @@ -policy = $policy; - $this->sandboxedGlobally = $sandboxed; - } - - public function getTokenParsers() - { - return array(new Twig_TokenParser_Sandbox()); - } - - public function getNodeVisitors() - { - return array(new Twig_NodeVisitor_Sandbox()); - } - - public function enableSandbox() - { - $this->sandboxed = true; - } - - public function disableSandbox() - { - $this->sandboxed = false; - } - - public function isSandboxed() - { - return $this->sandboxedGlobally || $this->sandboxed; - } - - public function isSandboxedGlobally() - { - return $this->sandboxedGlobally; - } - - public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy) - { - $this->policy = $policy; - } - - public function getSecurityPolicy() - { - return $this->policy; - } - - public function checkSecurity($tags, $filters, $functions) - { - if ($this->isSandboxed()) { - $this->policy->checkSecurity($tags, $filters, $functions); - } - } - - public function checkMethodAllowed($obj, $method) - { - if ($this->isSandboxed()) { - $this->policy->checkMethodAllowed($obj, $method); - } - } - - public function checkPropertyAllowed($obj, $method) - { - if ($this->isSandboxed()) { - $this->policy->checkPropertyAllowed($obj, $method); - } - } - - public function ensureToStringAllowed($obj) - { - if ($this->isSandboxed() && is_object($obj)) { - $this->policy->checkMethodAllowed($obj, '__toString'); - } - - return $obj; - } - - public function getName() - { - return 'sandbox'; - } -} - -class_alias('Twig_Extension_Sandbox', 'Twig\Extension\SandboxExtension', false); diff --git a/inc/lib/Twig/Extension/Staging.php b/inc/lib/Twig/Extension/Staging.php deleted file mode 100644 index d3a0f9c9..00000000 --- a/inc/lib/Twig/Extension/Staging.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * @internal - */ -class Twig_Extension_Staging extends Twig_Extension -{ - protected $functions = array(); - protected $filters = array(); - protected $visitors = array(); - protected $tokenParsers = array(); - protected $globals = array(); - protected $tests = array(); - - public function addFunction($name, $function) - { - if (isset($this->functions[$name])) { - @trigger_error(sprintf('Overriding function "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); - } - - $this->functions[$name] = $function; - } - - public function getFunctions() - { - return $this->functions; - } - - public function addFilter($name, $filter) - { - if (isset($this->filters[$name])) { - @trigger_error(sprintf('Overriding filter "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); - } - - $this->filters[$name] = $filter; - } - - public function getFilters() - { - return $this->filters; - } - - public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) - { - $this->visitors[] = $visitor; - } - - public function getNodeVisitors() - { - return $this->visitors; - } - - public function addTokenParser(Twig_TokenParserInterface $parser) - { - if (isset($this->tokenParsers[$parser->getTag()])) { - @trigger_error(sprintf('Overriding tag "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED); - } - - $this->tokenParsers[$parser->getTag()] = $parser; - } - - public function getTokenParsers() - { - return $this->tokenParsers; - } - - public function addGlobal($name, $value) - { - $this->globals[$name] = $value; - } - - public function getGlobals() - { - return $this->globals; - } - - public function addTest($name, $test) - { - if (isset($this->tests[$name])) { - @trigger_error(sprintf('Overriding test "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); - } - - $this->tests[$name] = $test; - } - - public function getTests() - { - return $this->tests; - } - - public function getName() - { - return 'staging'; - } -} - -class_alias('Twig_Extension_Staging', 'Twig\Extension\StagingExtension', false); diff --git a/inc/lib/Twig/Extension/StringLoader.php b/inc/lib/Twig/Extension/StringLoader.php deleted file mode 100644 index 2ce3c992..00000000 --- a/inc/lib/Twig/Extension/StringLoader.php +++ /dev/null @@ -1,47 +0,0 @@ - true)), - ); - } - - public function getName() - { - return 'string_loader'; - } -} - -/** - * Loads a template from a string. - * - *
- * {{ include(template_from_string("Hello {{ name }}")) }}
- * 
- * - * @param Twig_Environment $env A Twig_Environment instance - * @param string $template A template as a string or object implementing __toString() - * - * @return Twig_Template - */ -function twig_template_from_string(Twig_Environment $env, $template) -{ - return $env->createTemplate((string) $template); -} - -class_alias('Twig_Extension_StringLoader', 'Twig\Extension\StringLoaderExtension', false); diff --git a/inc/lib/Twig/ExtensionInterface.php b/inc/lib/Twig/ExtensionInterface.php deleted file mode 100644 index 946df500..00000000 --- a/inc/lib/Twig/ExtensionInterface.php +++ /dev/null @@ -1,90 +0,0 @@ - - */ -interface Twig_ExtensionInterface -{ - /** - * Initializes the runtime environment. - * - * This is where you can load some file that contains filter functions for instance. - * - * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead - */ - public function initRuntime(Twig_Environment $environment); - - /** - * Returns the token parser instances to add to the existing list. - * - * @return Twig_TokenParserInterface[] - */ - public function getTokenParsers(); - - /** - * Returns the node visitor instances to add to the existing list. - * - * @return Twig_NodeVisitorInterface[] - */ - public function getNodeVisitors(); - - /** - * Returns a list of filters to add to the existing list. - * - * @return Twig_SimpleFilter[] - */ - public function getFilters(); - - /** - * Returns a list of tests to add to the existing list. - * - * @return Twig_SimpleTest[] - */ - public function getTests(); - - /** - * Returns a list of functions to add to the existing list. - * - * @return Twig_SimpleFunction[] - */ - public function getFunctions(); - - /** - * Returns a list of operators to add to the existing list. - * - * @return array First array of unary operators, second array of binary operators - */ - public function getOperators(); - - /** - * Returns a list of global variables to add to the existing list. - * - * @return array An array of global variables - * - * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_GlobalsInterface instead - */ - public function getGlobals(); - - /** - * Returns the name of the extension. - * - * @return string The extension name - * - * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally - */ - public function getName(); -} - -class_alias('Twig_ExtensionInterface', 'Twig\Extension\ExtensionInterface', false); -class_exists('Twig_Environment'); diff --git a/inc/lib/Twig/FactoryRuntimeLoader.php b/inc/lib/Twig/FactoryRuntimeLoader.php deleted file mode 100644 index 2cdaded1..00000000 --- a/inc/lib/Twig/FactoryRuntimeLoader.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -class Twig_FactoryRuntimeLoader implements Twig_RuntimeLoaderInterface -{ - private $map; - - /** - * @param array $map An array where keys are class names and values factory callables - */ - public function __construct($map = array()) - { - $this->map = $map; - } - - public function load($class) - { - if (isset($this->map[$class])) { - $runtimeFactory = $this->map[$class]; - - return $runtimeFactory(); - } - } -} - -class_alias('Twig_FactoryRuntimeLoader', 'Twig\RuntimeLoader\FactoryRuntimeLoader', false); diff --git a/inc/lib/Twig/FileExtensionEscapingStrategy.php b/inc/lib/Twig/FileExtensionEscapingStrategy.php deleted file mode 100644 index 8f8cd2ee..00000000 --- a/inc/lib/Twig/FileExtensionEscapingStrategy.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ -class Twig_FileExtensionEscapingStrategy -{ - /** - * Guesses the best autoescaping strategy based on the file name. - * - * @param string $name The template name - * - * @return string|false The escaping strategy name to use or false to disable - */ - public static function guess($name) - { - if (in_array(substr($name, -1), array('/', '\\'))) { - return 'html'; // return html for directories - } - - if ('.twig' === substr($name, -5)) { - $name = substr($name, 0, -5); - } - - $extension = pathinfo($name, PATHINFO_EXTENSION); - - switch ($extension) { - case 'js': - return 'js'; - - case 'css': - return 'css'; - - case 'txt': - return false; - - default: - return 'html'; - } - } -} - -class_alias('Twig_FileExtensionEscapingStrategy', 'Twig\FileExtensionEscapingStrategy', false); diff --git a/inc/lib/Twig/Filter.php b/inc/lib/Twig/Filter.php deleted file mode 100644 index 893d75d1..00000000 --- a/inc/lib/Twig/Filter.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface -{ - protected $options; - protected $arguments = array(); - - public function __construct(array $options = array()) - { - $this->options = array_merge(array( - 'needs_environment' => false, - 'needs_context' => false, - 'pre_escape' => null, - 'preserves_safety' => null, - 'callable' => null, - ), $options); - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Twig_Node $filterArgs) - { - if (isset($this->options['is_safe'])) { - return $this->options['is_safe']; - } - - if (isset($this->options['is_safe_callback'])) { - return call_user_func($this->options['is_safe_callback'], $filterArgs); - } - } - - public function getPreservesSafety() - { - return $this->options['preserves_safety']; - } - - public function getPreEscape() - { - return $this->options['pre_escape']; - } - - public function getCallable() - { - return $this->options['callable']; - } -} diff --git a/inc/lib/Twig/Filter/Function.php b/inc/lib/Twig/Filter/Function.php deleted file mode 100644 index 71b16554..00000000 --- a/inc/lib/Twig/Filter/Function.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Filter_Function extends Twig_Filter -{ - protected $function; - - public function __construct($function, array $options = array()) - { - $options['callable'] = $function; - - parent::__construct($options); - - $this->function = $function; - } - - public function compile() - { - return $this->function; - } -} diff --git a/inc/lib/Twig/Filter/Method.php b/inc/lib/Twig/Filter/Method.php deleted file mode 100644 index 1b75676c..00000000 --- a/inc/lib/Twig/Filter/Method.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Filter_Method extends Twig_Filter -{ - protected $extension; - protected $method; - - public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) - { - $options['callable'] = array($extension, $method); - - parent::__construct($options); - - $this->extension = $extension; - $this->method = $method; - } - - public function compile() - { - return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method); - } -} diff --git a/inc/lib/Twig/Filter/Node.php b/inc/lib/Twig/Filter/Node.php deleted file mode 100644 index 3e6b12ef..00000000 --- a/inc/lib/Twig/Filter/Node.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Filter_Node extends Twig_Filter -{ - protected $class; - - public function __construct($class, array $options = array()) - { - parent::__construct($options); - - $this->class = $class; - } - - public function getClass() - { - return $this->class; - } - - public function compile() - { - } -} diff --git a/inc/lib/Twig/FilterCallableInterface.php b/inc/lib/Twig/FilterCallableInterface.php deleted file mode 100644 index 21b028c4..00000000 --- a/inc/lib/Twig/FilterCallableInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FilterCallableInterface -{ - public function getCallable(); -} diff --git a/inc/lib/Twig/FilterInterface.php b/inc/lib/Twig/FilterInterface.php deleted file mode 100644 index 9d7e9ab6..00000000 --- a/inc/lib/Twig/FilterInterface.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FilterInterface -{ - /** - * Compiles a filter. - * - * @return string The PHP code for the filter - */ - public function compile(); - - public function needsEnvironment(); - - public function needsContext(); - - public function getSafe(Twig_Node $filterArgs); - - public function getPreservesSafety(); - - public function getPreEscape(); - - public function setArguments($arguments); - - public function getArguments(); -} diff --git a/inc/lib/Twig/Function.php b/inc/lib/Twig/Function.php deleted file mode 100644 index 9dc16e90..00000000 --- a/inc/lib/Twig/Function.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface -{ - protected $options; - protected $arguments = array(); - - public function __construct(array $options = array()) - { - $this->options = array_merge(array( - 'needs_environment' => false, - 'needs_context' => false, - 'callable' => null, - ), $options); - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Twig_Node $functionArgs) - { - if (isset($this->options['is_safe'])) { - return $this->options['is_safe']; - } - - if (isset($this->options['is_safe_callback'])) { - return call_user_func($this->options['is_safe_callback'], $functionArgs); - } - - return array(); - } - - public function getCallable() - { - return $this->options['callable']; - } -} diff --git a/inc/lib/Twig/Function/Function.php b/inc/lib/Twig/Function/Function.php deleted file mode 100644 index 97c0eb77..00000000 --- a/inc/lib/Twig/Function/Function.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Function_Function extends Twig_Function -{ - protected $function; - - public function __construct($function, array $options = array()) - { - $options['callable'] = $function; - - parent::__construct($options); - - $this->function = $function; - } - - public function compile() - { - return $this->function; - } -} diff --git a/inc/lib/Twig/Function/Method.php b/inc/lib/Twig/Function/Method.php deleted file mode 100644 index 4299e118..00000000 --- a/inc/lib/Twig/Function/Method.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Function_Method extends Twig_Function -{ - protected $extension; - protected $method; - - public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) - { - $options['callable'] = array($extension, $method); - - parent::__construct($options); - - $this->extension = $extension; - $this->method = $method; - } - - public function compile() - { - return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method); - } -} diff --git a/inc/lib/Twig/Function/Node.php b/inc/lib/Twig/Function/Node.php deleted file mode 100644 index 0adc5d93..00000000 --- a/inc/lib/Twig/Function/Node.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Function_Node extends Twig_Function -{ - protected $class; - - public function __construct($class, array $options = array()) - { - parent::__construct($options); - - $this->class = $class; - } - - public function getClass() - { - return $this->class; - } - - public function compile() - { - } -} diff --git a/inc/lib/Twig/FunctionCallableInterface.php b/inc/lib/Twig/FunctionCallableInterface.php deleted file mode 100644 index d23d6917..00000000 --- a/inc/lib/Twig/FunctionCallableInterface.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FunctionCallableInterface -{ - public function getCallable(); -} diff --git a/inc/lib/Twig/FunctionInterface.php b/inc/lib/Twig/FunctionInterface.php deleted file mode 100644 index 00d4f95c..00000000 --- a/inc/lib/Twig/FunctionInterface.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_FunctionInterface -{ - /** - * Compiles a function. - * - * @return string The PHP code for the function - */ - public function compile(); - - public function needsEnvironment(); - - public function needsContext(); - - public function getSafe(Twig_Node $filterArgs); - - public function setArguments($arguments); - - public function getArguments(); -} diff --git a/inc/lib/Twig/Lexer.php b/inc/lib/Twig/Lexer.php deleted file mode 100644 index 41211eb2..00000000 --- a/inc/lib/Twig/Lexer.php +++ /dev/null @@ -1,427 +0,0 @@ - - */ -class Twig_Lexer implements Twig_LexerInterface -{ - protected $tokens; - protected $code; - protected $cursor; - protected $lineno; - protected $end; - protected $state; - protected $states; - protected $brackets; - protected $env; - // to be renamed to $name in 2.0 (where it is private) - protected $filename; - protected $options; - protected $regexes; - protected $position; - protected $positions; - protected $currentVarBlockLine; - - private $source; - - const STATE_DATA = 0; - const STATE_BLOCK = 1; - const STATE_VAR = 2; - const STATE_STRING = 3; - const STATE_INTERPOLATION = 4; - - const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'; - const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A'; - const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; - const REGEX_DQ_STRING_DELIM = '/"/A'; - const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; - const PUNCTUATION = '()[]{}?:.,|'; - - public function __construct(Twig_Environment $env, array $options = array()) - { - $this->env = $env; - - $this->options = array_merge(array( - 'tag_comment' => array('{#', '#}'), - 'tag_block' => array('{%', '%}'), - 'tag_variable' => array('{{', '}}'), - 'whitespace_trim' => '-', - 'interpolation' => array('#{', '}'), - ), $options); - - $this->regexes = array( - 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A', - 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A', - 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s', - 'operator' => $this->getOperatorRegex(), - 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s', - 'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As', - 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As', - 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s', - 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A', - 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A', - ); - } - - public function tokenize($code, $name = null) - { - if (!$code instanceof Twig_Source) { - @trigger_error(sprintf('Passing a string as the $code argument of %s() is deprecated since version 1.27 and will be removed in 2.0. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $this->source = new Twig_Source($code, $name); - } else { - $this->source = $code; - } - - if (((int) ini_get('mbstring.func_overload')) & 2) { - @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED); - } - - if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { - $mbEncoding = mb_internal_encoding(); - mb_internal_encoding('ASCII'); - } else { - $mbEncoding = null; - } - - $this->code = str_replace(array("\r\n", "\r"), "\n", $this->source->getCode()); - $this->filename = $this->source->getName(); - $this->cursor = 0; - $this->lineno = 1; - $this->end = strlen($this->code); - $this->tokens = array(); - $this->state = self::STATE_DATA; - $this->states = array(); - $this->brackets = array(); - $this->position = -1; - - // find all token starts in one go - preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE); - $this->positions = $matches; - - while ($this->cursor < $this->end) { - // dispatch to the lexing functions depending - // on the current state - switch ($this->state) { - case self::STATE_DATA: - $this->lexData(); - break; - - case self::STATE_BLOCK: - $this->lexBlock(); - break; - - case self::STATE_VAR: - $this->lexVar(); - break; - - case self::STATE_STRING: - $this->lexString(); - break; - - case self::STATE_INTERPOLATION: - $this->lexInterpolation(); - break; - } - } - - $this->pushToken(Twig_Token::EOF_TYPE); - - if (!empty($this->brackets)) { - list($expect, $lineno) = array_pop($this->brackets); - throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source); - } - - if ($mbEncoding) { - mb_internal_encoding($mbEncoding); - } - - return new Twig_TokenStream($this->tokens, $this->source); - } - - protected function lexData() - { - // if no matches are left we return the rest of the template as simple text token - if ($this->position == count($this->positions[0]) - 1) { - $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor)); - $this->cursor = $this->end; - - return; - } - - // Find the first token after the current cursor - $position = $this->positions[0][++$this->position]; - while ($position[1] < $this->cursor) { - if ($this->position == count($this->positions[0]) - 1) { - return; - } - $position = $this->positions[0][++$this->position]; - } - - // push the template text first - $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor); - if (isset($this->positions[2][$this->position][0])) { - $text = rtrim($text); - } - $this->pushToken(Twig_Token::TEXT_TYPE, $text); - $this->moveCursor($textContent.$position[0]); - - switch ($this->positions[1][$this->position][0]) { - case $this->options['tag_comment'][0]: - $this->lexComment(); - break; - - case $this->options['tag_block'][0]: - // raw data? - if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) { - $this->moveCursor($match[0]); - $this->lexRawData($match[1]); - // {% line \d+ %} - } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) { - $this->moveCursor($match[0]); - $this->lineno = (int) $match[1]; - } else { - $this->pushToken(Twig_Token::BLOCK_START_TYPE); - $this->pushState(self::STATE_BLOCK); - $this->currentVarBlockLine = $this->lineno; - } - break; - - case $this->options['tag_variable'][0]: - $this->pushToken(Twig_Token::VAR_START_TYPE); - $this->pushState(self::STATE_VAR); - $this->currentVarBlockLine = $this->lineno; - break; - } - } - - protected function lexBlock() - { - if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) { - $this->pushToken(Twig_Token::BLOCK_END_TYPE); - $this->moveCursor($match[0]); - $this->popState(); - } else { - $this->lexExpression(); - } - } - - protected function lexVar() - { - if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) { - $this->pushToken(Twig_Token::VAR_END_TYPE); - $this->moveCursor($match[0]); - $this->popState(); - } else { - $this->lexExpression(); - } - } - - protected function lexExpression() - { - // whitespace - if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) { - $this->moveCursor($match[0]); - - if ($this->cursor >= $this->end) { - throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', self::STATE_BLOCK === $this->state ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source); - } - } - - // operators - if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) { - $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0])); - $this->moveCursor($match[0]); - } - // names - elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) { - $this->pushToken(Twig_Token::NAME_TYPE, $match[0]); - $this->moveCursor($match[0]); - } - // numbers - elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) { - $number = (float) $match[0]; // floats - if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) { - $number = (int) $match[0]; // integers lower than the maximum - } - $this->pushToken(Twig_Token::NUMBER_TYPE, $number); - $this->moveCursor($match[0]); - } - // punctuation - elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) { - // opening bracket - if (false !== strpos('([{', $this->code[$this->cursor])) { - $this->brackets[] = array($this->code[$this->cursor], $this->lineno); - } - // closing bracket - elseif (false !== strpos(')]}', $this->code[$this->cursor])) { - if (empty($this->brackets)) { - throw new Twig_Error_Syntax(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source); - } - - list($expect, $lineno) = array_pop($this->brackets); - if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { - throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source); - } - } - - $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); - ++$this->cursor; - } - // strings - elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) { - $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1))); - $this->moveCursor($match[0]); - } - // opening double quoted string - elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { - $this->brackets[] = array('"', $this->lineno); - $this->pushState(self::STATE_STRING); - $this->moveCursor($match[0]); - } - // unlexable - else { - throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source); - } - } - - protected function lexRawData($tag) - { - if ('raw' === $tag) { - @trigger_error(sprintf('Twig Tag "raw" is deprecated since version 1.21. Use "verbatim" instead in %s at line %d.', $this->filename, $this->lineno), E_USER_DEPRECATED); - } - - if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { - throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->source); - } - - $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); - $this->moveCursor($text.$match[0][0]); - - if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) { - $text = rtrim($text); - } - - $this->pushToken(Twig_Token::TEXT_TYPE, $text); - } - - protected function lexComment() - { - if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { - throw new Twig_Error_Syntax('Unclosed comment.', $this->lineno, $this->source); - } - - $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); - } - - protected function lexString() - { - if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) { - $this->brackets[] = array($this->options['interpolation'][0], $this->lineno); - $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE); - $this->moveCursor($match[0]); - $this->pushState(self::STATE_INTERPOLATION); - } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) { - $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0])); - $this->moveCursor($match[0]); - } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { - list($expect, $lineno) = array_pop($this->brackets); - if ('"' != $this->code[$this->cursor]) { - throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source); - } - - $this->popState(); - ++$this->cursor; - } else { - // unlexable - throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source); - } - } - - protected function lexInterpolation() - { - $bracket = end($this->brackets); - if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) { - array_pop($this->brackets); - $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE); - $this->moveCursor($match[0]); - $this->popState(); - } else { - $this->lexExpression(); - } - } - - protected function pushToken($type, $value = '') - { - // do not push empty text tokens - if (Twig_Token::TEXT_TYPE === $type && '' === $value) { - return; - } - - $this->tokens[] = new Twig_Token($type, $value, $this->lineno); - } - - protected function moveCursor($text) - { - $this->cursor += strlen($text); - $this->lineno += substr_count($text, "\n"); - } - - protected function getOperatorRegex() - { - $operators = array_merge( - array('='), - array_keys($this->env->getUnaryOperators()), - array_keys($this->env->getBinaryOperators()) - ); - - $operators = array_combine($operators, array_map('strlen', $operators)); - arsort($operators); - - $regex = array(); - foreach ($operators as $operator => $length) { - // an operator that ends with a character must be followed by - // a whitespace or a parenthesis - if (ctype_alpha($operator[$length - 1])) { - $r = preg_quote($operator, '/').'(?=[\s()])'; - } else { - $r = preg_quote($operator, '/'); - } - - // an operator with a space can be any amount of whitespaces - $r = preg_replace('/\s+/', '\s+', $r); - - $regex[] = $r; - } - - return '/'.implode('|', $regex).'/A'; - } - - protected function pushState($state) - { - $this->states[] = $this->state; - $this->state = $state; - } - - protected function popState() - { - if (0 === count($this->states)) { - throw new Exception('Cannot pop state without a previous state.'); - } - - $this->state = array_pop($this->states); - } -} - -class_alias('Twig_Lexer', 'Twig\Lexer', false); diff --git a/inc/lib/Twig/LexerInterface.php b/inc/lib/Twig/LexerInterface.php deleted file mode 100644 index c10bbfec..00000000 --- a/inc/lib/Twig/LexerInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_LexerInterface -{ - /** - * Tokenizes a source code. - * - * @param string|Twig_Source $code The source code - * @param string $name A unique identifier for the source code - * - * @return Twig_TokenStream - * - * @throws Twig_Error_Syntax When the code is syntactically wrong - */ - public function tokenize($code, $name = null); -} diff --git a/inc/lib/Twig/Loader/Array.php b/inc/lib/Twig/Loader/Array.php deleted file mode 100644 index 0aac7690..00000000 --- a/inc/lib/Twig/Loader/Array.php +++ /dev/null @@ -1,97 +0,0 @@ - - */ -class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface -{ - protected $templates = array(); - - /** - * @param array $templates An array of templates (keys are the names, and values are the source code) - */ - public function __construct(array $templates = array()) - { - $this->templates = $templates; - } - - /** - * Adds or overrides a template. - * - * @param string $name The template name - * @param string $template The template source - */ - public function setTemplate($name, $template) - { - $this->templates[(string) $name] = $template; - } - - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED); - - $name = (string) $name; - if (!isset($this->templates[$name])) { - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); - } - - return $this->templates[$name]; - } - - public function getSourceContext($name) - { - $name = (string) $name; - if (!isset($this->templates[$name])) { - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); - } - - return new Twig_Source($this->templates[$name], $name); - } - - public function exists($name) - { - return isset($this->templates[(string) $name]); - } - - public function getCacheKey($name) - { - $name = (string) $name; - if (!isset($this->templates[$name])) { - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); - } - - return $name.':'.$this->templates[$name]; - } - - public function isFresh($name, $time) - { - $name = (string) $name; - if (!isset($this->templates[$name])) { - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); - } - - return true; - } -} - -class_alias('Twig_Loader_Array', 'Twig\Loader\ArrayLoader', false); diff --git a/inc/lib/Twig/Loader/Chain.php b/inc/lib/Twig/Loader/Chain.php deleted file mode 100644 index 59a33796..00000000 --- a/inc/lib/Twig/Loader/Chain.php +++ /dev/null @@ -1,151 +0,0 @@ - - */ -class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface -{ - private $hasSourceCache = array(); - protected $loaders = array(); - - /** - * @param Twig_LoaderInterface[] $loaders - */ - public function __construct(array $loaders = array()) - { - foreach ($loaders as $loader) { - $this->addLoader($loader); - } - } - - public function addLoader(Twig_LoaderInterface $loader) - { - $this->loaders[] = $loader; - $this->hasSourceCache = array(); - } - - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED); - - $exceptions = array(); - foreach ($this->loaders as $loader) { - if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { - continue; - } - - try { - return $loader->getSource($name); - } catch (Twig_Error_Loader $e) { - $exceptions[] = $e->getMessage(); - } - } - - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); - } - - public function getSourceContext($name) - { - $exceptions = array(); - foreach ($this->loaders as $loader) { - if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { - continue; - } - - try { - if ($loader instanceof Twig_SourceContextLoaderInterface) { - return $loader->getSourceContext($name); - } - - return new Twig_Source($loader->getSource($name), $name); - } catch (Twig_Error_Loader $e) { - $exceptions[] = $e->getMessage(); - } - } - - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); - } - - public function exists($name) - { - $name = (string) $name; - - if (isset($this->hasSourceCache[$name])) { - return $this->hasSourceCache[$name]; - } - - foreach ($this->loaders as $loader) { - if ($loader instanceof Twig_ExistsLoaderInterface) { - if ($loader->exists($name)) { - return $this->hasSourceCache[$name] = true; - } - - continue; - } - - try { - if ($loader instanceof Twig_SourceContextLoaderInterface) { - $loader->getSourceContext($name); - } else { - $loader->getSource($name); - } - - return $this->hasSourceCache[$name] = true; - } catch (Twig_Error_Loader $e) { - } - } - - return $this->hasSourceCache[$name] = false; - } - - public function getCacheKey($name) - { - $exceptions = array(); - foreach ($this->loaders as $loader) { - if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { - continue; - } - - try { - return $loader->getCacheKey($name); - } catch (Twig_Error_Loader $e) { - $exceptions[] = get_class($loader).': '.$e->getMessage(); - } - } - - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); - } - - public function isFresh($name, $time) - { - $exceptions = array(); - foreach ($this->loaders as $loader) { - if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { - continue; - } - - try { - return $loader->isFresh($name, $time); - } catch (Twig_Error_Loader $e) { - $exceptions[] = get_class($loader).': '.$e->getMessage(); - } - } - - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); - } -} - -class_alias('Twig_Loader_Chain', 'Twig\Loader\ChainLoader', false); diff --git a/inc/lib/Twig/Loader/Filesystem.php b/inc/lib/Twig/Loader/Filesystem.php deleted file mode 100644 index 4e8be0d5..00000000 --- a/inc/lib/Twig/Loader/Filesystem.php +++ /dev/null @@ -1,290 +0,0 @@ - - */ -class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface -{ - /** Identifier of the main namespace. */ - const MAIN_NAMESPACE = '__main__'; - - protected $paths = array(); - protected $cache = array(); - protected $errorCache = array(); - - private $rootPath; - - /** - * @param string|array $paths A path or an array of paths where to look for templates - * @param string|null $rootPath The root path common to all relative paths (null for getcwd()) - */ - public function __construct($paths = array(), $rootPath = null) - { - $this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR; - if (false !== $realPath = realpath($rootPath)) { - $this->rootPath = $realPath.DIRECTORY_SEPARATOR; - } - - if ($paths) { - $this->setPaths($paths); - } - } - - /** - * Returns the paths to the templates. - * - * @param string $namespace A path namespace - * - * @return array The array of paths where to look for templates - */ - public function getPaths($namespace = self::MAIN_NAMESPACE) - { - return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array(); - } - - /** - * Returns the path namespaces. - * - * The main namespace is always defined. - * - * @return array The array of defined namespaces - */ - public function getNamespaces() - { - return array_keys($this->paths); - } - - /** - * Sets the paths where templates are stored. - * - * @param string|array $paths A path or an array of paths where to look for templates - * @param string $namespace A path namespace - */ - public function setPaths($paths, $namespace = self::MAIN_NAMESPACE) - { - if (!is_array($paths)) { - $paths = array($paths); - } - - $this->paths[$namespace] = array(); - foreach ($paths as $path) { - $this->addPath($path, $namespace); - } - } - - /** - * Adds a path where templates are stored. - * - * @param string $path A path where to look for templates - * @param string $namespace A path namespace - * - * @throws Twig_Error_Loader - */ - public function addPath($path, $namespace = self::MAIN_NAMESPACE) - { - // invalidate the cache - $this->cache = $this->errorCache = array(); - - $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path; - if (!is_dir($checkPath)) { - throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath)); - } - - $this->paths[$namespace][] = rtrim($path, '/\\'); - } - - /** - * Prepends a path where templates are stored. - * - * @param string $path A path where to look for templates - * @param string $namespace A path namespace - * - * @throws Twig_Error_Loader - */ - public function prependPath($path, $namespace = self::MAIN_NAMESPACE) - { - // invalidate the cache - $this->cache = $this->errorCache = array(); - - $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path; - if (!is_dir($checkPath)) { - throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath)); - } - - $path = rtrim($path, '/\\'); - - if (!isset($this->paths[$namespace])) { - $this->paths[$namespace][] = $path; - } else { - array_unshift($this->paths[$namespace], $path); - } - } - - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED); - - return file_get_contents($this->findTemplate($name)); - } - - public function getSourceContext($name) - { - $path = $this->findTemplate($name); - - return new Twig_Source(file_get_contents($path), $name, $path); - } - - public function getCacheKey($name) - { - $path = $this->findTemplate($name); - $len = strlen($this->rootPath); - if (0 === strncmp($this->rootPath, $path, $len)) { - return substr($path, $len); - } - - return $path; - } - - public function exists($name) - { - $name = $this->normalizeName($name); - - if (isset($this->cache[$name])) { - return true; - } - - try { - return false !== $this->findTemplate($name, false); - } catch (Twig_Error_Loader $exception) { - @trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', get_class($this)), E_USER_DEPRECATED); - - return false; - } - } - - public function isFresh($name, $time) - { - return filemtime($this->findTemplate($name)) < $time; - } - - protected function findTemplate($name) - { - $throw = func_num_args() > 1 ? func_get_arg(1) : true; - $name = $this->normalizeName($name); - - if (isset($this->cache[$name])) { - return $this->cache[$name]; - } - - if (isset($this->errorCache[$name])) { - if (!$throw) { - return false; - } - - throw new Twig_Error_Loader($this->errorCache[$name]); - } - - $this->validateName($name); - - list($namespace, $shortname) = $this->parseName($name); - - if (!isset($this->paths[$namespace])) { - $this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace); - - if (!$throw) { - return false; - } - - throw new Twig_Error_Loader($this->errorCache[$name]); - } - - foreach ($this->paths[$namespace] as $path) { - if (!$this->isAbsolutePath($path)) { - $path = $this->rootPath.'/'.$path; - } - - if (is_file($path.'/'.$shortname)) { - if (false !== $realpath = realpath($path.'/'.$shortname)) { - return $this->cache[$name] = $realpath; - } - - return $this->cache[$name] = $path.'/'.$shortname; - } - } - - $this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])); - - if (!$throw) { - return false; - } - - throw new Twig_Error_Loader($this->errorCache[$name]); - } - - protected function parseName($name, $default = self::MAIN_NAMESPACE) - { - if (isset($name[0]) && '@' == $name[0]) { - if (false === $pos = strpos($name, '/')) { - throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name)); - } - - $namespace = substr($name, 1, $pos - 1); - $shortname = substr($name, $pos + 1); - - return array($namespace, $shortname); - } - - return array($default, $name); - } - - protected function normalizeName($name) - { - return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); - } - - protected function validateName($name) - { - if (false !== strpos($name, "\0")) { - throw new Twig_Error_Loader('A template name cannot contain NUL bytes.'); - } - - $name = ltrim($name, '/'); - $parts = explode('/', $name); - $level = 0; - foreach ($parts as $part) { - if ('..' === $part) { - --$level; - } elseif ('.' !== $part) { - ++$level; - } - - if ($level < 0) { - throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name)); - } - } - } - - private function isAbsolutePath($file) - { - return strspn($file, '/\\', 0, 1) - || (strlen($file) > 3 && ctype_alpha($file[0]) - && ':' === substr($file, 1, 1) - && strspn($file, '/\\', 2, 1) - ) - || null !== parse_url($file, PHP_URL_SCHEME) - ; - } -} - -class_alias('Twig_Loader_Filesystem', 'Twig\Loader\FilesystemLoader', false); diff --git a/inc/lib/Twig/Loader/String.php b/inc/lib/Twig/Loader/String.php deleted file mode 100644 index 950bd35b..00000000 --- a/inc/lib/Twig/Loader/String.php +++ /dev/null @@ -1,58 +0,0 @@ - - */ -class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface -{ - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', get_class($this)), E_USER_DEPRECATED); - - return $name; - } - - public function getSourceContext($name) - { - return new Twig_Source($name, $name); - } - - public function exists($name) - { - return true; - } - - public function getCacheKey($name) - { - return $name; - } - - public function isFresh($name, $time) - { - return true; - } -} diff --git a/inc/lib/Twig/LoaderInterface.php b/inc/lib/Twig/LoaderInterface.php deleted file mode 100644 index 459a70ab..00000000 --- a/inc/lib/Twig/LoaderInterface.php +++ /dev/null @@ -1,57 +0,0 @@ - - */ -interface Twig_LoaderInterface -{ - /** - * Gets the source code of a template, given its name. - * - * @param string $name The name of the template to load - * - * @return string The template source code - * - * @throws Twig_Error_Loader When $name is not found - * - * @deprecated since 1.27 (to be removed in 2.0), implement Twig_SourceContextLoaderInterface - */ - public function getSource($name); - - /** - * Gets the cache key to use for the cache for a given template name. - * - * @param string $name The name of the template to load - * - * @return string The cache key - * - * @throws Twig_Error_Loader When $name is not found - */ - public function getCacheKey($name); - - /** - * Returns true if the template is still fresh. - * - * @param string $name The template name - * @param int $time Timestamp of the last modification time of the - * cached template - * - * @return bool true if the template is fresh, false otherwise - * - * @throws Twig_Error_Loader When $name is not found - */ - public function isFresh($name, $time); -} - -class_alias('Twig_LoaderInterface', 'Twig\Loader\LoaderInterface', false); diff --git a/inc/lib/Twig/Markup.php b/inc/lib/Twig/Markup.php deleted file mode 100644 index 8591d1f9..00000000 --- a/inc/lib/Twig/Markup.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -class Twig_Markup implements Countable -{ - protected $content; - protected $charset; - - public function __construct($content, $charset) - { - $this->content = (string) $content; - $this->charset = $charset; - } - - public function __toString() - { - return $this->content; - } - - public function count() - { - return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content); - } -} - -class_alias('Twig_Markup', 'Twig\Markup', false); diff --git a/inc/lib/Twig/Node.php b/inc/lib/Twig/Node.php deleted file mode 100644 index 89ada144..00000000 --- a/inc/lib/Twig/Node.php +++ /dev/null @@ -1,256 +0,0 @@ - - */ -class Twig_Node implements Twig_NodeInterface -{ - protected $nodes; - protected $attributes; - protected $lineno; - protected $tag; - - private $name; - - /** - * Constructor. - * - * The nodes are automatically made available as properties ($this->node). - * The attributes are automatically made available as array items ($this['name']). - * - * @param array $nodes An array of named nodes - * @param array $attributes An array of attributes (should not be nodes) - * @param int $lineno The line number - * @param string $tag The tag name associated with the Node - */ - public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null) - { - foreach ($nodes as $name => $node) { - if (!$node instanceof Twig_NodeInterface) { - @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', is_object($node) ? get_class($node) : null === $node ? 'null' : gettype($node), $name, get_class($this)), E_USER_DEPRECATED); - } - } - $this->nodes = $nodes; - $this->attributes = $attributes; - $this->lineno = $lineno; - $this->tag = $tag; - } - - public function __toString() - { - $attributes = array(); - foreach ($this->attributes as $name => $value) { - $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); - } - - $repr = array(get_class($this).'('.implode(', ', $attributes)); - - if (count($this->nodes)) { - foreach ($this->nodes as $name => $node) { - $len = strlen($name) + 4; - $noderepr = array(); - foreach (explode("\n", (string) $node) as $line) { - $noderepr[] = str_repeat(' ', $len).$line; - } - - $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr))); - } - - $repr[] = ')'; - } else { - $repr[0] .= ')'; - } - - return implode("\n", $repr); - } - - /** - * @deprecated since 1.16.1 (to be removed in 2.0) - */ - public function toXml($asDom = false) - { - @trigger_error(sprintf('%s is deprecated since version 1.16.1 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); - - $dom = new DOMDocument('1.0', 'UTF-8'); - $dom->formatOutput = true; - $dom->appendChild($xml = $dom->createElement('twig')); - - $xml->appendChild($node = $dom->createElement('node')); - $node->setAttribute('class', get_class($this)); - - foreach ($this->attributes as $name => $value) { - $node->appendChild($attribute = $dom->createElement('attribute')); - $attribute->setAttribute('name', $name); - $attribute->appendChild($dom->createTextNode($value)); - } - - foreach ($this->nodes as $name => $n) { - if (null === $n) { - continue; - } - - $child = $n->toXml(true)->getElementsByTagName('node')->item(0); - $child = $dom->importNode($child, true); - $child->setAttribute('name', $name); - - $node->appendChild($child); - } - - return $asDom ? $dom : $dom->saveXML(); - } - - public function compile(Twig_Compiler $compiler) - { - foreach ($this->nodes as $node) { - $node->compile($compiler); - } - } - - public function getTemplateLine() - { - return $this->lineno; - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getLine() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateLine() instead.', E_USER_DEPRECATED); - - return $this->lineno; - } - - public function getNodeTag() - { - return $this->tag; - } - - /** - * @return bool - */ - public function hasAttribute($name) - { - return array_key_exists($name, $this->attributes); - } - - /** - * @return mixed - */ - public function getAttribute($name) - { - if (!array_key_exists($name, $this->attributes)) { - throw new LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this))); - } - - return $this->attributes[$name]; - } - - /** - * @param string $name - * @param mixed $value - */ - public function setAttribute($name, $value) - { - $this->attributes[$name] = $value; - } - - public function removeAttribute($name) - { - unset($this->attributes[$name]); - } - - /** - * @return bool - */ - public function hasNode($name) - { - return array_key_exists($name, $this->nodes); - } - - /** - * @return Twig_Node - */ - public function getNode($name) - { - if (!array_key_exists($name, $this->nodes)) { - throw new LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this))); - } - - return $this->nodes[$name]; - } - - public function setNode($name, $node = null) - { - if (!$node instanceof Twig_NodeInterface) { - @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', is_object($node) ? get_class($node) : null === $node ? 'null' : gettype($node), $name, get_class($this)), E_USER_DEPRECATED); - } - - $this->nodes[$name] = $node; - } - - public function removeNode($name) - { - unset($this->nodes[$name]); - } - - public function count() - { - return count($this->nodes); - } - - public function getIterator() - { - return new ArrayIterator($this->nodes); - } - - public function setTemplateName($name) - { - $this->name = $name; - foreach ($this->nodes as $node) { - if (null !== $node) { - $node->setTemplateName($name); - } - } - } - - public function getTemplateName() - { - return $this->name; - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function setFilename($name) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', E_USER_DEPRECATED); - - $this->setTemplateName($name); - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', E_USER_DEPRECATED); - - return $this->name; - } -} - -class_alias('Twig_Node', 'Twig\Node\Node', false); -class_exists('Twig_Compiler'); diff --git a/inc/lib/Twig/Node/AutoEscape.php b/inc/lib/Twig/Node/AutoEscape.php deleted file mode 100644 index 17e4e381..00000000 --- a/inc/lib/Twig/Node/AutoEscape.php +++ /dev/null @@ -1,36 +0,0 @@ - - */ -class Twig_Node_AutoEscape extends Twig_Node -{ - public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape') - { - parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->subcompile($this->getNode('body')); - } -} - -class_alias('Twig_Node_AutoEscape', 'Twig\Node\AutoEscapeNode', false); diff --git a/inc/lib/Twig/Node/Block.php b/inc/lib/Twig/Node/Block.php deleted file mode 100644 index 91752ad2..00000000 --- a/inc/lib/Twig/Node/Block.php +++ /dev/null @@ -1,41 +0,0 @@ - - */ -class Twig_Node_Block extends Twig_Node -{ - public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null) - { - parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n") - ->indent() - ; - - $compiler - ->subcompile($this->getNode('body')) - ->outdent() - ->write("}\n\n") - ; - } -} - -class_alias('Twig_Node_Block', 'Twig\Node\BlockNode', false); diff --git a/inc/lib/Twig/Node/BlockReference.php b/inc/lib/Twig/Node/BlockReference.php deleted file mode 100644 index 92a9f398..00000000 --- a/inc/lib/Twig/Node/BlockReference.php +++ /dev/null @@ -1,34 +0,0 @@ - - */ -class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface -{ - public function __construct($name, $lineno, $tag = null) - { - parent::__construct(array(), array('name' => $name), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name'))) - ; - } -} - -class_alias('Twig_Node_BlockReference', 'Twig\Node\BlockReferenceNode', false); diff --git a/inc/lib/Twig/Node/Body.php b/inc/lib/Twig/Node/Body.php deleted file mode 100644 index 07dfef8b..00000000 --- a/inc/lib/Twig/Node/Body.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -class Twig_Node_Body extends Twig_Node -{ -} - -class_alias('Twig_Node_Body', 'Twig\Node\BodyNode', false); diff --git a/inc/lib/Twig/Node/CheckSecurity.php b/inc/lib/Twig/Node/CheckSecurity.php deleted file mode 100644 index 7258acb6..00000000 --- a/inc/lib/Twig/Node/CheckSecurity.php +++ /dev/null @@ -1,80 +0,0 @@ - - */ -class Twig_Node_CheckSecurity extends Twig_Node -{ - protected $usedFilters; - protected $usedTags; - protected $usedFunctions; - - public function __construct(array $usedFilters, array $usedTags, array $usedFunctions) - { - $this->usedFilters = $usedFilters; - $this->usedTags = $usedTags; - $this->usedFunctions = $usedFunctions; - - parent::__construct(); - } - - public function compile(Twig_Compiler $compiler) - { - $tags = $filters = $functions = array(); - foreach (array('tags', 'filters', 'functions') as $type) { - foreach ($this->{'used'.ucfirst($type)} as $name => $node) { - if ($node instanceof Twig_Node) { - ${$type}[$name] = $node->getTemplateLine(); - } else { - ${$type}[$node] = null; - } - } - } - - $compiler - ->write('$tags = ')->repr(array_filter($tags))->raw(";\n") - ->write('$filters = ')->repr(array_filter($filters))->raw(";\n") - ->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n") - ->write("try {\n") - ->indent() - ->write("\$this->env->getExtension('Twig_Extension_Sandbox')->checkSecurity(\n") - ->indent() - ->write(!$tags ? "array(),\n" : "array('".implode("', '", array_keys($tags))."'),\n") - ->write(!$filters ? "array(),\n" : "array('".implode("', '", array_keys($filters))."'),\n") - ->write(!$functions ? "array()\n" : "array('".implode("', '", array_keys($functions))."')\n") - ->outdent() - ->write(");\n") - ->outdent() - ->write("} catch (Twig_Sandbox_SecurityError \$e) {\n") - ->indent() - ->write("\$e->setSourceContext(\$this->getSourceContext());\n\n") - ->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n") - ->indent() - ->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n") - ->outdent() - ->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFilterError && isset(\$filters[\$e->getFilterName()])) {\n") - ->indent() - ->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n") - ->outdent() - ->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFunctionError && isset(\$functions[\$e->getFunctionName()])) {\n") - ->indent() - ->write("\$e->setTemplateLine(\$functions[\$e->getFunctionName()]);\n") - ->outdent() - ->write("}\n\n") - ->write("throw \$e;\n") - ->outdent() - ->write("}\n\n") - ; - } -} - -class_alias('Twig_Node_CheckSecurity', 'Twig\Node\CheckSecurityNode', false); diff --git a/inc/lib/Twig/Node/Do.php b/inc/lib/Twig/Node/Do.php deleted file mode 100644 index cdd7e77a..00000000 --- a/inc/lib/Twig/Node/Do.php +++ /dev/null @@ -1,35 +0,0 @@ - - */ -class Twig_Node_Do extends Twig_Node -{ - public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) - { - parent::__construct(array('expr' => $expr), array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write('') - ->subcompile($this->getNode('expr')) - ->raw(";\n") - ; - } -} - -class_alias('Twig_Node_Do', 'Twig\Node\DoNode', false); diff --git a/inc/lib/Twig/Node/Embed.php b/inc/lib/Twig/Node/Embed.php deleted file mode 100644 index 3785d3a9..00000000 --- a/inc/lib/Twig/Node/Embed.php +++ /dev/null @@ -1,46 +0,0 @@ - - */ -class Twig_Node_Embed extends Twig_Node_Include -{ - // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module) - public function __construct($name, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) - { - parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag); - - $this->setAttribute('name', $name); - // to be removed in 2.0, used name instead - $this->setAttribute('filename', $name); - $this->setAttribute('index', $index); - } - - protected function addGetTemplate(Twig_Compiler $compiler) - { - $compiler - ->write('$this->loadTemplate(') - ->string($this->getAttribute('name')) - ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') - ->repr($this->getTemplateLine()) - ->raw(', ') - ->string($this->getAttribute('index')) - ->raw(')') - ; - } -} - -class_alias('Twig_Node_Embed', 'Twig\Node\EmbedNode', false); diff --git a/inc/lib/Twig/Node/Expression.php b/inc/lib/Twig/Node/Expression.php deleted file mode 100644 index a99c4e63..00000000 --- a/inc/lib/Twig/Node/Expression.php +++ /dev/null @@ -1,22 +0,0 @@ - - */ -abstract class Twig_Node_Expression extends Twig_Node -{ -} - -class_alias('Twig_Node_Expression', 'Twig\Node\Expression\AbstractExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Array.php b/inc/lib/Twig/Node/Expression/Array.php deleted file mode 100644 index 0e77bb08..00000000 --- a/inc/lib/Twig/Node/Expression/Array.php +++ /dev/null @@ -1,83 +0,0 @@ -index = -1; - foreach ($this->getKeyValuePairs() as $pair) { - if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) { - $this->index = $pair['key']->getAttribute('value'); - } - } - } - - public function getKeyValuePairs() - { - $pairs = array(); - - foreach (array_chunk($this->nodes, 2) as $pair) { - $pairs[] = array( - 'key' => $pair[0], - 'value' => $pair[1], - ); - } - - return $pairs; - } - - public function hasElement(Twig_Node_Expression $key) - { - foreach ($this->getKeyValuePairs() as $pair) { - // we compare the string representation of the keys - // to avoid comparing the line numbers which are not relevant here. - if ((string) $key === (string) $pair['key']) { - return true; - } - } - - return false; - } - - public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null) - { - if (null === $key) { - $key = new Twig_Node_Expression_Constant(++$this->index, $value->getTemplateLine()); - } - - array_push($this->nodes, $key, $value); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->raw('array('); - $first = true; - foreach ($this->getKeyValuePairs() as $pair) { - if (!$first) { - $compiler->raw(', '); - } - $first = false; - - $compiler - ->subcompile($pair['key']) - ->raw(' => ') - ->subcompile($pair['value']) - ; - } - $compiler->raw(')'); - } -} - -class_alias('Twig_Node_Expression_Array', 'Twig\Node\Expression\ArrayExpression', false); diff --git a/inc/lib/Twig/Node/Expression/AssignName.php b/inc/lib/Twig/Node/Expression/AssignName.php deleted file mode 100644 index 2e6b4c7c..00000000 --- a/inc/lib/Twig/Node/Expression/AssignName.php +++ /dev/null @@ -1,25 +0,0 @@ -raw('$context[') - ->string($this->getAttribute('name')) - ->raw(']') - ; - } -} - -class_alias('Twig_Node_Expression_AssignName', 'Twig\Node\Expression\AssignNameExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Binary.php b/inc/lib/Twig/Node/Expression/Binary.php deleted file mode 100644 index 2b545d98..00000000 --- a/inc/lib/Twig/Node/Expression/Binary.php +++ /dev/null @@ -1,37 +0,0 @@ - $left, 'right' => $right), array(), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('(') - ->subcompile($this->getNode('left')) - ->raw(' ') - ; - $this->operator($compiler); - $compiler - ->raw(' ') - ->subcompile($this->getNode('right')) - ->raw(')') - ; - } - - abstract public function operator(Twig_Compiler $compiler); -} - -class_alias('Twig_Node_Expression_Binary', 'Twig\Node\Expression\Binary\AbstractBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Add.php b/inc/lib/Twig/Node/Expression/Binary/Add.php deleted file mode 100644 index 5a09d836..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Add.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('+'); - } -} - -class_alias('Twig_Node_Expression_Binary_Add', 'Twig\Node\Expression\Binary\AddBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/And.php b/inc/lib/Twig/Node/Expression/Binary/And.php deleted file mode 100644 index 9ffddce6..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/And.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('&&'); - } -} - -class_alias('Twig_Node_Expression_Binary_And', 'Twig\Node\Expression\Binary\AndBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/BitwiseAnd.php b/inc/lib/Twig/Node/Expression/Binary/BitwiseAnd.php deleted file mode 100644 index e46e9ebf..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/BitwiseAnd.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('&'); - } -} - -class_alias('Twig_Node_Expression_Binary_BitwiseAnd', 'Twig\Node\Expression\Binary\BitwiseAndBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/BitwiseOr.php b/inc/lib/Twig/Node/Expression/Binary/BitwiseOr.php deleted file mode 100644 index 5d7f1b7c..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/BitwiseOr.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('|'); - } -} - -class_alias('Twig_Node_Expression_Binary_BitwiseOr', 'Twig\Node\Expression\Binary\BitwiseOrBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/BitwiseXor.php b/inc/lib/Twig/Node/Expression/Binary/BitwiseXor.php deleted file mode 100644 index 82edf516..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/BitwiseXor.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('^'); - } -} - -class_alias('Twig_Node_Expression_Binary_BitwiseXor', 'Twig\Node\Expression\Binary\BitwiseXorBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Concat.php b/inc/lib/Twig/Node/Expression/Binary/Concat.php deleted file mode 100644 index 91abca60..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Concat.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('.'); - } -} - -class_alias('Twig_Node_Expression_Binary_Concat', 'Twig\Node\Expression\Binary\ConcatBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Div.php b/inc/lib/Twig/Node/Expression/Binary/Div.php deleted file mode 100644 index 38ffa30c..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Div.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('/'); - } -} - -class_alias('Twig_Node_Expression_Binary_Div', 'Twig\Node\Expression\Binary\DivBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/EndsWith.php b/inc/lib/Twig/Node/Expression/Binary/EndsWith.php deleted file mode 100644 index 85c52937..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/EndsWith.php +++ /dev/null @@ -1,32 +0,0 @@ -getVarName(); - $right = $compiler->getVarName(); - $compiler - ->raw(sprintf('(is_string($%s = ', $left)) - ->subcompile($this->getNode('left')) - ->raw(sprintf(') && is_string($%s = ', $right)) - ->subcompile($this->getNode('right')) - ->raw(sprintf(') && (\'\' === $%2$s || $%2$s === substr($%1$s, -strlen($%2$s))))', $left, $right)) - ; - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw(''); - } -} - -class_alias('Twig_Node_Expression_Binary_EndsWith', 'Twig\Node\Expression\Binary\EndsWithBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Equal.php b/inc/lib/Twig/Node/Expression/Binary/Equal.php deleted file mode 100644 index a6a6946b..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Equal.php +++ /dev/null @@ -1,19 +0,0 @@ -raw('=='); - } -} - -class_alias('Twig_Node_Expression_Binary_Equal', 'Twig\Node\Expression\Binary\EqualBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/FloorDiv.php b/inc/lib/Twig/Node/Expression/Binary/FloorDiv.php deleted file mode 100644 index 7393bcb8..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/FloorDiv.php +++ /dev/null @@ -1,26 +0,0 @@ -raw('(int) floor('); - parent::compile($compiler); - $compiler->raw(')'); - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw('/'); - } -} - -class_alias('Twig_Node_Expression_Binary_FloorDiv', 'Twig\Node\Expression\Binary\FloorDivBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Greater.php b/inc/lib/Twig/Node/Expression/Binary/Greater.php deleted file mode 100644 index 832f9797..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Greater.php +++ /dev/null @@ -1,19 +0,0 @@ -raw('>'); - } -} - -class_alias('Twig_Node_Expression_Binary_Greater', 'Twig\Node\Expression\Binary\GreaterBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/GreaterEqual.php b/inc/lib/Twig/Node/Expression/Binary/GreaterEqual.php deleted file mode 100644 index c5f76245..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/GreaterEqual.php +++ /dev/null @@ -1,19 +0,0 @@ -raw('>='); - } -} - -class_alias('Twig_Node_Expression_Binary_GreaterEqual', 'Twig\Node\Expression\Binary\GreaterEqualBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/In.php b/inc/lib/Twig/Node/Expression/Binary/In.php deleted file mode 100644 index af112448..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/In.php +++ /dev/null @@ -1,30 +0,0 @@ -raw('twig_in_filter(') - ->subcompile($this->getNode('left')) - ->raw(', ') - ->subcompile($this->getNode('right')) - ->raw(')') - ; - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw('in'); - } -} - -class_alias('Twig_Node_Expression_Binary_In', 'Twig\Node\Expression\Binary\InBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Less.php b/inc/lib/Twig/Node/Expression/Binary/Less.php deleted file mode 100644 index ab8fc1f9..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Less.php +++ /dev/null @@ -1,19 +0,0 @@ -raw('<'); - } -} - -class_alias('Twig_Node_Expression_Binary_Less', 'Twig\Node\Expression\Binary\LessBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/LessEqual.php b/inc/lib/Twig/Node/Expression/Binary/LessEqual.php deleted file mode 100644 index 71a279e9..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/LessEqual.php +++ /dev/null @@ -1,19 +0,0 @@ -raw('<='); - } -} - -class_alias('Twig_Node_Expression_Binary_LessEqual', 'Twig\Node\Expression\Binary\LessEqualBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Matches.php b/inc/lib/Twig/Node/Expression/Binary/Matches.php deleted file mode 100644 index 5cb85584..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Matches.php +++ /dev/null @@ -1,30 +0,0 @@ -raw('preg_match(') - ->subcompile($this->getNode('right')) - ->raw(', ') - ->subcompile($this->getNode('left')) - ->raw(')') - ; - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw(''); - } -} - -class_alias('Twig_Node_Expression_Binary_Matches', 'Twig\Node\Expression\Binary\MatchesBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Mod.php b/inc/lib/Twig/Node/Expression/Binary/Mod.php deleted file mode 100644 index 28109633..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Mod.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('%'); - } -} - -class_alias('Twig_Node_Expression_Binary_Mod', 'Twig\Node\Expression\Binary\ModBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Mul.php b/inc/lib/Twig/Node/Expression/Binary/Mul.php deleted file mode 100644 index 790c6a22..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Mul.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('*'); - } -} - -class_alias('Twig_Node_Expression_Binary_Mul', 'Twig\Node\Expression\Binary\MulBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/NotEqual.php b/inc/lib/Twig/Node/Expression/Binary/NotEqual.php deleted file mode 100644 index bb45c9ed..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/NotEqual.php +++ /dev/null @@ -1,19 +0,0 @@ -raw('!='); - } -} - -class_alias('Twig_Node_Expression_Binary_NotEqual', 'Twig\Node\Expression\Binary\NotEqualBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/NotIn.php b/inc/lib/Twig/Node/Expression/Binary/NotIn.php deleted file mode 100644 index 9dedf92f..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/NotIn.php +++ /dev/null @@ -1,30 +0,0 @@ -raw('!twig_in_filter(') - ->subcompile($this->getNode('left')) - ->raw(', ') - ->subcompile($this->getNode('right')) - ->raw(')') - ; - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw('not in'); - } -} - -class_alias('Twig_Node_Expression_Binary_NotIn', 'Twig\Node\Expression\Binary\NotInBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Or.php b/inc/lib/Twig/Node/Expression/Binary/Or.php deleted file mode 100644 index dc9eece1..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Or.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('||'); - } -} - -class_alias('Twig_Node_Expression_Binary_Or', 'Twig\Node\Expression\Binary\OrBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Power.php b/inc/lib/Twig/Node/Expression/Binary/Power.php deleted file mode 100644 index d24777bd..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Power.php +++ /dev/null @@ -1,34 +0,0 @@ -= 50600) { - return parent::compile($compiler); - } - - $compiler - ->raw('pow(') - ->subcompile($this->getNode('left')) - ->raw(', ') - ->subcompile($this->getNode('right')) - ->raw(')') - ; - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw('**'); - } -} - -class_alias('Twig_Node_Expression_Binary_Power', 'Twig\Node\Expression\Binary\PowerBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Range.php b/inc/lib/Twig/Node/Expression/Binary/Range.php deleted file mode 100644 index 187f6765..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Range.php +++ /dev/null @@ -1,30 +0,0 @@ -raw('range(') - ->subcompile($this->getNode('left')) - ->raw(', ') - ->subcompile($this->getNode('right')) - ->raw(')') - ; - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw('..'); - } -} - -class_alias('Twig_Node_Expression_Binary_Range', 'Twig\Node\Expression\Binary\RangeBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/StartsWith.php b/inc/lib/Twig/Node/Expression/Binary/StartsWith.php deleted file mode 100644 index 7e43b8de..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/StartsWith.php +++ /dev/null @@ -1,32 +0,0 @@ -getVarName(); - $right = $compiler->getVarName(); - $compiler - ->raw(sprintf('(is_string($%s = ', $left)) - ->subcompile($this->getNode('left')) - ->raw(sprintf(') && is_string($%s = ', $right)) - ->subcompile($this->getNode('right')) - ->raw(sprintf(') && (\'\' === $%2$s || 0 === strpos($%1$s, $%2$s)))', $left, $right)) - ; - } - - public function operator(Twig_Compiler $compiler) - { - return $compiler->raw(''); - } -} - -class_alias('Twig_Node_Expression_Binary_StartsWith', 'Twig\Node\Expression\Binary\StartsWithBinary', false); diff --git a/inc/lib/Twig/Node/Expression/Binary/Sub.php b/inc/lib/Twig/Node/Expression/Binary/Sub.php deleted file mode 100644 index cff8ed07..00000000 --- a/inc/lib/Twig/Node/Expression/Binary/Sub.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('-'); - } -} - -class_alias('Twig_Node_Expression_Binary_Sub', 'Twig\Node\Expression\Binary\SubBinary', false); diff --git a/inc/lib/Twig/Node/Expression/BlockReference.php b/inc/lib/Twig/Node/Expression/BlockReference.php deleted file mode 100644 index 37a3983d..00000000 --- a/inc/lib/Twig/Node/Expression/BlockReference.php +++ /dev/null @@ -1,93 +0,0 @@ - - */ -class Twig_Node_Expression_BlockReference extends Twig_Node_Expression -{ - /** - * @param Twig_Node|null $template - */ - public function __construct(Twig_NodeInterface $name, $template = null, $lineno, $tag = null) - { - if (is_bool($template)) { - @trigger_error(sprintf('The %s method "$asString" argument is deprecated since version 1.28 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); - - $template = null; - } - - $nodes = array('name' => $name); - if (null !== $template) { - $nodes['template'] = $template; - } - - parent::__construct($nodes, array('is_defined_test' => false, 'output' => false), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - if ($this->getAttribute('is_defined_test')) { - $this->compileTemplateCall($compiler, 'hasBlock'); - } else { - if ($this->getAttribute('output')) { - $compiler->addDebugInfo($this); - - $this - ->compileTemplateCall($compiler, 'displayBlock') - ->raw(";\n"); - } else { - $this->compileTemplateCall($compiler, 'renderBlock'); - } - } - } - - private function compileTemplateCall(Twig_Compiler $compiler, $method) - { - if (!$this->hasNode('template')) { - $compiler->write('$this'); - } else { - $compiler - ->write('$this->loadTemplate(') - ->subcompile($this->getNode('template')) - ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') - ->repr($this->getTemplateLine()) - ->raw(')') - ; - } - - $compiler->raw(sprintf('->%s', $method)); - $this->compileBlockArguments($compiler); - - return $compiler; - } - - private function compileBlockArguments(Twig_Compiler $compiler) - { - $compiler - ->raw('(') - ->subcompile($this->getNode('name')) - ->raw(', $context'); - - if (!$this->hasNode('template')) { - $compiler->raw(', $blocks'); - } - - return $compiler->raw(')'); - } -} - -class_alias('Twig_Node_Expression_BlockReference', 'Twig\Node\Expression\BlockReferenceExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Call.php b/inc/lib/Twig/Node/Expression/Call.php deleted file mode 100644 index d962b6a5..00000000 --- a/inc/lib/Twig/Node/Expression/Call.php +++ /dev/null @@ -1,291 +0,0 @@ -hasAttribute('callable') && $callable = $this->getAttribute('callable')) { - if (is_string($callable) && false === strpos($callable, '::')) { - $compiler->raw($callable); - } else { - list($r, $callable) = $this->reflectCallable($callable); - if ($r instanceof ReflectionMethod && is_string($callable[0])) { - if ($r->isStatic()) { - $compiler->raw(sprintf('%s::%s', $callable[0], $callable[1])); - } else { - $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1])); - } - } elseif ($r instanceof ReflectionMethod && $callable[0] instanceof Twig_ExtensionInterface) { - $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', get_class($callable[0]), $callable[1])); - } else { - $type = ucfirst($this->getAttribute('type')); - $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name'))); - $closingParenthesis = true; - } - } - } else { - $compiler->raw($this->getAttribute('thing')->compile()); - } - - $this->compileArguments($compiler); - - if ($closingParenthesis) { - $compiler->raw(')'); - } - } - - protected function compileArguments(Twig_Compiler $compiler) - { - $compiler->raw('('); - - $first = true; - - if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { - $compiler->raw('$this->env'); - $first = false; - } - - if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { - if (!$first) { - $compiler->raw(', '); - } - $compiler->raw('$context'); - $first = false; - } - - if ($this->hasAttribute('arguments')) { - foreach ($this->getAttribute('arguments') as $argument) { - if (!$first) { - $compiler->raw(', '); - } - $compiler->string($argument); - $first = false; - } - } - - if ($this->hasNode('node')) { - if (!$first) { - $compiler->raw(', '); - } - $compiler->subcompile($this->getNode('node')); - $first = false; - } - - if ($this->hasNode('arguments')) { - $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; - - $arguments = $this->getArguments($callable, $this->getNode('arguments')); - - foreach ($arguments as $node) { - if (!$first) { - $compiler->raw(', '); - } - $compiler->subcompile($node); - $first = false; - } - } - - $compiler->raw(')'); - } - - protected function getArguments($callable, $arguments) - { - $callType = $this->getAttribute('type'); - $callName = $this->getAttribute('name'); - - $parameters = array(); - $named = false; - foreach ($arguments as $name => $node) { - if (!is_int($name)) { - $named = true; - $name = $this->normalizeName($name); - } elseif ($named) { - throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName)); - } - - $parameters[$name] = $node; - } - - $isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic'); - if (!$named && !$isVariadic) { - return $parameters; - } - - if (!$callable) { - if ($named) { - $message = sprintf('Named arguments are not supported for %s "%s".', $callType, $callName); - } else { - $message = sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName); - } - - throw new LogicException($message); - } - - $callableParameters = $this->getCallableParameters($callable, $isVariadic); - $arguments = array(); - $names = array(); - $missingArguments = array(); - $optionalArguments = array(); - $pos = 0; - foreach ($callableParameters as $callableParameter) { - $names[] = $name = $this->normalizeName($callableParameter->name); - - if (array_key_exists($name, $parameters)) { - if (array_key_exists($pos, $parameters)) { - throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName)); - } - - if (count($missingArguments)) { - throw new Twig_Error_Syntax(sprintf( - 'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".', - $name, $callType, $callName, implode(', ', $names), count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments)) - ); - } - - $arguments = array_merge($arguments, $optionalArguments); - $arguments[] = $parameters[$name]; - unset($parameters[$name]); - $optionalArguments = array(); - } elseif (array_key_exists($pos, $parameters)) { - $arguments = array_merge($arguments, $optionalArguments); - $arguments[] = $parameters[$pos]; - unset($parameters[$pos]); - $optionalArguments = array(); - ++$pos; - } elseif ($callableParameter->isDefaultValueAvailable()) { - $optionalArguments[] = new Twig_Node_Expression_Constant($callableParameter->getDefaultValue(), -1); - } elseif ($callableParameter->isOptional()) { - if (empty($parameters)) { - break; - } else { - $missingArguments[] = $name; - } - } else { - throw new Twig_Error_Syntax(sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName)); - } - } - - if ($isVariadic) { - $arbitraryArguments = new Twig_Node_Expression_Array(array(), -1); - foreach ($parameters as $key => $value) { - if (is_int($key)) { - $arbitraryArguments->addElement($value); - } else { - $arbitraryArguments->addElement($value, new Twig_Node_Expression_Constant($key, -1)); - } - unset($parameters[$key]); - } - - if ($arbitraryArguments->count()) { - $arguments = array_merge($arguments, $optionalArguments); - $arguments[] = $arbitraryArguments; - } - } - - if (!empty($parameters)) { - $unknownParameter = null; - foreach ($parameters as $parameter) { - if ($parameter instanceof Twig_Node) { - $unknownParameter = $parameter; - break; - } - } - - throw new Twig_Error_Syntax(sprintf( - 'Unknown argument%s "%s" for %s "%s(%s)".', - count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names) - ), $unknownParameter ? $unknownParameter->getTemplateLine() : -1); - } - - return $arguments; - } - - protected function normalizeName($name) - { - return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name)); - } - - private function getCallableParameters($callable, $isVariadic) - { - list($r) = $this->reflectCallable($callable); - if (null === $r) { - return array(); - } - - $parameters = $r->getParameters(); - if ($this->hasNode('node')) { - array_shift($parameters); - } - if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { - array_shift($parameters); - } - if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { - array_shift($parameters); - } - if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) { - foreach ($this->getAttribute('arguments') as $argument) { - array_shift($parameters); - } - } - if ($isVariadic) { - $argument = end($parameters); - if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) { - array_pop($parameters); - } else { - $callableName = $r->name; - if ($r instanceof ReflectionMethod) { - $callableName = $r->getDeclaringClass()->name.'::'.$callableName; - } - - throw new LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = array()".', $callableName, $this->getAttribute('type'), $this->getAttribute('name'))); - } - } - - return $parameters; - } - - private function reflectCallable($callable) - { - if (null !== $this->reflector) { - return $this->reflector; - } - - if (is_array($callable)) { - if (!method_exists($callable[0], $callable[1])) { - // __call() - return array(null, array()); - } - $r = new ReflectionMethod($callable[0], $callable[1]); - } elseif (is_object($callable) && !$callable instanceof Closure) { - $r = new ReflectionObject($callable); - $r = $r->getMethod('__invoke'); - $callable = array($callable, '__invoke'); - } elseif (is_string($callable) && false !== $pos = strpos($callable, '::')) { - $class = substr($callable, 0, $pos); - $method = substr($callable, $pos + 2); - if (!method_exists($class, $method)) { - // __staticCall() - return array(null, array()); - } - $r = new ReflectionMethod($callable); - $callable = array($class, $method); - } else { - $r = new ReflectionFunction($callable); - } - - return $this->reflector = array($r, $callable); - } -} - -class_alias('Twig_Node_Expression_Call', 'Twig\Node\Expression\CallExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Conditional.php b/inc/lib/Twig/Node/Expression/Conditional.php deleted file mode 100644 index c339d773..00000000 --- a/inc/lib/Twig/Node/Expression/Conditional.php +++ /dev/null @@ -1,33 +0,0 @@ - $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('((') - ->subcompile($this->getNode('expr1')) - ->raw(') ? (') - ->subcompile($this->getNode('expr2')) - ->raw(') : (') - ->subcompile($this->getNode('expr3')) - ->raw('))') - ; - } -} - -class_alias('Twig_Node_Expression_Conditional', 'Twig\Node\Expression\ConditionalExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Constant.php b/inc/lib/Twig/Node/Expression/Constant.php deleted file mode 100644 index bf4d031c..00000000 --- a/inc/lib/Twig/Node/Expression/Constant.php +++ /dev/null @@ -1,25 +0,0 @@ - $value), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->repr($this->getAttribute('value')); - } -} - -class_alias('Twig_Node_Expression_Constant', 'Twig\Node\Expression\ConstantExpression', false); diff --git a/inc/lib/Twig/Node/Expression/ExtensionReference.php b/inc/lib/Twig/Node/Expression/ExtensionReference.php deleted file mode 100644 index 114b5cd9..00000000 --- a/inc/lib/Twig/Node/Expression/ExtensionReference.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * @deprecated since 1.23 and will be removed in 2.0. - */ -class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression -{ - public function __construct($name, $lineno, $tag = null) - { - parent::__construct(array(), array('name' => $name), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); - } -} diff --git a/inc/lib/Twig/Node/Expression/Filter.php b/inc/lib/Twig/Node/Expression/Filter.php deleted file mode 100644 index 12da1d67..00000000 --- a/inc/lib/Twig/Node/Expression/Filter.php +++ /dev/null @@ -1,41 +0,0 @@ - $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $name = $this->getNode('filter')->getAttribute('value'); - $filter = $compiler->getEnvironment()->getFilter($name); - - $this->setAttribute('name', $name); - $this->setAttribute('type', 'filter'); - $this->setAttribute('thing', $filter); - $this->setAttribute('needs_environment', $filter->needsEnvironment()); - $this->setAttribute('needs_context', $filter->needsContext()); - $this->setAttribute('arguments', $filter->getArguments()); - if ($filter instanceof Twig_FilterCallableInterface || $filter instanceof Twig_SimpleFilter) { - $this->setAttribute('callable', $filter->getCallable()); - } - if ($filter instanceof Twig_SimpleFilter) { - $this->setAttribute('is_variadic', $filter->isVariadic()); - } - - $this->compileCallable($compiler); - } -} - -class_alias('Twig_Node_Expression_Filter', 'Twig\Node\Expression\FilterExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Filter/Default.php b/inc/lib/Twig/Node/Expression/Filter/Default.php deleted file mode 100644 index d2e19d54..00000000 --- a/inc/lib/Twig/Node/Expression/Filter/Default.php +++ /dev/null @@ -1,45 +0,0 @@ - - * {{ var.foo|default('foo item on var is not defined') }} - * - * - * @author Fabien Potencier - */ -class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter -{ - public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) - { - $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getTemplateLine()), $arguments, $node->getTemplateLine()); - - if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { - $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getTemplateLine()); - $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getTemplateLine()); - - $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getTemplateLine()); - } else { - $node = $default; - } - - parent::__construct($node, $filterName, $arguments, $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->subcompile($this->getNode('node')); - } -} - -class_alias('Twig_Node_Expression_Filter_Default', 'Twig\Node\Expression\Filter\DefaultFilter', false); diff --git a/inc/lib/Twig/Node/Expression/Function.php b/inc/lib/Twig/Node/Expression/Function.php deleted file mode 100644 index cdee7c97..00000000 --- a/inc/lib/Twig/Node/Expression/Function.php +++ /dev/null @@ -1,45 +0,0 @@ - $arguments), array('name' => $name, 'is_defined_test' => false), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $name = $this->getAttribute('name'); - $function = $compiler->getEnvironment()->getFunction($name); - - $this->setAttribute('name', $name); - $this->setAttribute('type', 'function'); - $this->setAttribute('thing', $function); - $this->setAttribute('needs_environment', $function->needsEnvironment()); - $this->setAttribute('needs_context', $function->needsContext()); - $this->setAttribute('arguments', $function->getArguments()); - if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) { - $callable = $function->getCallable(); - if ('constant' === $name && $this->getAttribute('is_defined_test')) { - $callable = 'twig_constant_is_defined'; - } - - $this->setAttribute('callable', $callable); - } - if ($function instanceof Twig_SimpleFunction) { - $this->setAttribute('is_variadic', $function->isVariadic()); - } - - $this->compileCallable($compiler); - } -} - -class_alias('Twig_Node_Expression_Function', 'Twig\Node\Expression\FunctionExpression', false); diff --git a/inc/lib/Twig/Node/Expression/GetAttr.php b/inc/lib/Twig/Node/Expression/GetAttr.php deleted file mode 100644 index b7823acc..00000000 --- a/inc/lib/Twig/Node/Expression/GetAttr.php +++ /dev/null @@ -1,74 +0,0 @@ - $node, 'attribute' => $attribute); - if (null !== $arguments) { - $nodes['arguments'] = $arguments; - } - - parent::__construct($nodes, array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - if ($this->getAttribute('disable_c_ext')) { - @trigger_error(sprintf('Using the "disable_c_ext" attribute on %s is deprecated since version 1.30 and will be removed in 2.0.', __CLASS__), E_USER_DEPRECATED); - } - - if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) { - $compiler->raw('twig_template_get_attributes($this, '); - } else { - $compiler->raw('$this->getAttribute('); - } - - if ($this->getAttribute('ignore_strict_check')) { - $this->getNode('node')->setAttribute('ignore_strict_check', true); - } - - $compiler->subcompile($this->getNode('node')); - - $compiler->raw(', ')->subcompile($this->getNode('attribute')); - - // only generate optional arguments when needed (to make generated code more readable) - $needFourth = $this->getAttribute('ignore_strict_check'); - $needThird = $needFourth || $this->getAttribute('is_defined_test'); - $needSecond = $needThird || Twig_Template::ANY_CALL !== $this->getAttribute('type'); - $needFirst = $needSecond || $this->hasNode('arguments'); - - if ($needFirst) { - if ($this->hasNode('arguments')) { - $compiler->raw(', ')->subcompile($this->getNode('arguments')); - } else { - $compiler->raw(', array()'); - } - } - - if ($needSecond) { - $compiler->raw(', ')->repr($this->getAttribute('type')); - } - - if ($needThird) { - $compiler->raw(', ')->repr($this->getAttribute('is_defined_test')); - } - - if ($needFourth) { - $compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check')); - } - - $compiler->raw(')'); - } -} - -class_alias('Twig_Node_Expression_GetAttr', 'Twig\Node\Expression\GetAttrExpression', false); diff --git a/inc/lib/Twig/Node/Expression/MacroCall.php b/inc/lib/Twig/Node/Expression/MacroCall.php deleted file mode 100644 index 3e6b8c12..00000000 --- a/inc/lib/Twig/Node/Expression/MacroCall.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ -class Twig_Node_Expression_MacroCall extends Twig_Node_Expression -{ - public function __construct(Twig_Node_Expression $template, $name, Twig_Node_Expression_Array $arguments, $lineno) - { - parent::__construct(array('template' => $template, 'arguments' => $arguments), array('name' => $name), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $namedNames = array(); - $namedCount = 0; - $positionalCount = 0; - foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { - $name = $pair['key']->getAttribute('value'); - if (!is_int($name)) { - $namedCount++; - $namedNames[$name] = 1; - } elseif ($namedCount > 0) { - throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for macro "%s".', $this->getAttribute('name')), $this->lineno); - } else { - $positionalCount++; - } - } - - $compiler - ->raw('$this->callMacro(') - ->subcompile($this->getNode('template')) - ->raw(', ')->repr($this->getAttribute('name')) - ->raw(', ')->subcompile($this->getNode('arguments')) - ; - - if ($namedCount > 0) { - $compiler - ->raw(', ')->repr($namedNames) - ->raw(', ')->repr($namedCount) - ->raw(', ')->repr($positionalCount) - ; - } - - $compiler - ->raw(')') - ; - } -} diff --git a/inc/lib/Twig/Node/Expression/MethodCall.php b/inc/lib/Twig/Node/Expression/MethodCall.php deleted file mode 100644 index 709016eb..00000000 --- a/inc/lib/Twig/Node/Expression/MethodCall.php +++ /dev/null @@ -1,43 +0,0 @@ - $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno); - - if ($node instanceof Twig_Node_Expression_Name) { - $node->setAttribute('always_defined', true); - } - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->subcompile($this->getNode('node')) - ->raw('->') - ->raw($this->getAttribute('method')) - ->raw('(') - ; - $first = true; - foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { - if (!$first) { - $compiler->raw(', '); - } - $first = false; - - $compiler->subcompile($pair['value']); - } - $compiler->raw(')'); - } -} - -class_alias('Twig_Node_Expression_MethodCall', 'Twig\Node\Expression\MethodCallExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Name.php b/inc/lib/Twig/Node/Expression/Name.php deleted file mode 100644 index 9d5a21f8..00000000 --- a/inc/lib/Twig/Node/Expression/Name.php +++ /dev/null @@ -1,102 +0,0 @@ - '$this', - '_context' => '$context', - '_charset' => '$this->env->getCharset()', - ); - - public function __construct($name, $lineno) - { - parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $name = $this->getAttribute('name'); - - $compiler->addDebugInfo($this); - - if ($this->getAttribute('is_defined_test')) { - if ($this->isSpecial()) { - $compiler->repr(true); - } else { - $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)'); - } - } elseif ($this->isSpecial()) { - $compiler->raw($this->specialVars[$name]); - } elseif ($this->getAttribute('always_defined')) { - $compiler - ->raw('$context[') - ->string($name) - ->raw(']') - ; - } else { - if (PHP_VERSION_ID >= 70000) { - // use PHP 7 null coalescing operator - $compiler - ->raw('($context[') - ->string($name) - ->raw('] ?? ') - ; - - if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { - $compiler->raw('null)'); - } else { - $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); - } - } elseif (PHP_VERSION_ID >= 50400) { - // PHP 5.4 ternary operator performance was optimized - $compiler - ->raw('(isset($context[') - ->string($name) - ->raw(']) ? $context[') - ->string($name) - ->raw('] : ') - ; - - if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { - $compiler->raw('null)'); - } else { - $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); - } - } else { - $compiler - ->raw('$this->getContext($context, ') - ->string($name) - ; - - if ($this->getAttribute('ignore_strict_check')) { - $compiler->raw(', true'); - } - - $compiler - ->raw(')') - ; - } - } - } - - public function isSpecial() - { - return isset($this->specialVars[$this->getAttribute('name')]); - } - - public function isSimple() - { - return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); - } -} - -class_alias('Twig_Node_Expression_Name', 'Twig\Node\Expression\NameExpression', false); diff --git a/inc/lib/Twig/Node/Expression/NullCoalesce.php b/inc/lib/Twig/Node/Expression/NullCoalesce.php deleted file mode 100644 index eaafa4c9..00000000 --- a/inc/lib/Twig/Node/Expression/NullCoalesce.php +++ /dev/null @@ -1,48 +0,0 @@ -getTemplateLine()), - new Twig_Node_Expression_Unary_Not(new Twig_Node_Expression_Test_Null($left, 'null', new Twig_Node(), $left->getTemplateLine()), $left->getTemplateLine()), - $left->getTemplateLine() - ); - - parent::__construct($test, $left, $right, $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - /* - * This optimizes only one case. PHP 7 also supports more complex expressions - * that can return null. So, for instance, if log is defined, log("foo") ?? "..." works, - * but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced - * cases might be implemented as an optimizer node visitor, but has not been done - * as benefits are probably not worth the added complexity. - */ - if (PHP_VERSION_ID >= 70000 && $this->getNode('expr2') instanceof Twig_Node_Expression_Name) { - $this->getNode('expr2')->setAttribute('always_defined', true); - $compiler - ->raw('((') - ->subcompile($this->getNode('expr2')) - ->raw(') ?? (') - ->subcompile($this->getNode('expr3')) - ->raw('))') - ; - } else { - parent::compile($compiler); - } - } -} - -class_alias('Twig_Node_Expression_NullCoalesce', 'Twig\Node\Expression\NullCoalesceExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Parent.php b/inc/lib/Twig/Node/Expression/Parent.php deleted file mode 100644 index 78692db2..00000000 --- a/inc/lib/Twig/Node/Expression/Parent.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -class Twig_Node_Expression_Parent extends Twig_Node_Expression -{ - public function __construct($name, $lineno, $tag = null) - { - parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - if ($this->getAttribute('output')) { - $compiler - ->addDebugInfo($this) - ->write('$this->displayParentBlock(') - ->string($this->getAttribute('name')) - ->raw(", \$context, \$blocks);\n") - ; - } else { - $compiler - ->raw('$this->renderParentBlock(') - ->string($this->getAttribute('name')) - ->raw(', $context, $blocks)') - ; - } - } -} - -class_alias('Twig_Node_Expression_Parent', 'Twig\Node\Expression\ParentExpression', false); diff --git a/inc/lib/Twig/Node/Expression/TempName.php b/inc/lib/Twig/Node/Expression/TempName.php deleted file mode 100644 index 0a86e003..00000000 --- a/inc/lib/Twig/Node/Expression/TempName.php +++ /dev/null @@ -1,28 +0,0 @@ - $name), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('$_') - ->raw($this->getAttribute('name')) - ->raw('_') - ; - } -} - -class_alias('Twig_Node_Expression_TempName', 'Twig\Node\Expression\TempNameExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Test.php b/inc/lib/Twig/Node/Expression/Test.php deleted file mode 100644 index ad102ba6..00000000 --- a/inc/lib/Twig/Node/Expression/Test.php +++ /dev/null @@ -1,42 +0,0 @@ - $node); - if (null !== $arguments) { - $nodes['arguments'] = $arguments; - } - - parent::__construct($nodes, array('name' => $name), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $name = $this->getAttribute('name'); - $test = $compiler->getEnvironment()->getTest($name); - - $this->setAttribute('name', $name); - $this->setAttribute('type', 'test'); - $this->setAttribute('thing', $test); - if ($test instanceof Twig_TestCallableInterface || $test instanceof Twig_SimpleTest) { - $this->setAttribute('callable', $test->getCallable()); - } - if ($test instanceof Twig_SimpleTest) { - $this->setAttribute('is_variadic', $test->isVariadic()); - } - - $this->compileCallable($compiler); - } -} - -class_alias('Twig_Node_Expression_Test', 'Twig\Node\Expression\TestExpression', false); diff --git a/inc/lib/Twig/Node/Expression/Test/Constant.php b/inc/lib/Twig/Node/Expression/Test/Constant.php deleted file mode 100644 index a51a4ba1..00000000 --- a/inc/lib/Twig/Node/Expression/Test/Constant.php +++ /dev/null @@ -1,48 +0,0 @@ - - * {% if post.status is constant('Post::PUBLISHED') %} - * the status attribute is exactly the same as Post::PUBLISHED - * {% endif %} - * - * - * @author Fabien Potencier - */ -class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test -{ - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('(') - ->subcompile($this->getNode('node')) - ->raw(' === constant(') - ; - - if ($this->getNode('arguments')->hasNode(1)) { - $compiler - ->raw('get_class(') - ->subcompile($this->getNode('arguments')->getNode(1)) - ->raw(')."::".') - ; - } - - $compiler - ->subcompile($this->getNode('arguments')->getNode(0)) - ->raw('))') - ; - } -} - -class_alias('Twig_Node_Expression_Test_Constant', 'Twig\Node\Expression\Test\ConstantTest', false); diff --git a/inc/lib/Twig/Node/Expression/Test/Defined.php b/inc/lib/Twig/Node/Expression/Test/Defined.php deleted file mode 100644 index 2136c390..00000000 --- a/inc/lib/Twig/Node/Expression/Test/Defined.php +++ /dev/null @@ -1,61 +0,0 @@ - - * {# defined works with variable names and variable attributes #} - * {% if foo is defined %} - * {# ... #} - * {% endif %} - * - * - * @author Fabien Potencier - */ -class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test -{ - public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) - { - if ($node instanceof Twig_Node_Expression_Name) { - $node->setAttribute('is_defined_test', true); - } elseif ($node instanceof Twig_Node_Expression_GetAttr) { - $node->setAttribute('is_defined_test', true); - $this->changeIgnoreStrictCheck($node); - } elseif ($node instanceof Twig_Node_Expression_BlockReference) { - $node->setAttribute('is_defined_test', true); - } elseif ($node instanceof Twig_Node_Expression_Function && 'constant' === $node->getAttribute('name')) { - $node->setAttribute('is_defined_test', true); - } elseif ($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array) { - $node = new Twig_Node_Expression_Constant(true, $node->getTemplateLine()); - } else { - throw new Twig_Error_Syntax('The "defined" test only works with simple variables.', $this->getTemplateLine()); - } - - parent::__construct($node, $name, $arguments, $lineno); - } - - protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node) - { - $node->setAttribute('ignore_strict_check', true); - - if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) { - $this->changeIgnoreStrictCheck($node->getNode('node')); - } - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->subcompile($this->getNode('node')); - } -} - -class_alias('Twig_Node_Expression_Test_Defined', 'Twig\Node\Expression\Test\DefinedTest', false); diff --git a/inc/lib/Twig/Node/Expression/Test/Divisibleby.php b/inc/lib/Twig/Node/Expression/Test/Divisibleby.php deleted file mode 100644 index a5d71961..00000000 --- a/inc/lib/Twig/Node/Expression/Test/Divisibleby.php +++ /dev/null @@ -1,35 +0,0 @@ - - * {% if loop.index is divisible by(3) %} - * - * - * @author Fabien Potencier - */ -class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test -{ - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('(0 == ') - ->subcompile($this->getNode('node')) - ->raw(' % ') - ->subcompile($this->getNode('arguments')->getNode(0)) - ->raw(')') - ; - } -} - -class_alias('Twig_Node_Expression_Test_Divisibleby', 'Twig\Node\Expression\Test\DivisiblebyTest', false); diff --git a/inc/lib/Twig/Node/Expression/Test/Even.php b/inc/lib/Twig/Node/Expression/Test/Even.php deleted file mode 100644 index 7e198bea..00000000 --- a/inc/lib/Twig/Node/Expression/Test/Even.php +++ /dev/null @@ -1,34 +0,0 @@ - - * {{ var is even }} - * - * - * @author Fabien Potencier - */ -class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test -{ - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('(') - ->subcompile($this->getNode('node')) - ->raw(' % 2 == 0') - ->raw(')') - ; - } -} - -class_alias('Twig_Node_Expression_Test_Even', 'Twig\Node\Expression\Test\EvenTest', false); diff --git a/inc/lib/Twig/Node/Expression/Test/Null.php b/inc/lib/Twig/Node/Expression/Test/Null.php deleted file mode 100644 index 3746e4cb..00000000 --- a/inc/lib/Twig/Node/Expression/Test/Null.php +++ /dev/null @@ -1,33 +0,0 @@ - - * {{ var is none }} - * - * - * @author Fabien Potencier - */ -class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test -{ - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('(null === ') - ->subcompile($this->getNode('node')) - ->raw(')') - ; - } -} - -class_alias('Twig_Node_Expression_Test_Null', 'Twig\Node\Expression\Test\NullTest', false); diff --git a/inc/lib/Twig/Node/Expression/Test/Odd.php b/inc/lib/Twig/Node/Expression/Test/Odd.php deleted file mode 100644 index 0c6c099b..00000000 --- a/inc/lib/Twig/Node/Expression/Test/Odd.php +++ /dev/null @@ -1,34 +0,0 @@ - - * {{ var is odd }} - * - * - * @author Fabien Potencier - */ -class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test -{ - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('(') - ->subcompile($this->getNode('node')) - ->raw(' % 2 == 1') - ->raw(')') - ; - } -} - -class_alias('Twig_Node_Expression_Test_Odd', 'Twig\Node\Expression\Test\OddTest', false); diff --git a/inc/lib/Twig/Node/Expression/Test/Sameas.php b/inc/lib/Twig/Node/Expression/Test/Sameas.php deleted file mode 100644 index e95ff1f2..00000000 --- a/inc/lib/Twig/Node/Expression/Test/Sameas.php +++ /dev/null @@ -1,31 +0,0 @@ - - */ -class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test -{ - public function compile(Twig_Compiler $compiler) - { - $compiler - ->raw('(') - ->subcompile($this->getNode('node')) - ->raw(' === ') - ->subcompile($this->getNode('arguments')->getNode(0)) - ->raw(')') - ; - } -} - -class_alias('Twig_Node_Expression_Test_Sameas', 'Twig\Node\Expression\Test\SameasTest', false); diff --git a/inc/lib/Twig/Node/Expression/Unary.php b/inc/lib/Twig/Node/Expression/Unary.php deleted file mode 100644 index 5804485e..00000000 --- a/inc/lib/Twig/Node/Expression/Unary.php +++ /dev/null @@ -1,29 +0,0 @@ - $node), array(), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->raw(' '); - $this->operator($compiler); - $compiler->subcompile($this->getNode('node')); - } - - abstract public function operator(Twig_Compiler $compiler); -} - -class_alias('Twig_Node_Expression_Unary', 'Twig\Node\Expression\Unary\AbstractUnary', false); diff --git a/inc/lib/Twig/Node/Expression/Unary/Neg.php b/inc/lib/Twig/Node/Expression/Unary/Neg.php deleted file mode 100644 index 039d933d..00000000 --- a/inc/lib/Twig/Node/Expression/Unary/Neg.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('-'); - } -} - -class_alias('Twig_Node_Expression_Unary_Neg', 'Twig\Node\Expression\Unary\NegUnary', false); diff --git a/inc/lib/Twig/Node/Expression/Unary/Not.php b/inc/lib/Twig/Node/Expression/Unary/Not.php deleted file mode 100644 index a0860b18..00000000 --- a/inc/lib/Twig/Node/Expression/Unary/Not.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('!'); - } -} - -class_alias('Twig_Node_Expression_Unary_Not', 'Twig\Node\Expression\Unary\NotUnary', false); diff --git a/inc/lib/Twig/Node/Expression/Unary/Pos.php b/inc/lib/Twig/Node/Expression/Unary/Pos.php deleted file mode 100644 index eeff5452..00000000 --- a/inc/lib/Twig/Node/Expression/Unary/Pos.php +++ /dev/null @@ -1,20 +0,0 @@ -raw('+'); - } -} - -class_alias('Twig_Node_Expression_Unary_Pos', 'Twig\Node\Expression\Unary\PosUnary', false); diff --git a/inc/lib/Twig/Node/Flush.php b/inc/lib/Twig/Node/Flush.php deleted file mode 100644 index fcc461ac..00000000 --- a/inc/lib/Twig/Node/Flush.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -class Twig_Node_Flush extends Twig_Node -{ - public function __construct($lineno, $tag) - { - parent::__construct(array(), array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write("flush();\n") - ; - } -} - -class_alias('Twig_Node_Flush', 'Twig\Node\FlushNode', false); diff --git a/inc/lib/Twig/Node/For.php b/inc/lib/Twig/Node/For.php deleted file mode 100644 index 914b70c9..00000000 --- a/inc/lib/Twig/Node/For.php +++ /dev/null @@ -1,113 +0,0 @@ - - */ -class Twig_Node_For extends Twig_Node -{ - protected $loop; - - public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null) - { - $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag))); - - if (null !== $ifexpr) { - $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag); - } - - $nodes = array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body); - if (null !== $else) { - $nodes['else'] = $else; - } - - parent::__construct($nodes, array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write("\$context['_parent'] = \$context;\n") - ->write("\$context['_seq'] = twig_ensure_traversable(") - ->subcompile($this->getNode('seq')) - ->raw(");\n") - ; - - if ($this->hasNode('else')) { - $compiler->write("\$context['_iterated'] = false;\n"); - } - - if ($this->getAttribute('with_loop')) { - $compiler - ->write("\$context['loop'] = array(\n") - ->write(" 'parent' => \$context['_parent'],\n") - ->write(" 'index0' => 0,\n") - ->write(" 'index' => 1,\n") - ->write(" 'first' => true,\n") - ->write(");\n") - ; - - if (!$this->getAttribute('ifexpr')) { - $compiler - ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n") - ->indent() - ->write("\$length = count(\$context['_seq']);\n") - ->write("\$context['loop']['revindex0'] = \$length - 1;\n") - ->write("\$context['loop']['revindex'] = \$length;\n") - ->write("\$context['loop']['length'] = \$length;\n") - ->write("\$context['loop']['last'] = 1 === \$length;\n") - ->outdent() - ->write("}\n") - ; - } - } - - $this->loop->setAttribute('else', $this->hasNode('else')); - $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop')); - $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr')); - - $compiler - ->write("foreach (\$context['_seq'] as ") - ->subcompile($this->getNode('key_target')) - ->raw(' => ') - ->subcompile($this->getNode('value_target')) - ->raw(") {\n") - ->indent() - ->subcompile($this->getNode('body')) - ->outdent() - ->write("}\n") - ; - - if ($this->hasNode('else')) { - $compiler - ->write("if (!\$context['_iterated']) {\n") - ->indent() - ->subcompile($this->getNode('else')) - ->outdent() - ->write("}\n") - ; - } - - $compiler->write("\$_parent = \$context['_parent'];\n"); - - // remove some "private" loop variables (needed for nested loops) - $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n"); - - // keep the values set in the inner context for variables defined in the outer context - $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n"); - } -} - -class_alias('Twig_Node_For', 'Twig\Node\ForNode', false); diff --git a/inc/lib/Twig/Node/ForLoop.php b/inc/lib/Twig/Node/ForLoop.php deleted file mode 100644 index 06477cf1..00000000 --- a/inc/lib/Twig/Node/ForLoop.php +++ /dev/null @@ -1,52 +0,0 @@ - - */ -class Twig_Node_ForLoop extends Twig_Node -{ - public function __construct($lineno, $tag = null) - { - parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - if ($this->getAttribute('else')) { - $compiler->write("\$context['_iterated'] = true;\n"); - } - - if ($this->getAttribute('with_loop')) { - $compiler - ->write("++\$context['loop']['index0'];\n") - ->write("++\$context['loop']['index'];\n") - ->write("\$context['loop']['first'] = false;\n") - ; - - if (!$this->getAttribute('ifexpr')) { - $compiler - ->write("if (isset(\$context['loop']['length'])) {\n") - ->indent() - ->write("--\$context['loop']['revindex0'];\n") - ->write("--\$context['loop']['revindex'];\n") - ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n") - ->outdent() - ->write("}\n") - ; - } - } - } -} - -class_alias('Twig_Node_ForLoop', 'Twig\Node\ForLoopNode', false); diff --git a/inc/lib/Twig/Node/If.php b/inc/lib/Twig/Node/If.php deleted file mode 100644 index d82edec7..00000000 --- a/inc/lib/Twig/Node/If.php +++ /dev/null @@ -1,68 +0,0 @@ - - */ -class Twig_Node_If extends Twig_Node -{ - public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null) - { - $nodes = array('tests' => $tests); - if (null !== $else) { - $nodes['else'] = $else; - } - - parent::__construct($nodes, array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) { - if ($i > 0) { - $compiler - ->outdent() - ->write('} elseif (') - ; - } else { - $compiler - ->write('if (') - ; - } - - $compiler - ->subcompile($this->getNode('tests')->getNode($i)) - ->raw(") {\n") - ->indent() - ->subcompile($this->getNode('tests')->getNode($i + 1)) - ; - } - - if ($this->hasNode('else')) { - $compiler - ->outdent() - ->write("} else {\n") - ->indent() - ->subcompile($this->getNode('else')) - ; - } - - $compiler - ->outdent() - ->write("}\n"); - } -} - -class_alias('Twig_Node_If', 'Twig\Node\IfNode', false); diff --git a/inc/lib/Twig/Node/Import.php b/inc/lib/Twig/Node/Import.php deleted file mode 100644 index c77e320b..00000000 --- a/inc/lib/Twig/Node/Import.php +++ /dev/null @@ -1,51 +0,0 @@ - - */ -class Twig_Node_Import extends Twig_Node -{ - public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null) - { - parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write('') - ->subcompile($this->getNode('var')) - ->raw(' = ') - ; - - if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) { - $compiler->raw('$this'); - } else { - $compiler - ->raw('$this->loadTemplate(') - ->subcompile($this->getNode('expr')) - ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') - ->repr($this->getTemplateLine()) - ->raw(')') - ; - } - - $compiler->raw(";\n"); - } -} - -class_alias('Twig_Node_Import', 'Twig\Node\ImportNode', false); diff --git a/inc/lib/Twig/Node/Include.php b/inc/lib/Twig/Node/Include.php deleted file mode 100644 index 2a5114cb..00000000 --- a/inc/lib/Twig/Node/Include.php +++ /dev/null @@ -1,90 +0,0 @@ - - */ -class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface -{ - public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) - { - $nodes = array('expr' => $expr); - if (null !== $variables) { - $nodes['variables'] = $variables; - } - - parent::__construct($nodes, array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - if ($this->getAttribute('ignore_missing')) { - $compiler - ->write("try {\n") - ->indent() - ; - } - - $this->addGetTemplate($compiler); - - $compiler->raw('->display('); - - $this->addTemplateArguments($compiler); - - $compiler->raw(");\n"); - - if ($this->getAttribute('ignore_missing')) { - $compiler - ->outdent() - ->write("} catch (Twig_Error_Loader \$e) {\n") - ->indent() - ->write("// ignore missing template\n") - ->outdent() - ->write("}\n\n") - ; - } - } - - protected function addGetTemplate(Twig_Compiler $compiler) - { - $compiler - ->write('$this->loadTemplate(') - ->subcompile($this->getNode('expr')) - ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') - ->repr($this->getTemplateLine()) - ->raw(')') - ; - } - - protected function addTemplateArguments(Twig_Compiler $compiler) - { - if (!$this->hasNode('variables')) { - $compiler->raw(false === $this->getAttribute('only') ? '$context' : 'array()'); - } elseif (false === $this->getAttribute('only')) { - $compiler - ->raw('array_merge($context, ') - ->subcompile($this->getNode('variables')) - ->raw(')') - ; - } else { - $compiler->subcompile($this->getNode('variables')); - } - } -} - -class_alias('Twig_Node_Include', 'Twig\Node\IncludeNode', false); diff --git a/inc/lib/Twig/Node/Macro.php b/inc/lib/Twig/Node/Macro.php deleted file mode 100644 index 3cf54977..00000000 --- a/inc/lib/Twig/Node/Macro.php +++ /dev/null @@ -1,125 +0,0 @@ - - */ -class Twig_Node_Macro extends Twig_Node -{ - const VARARGS_NAME = 'varargs'; - - public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null) - { - foreach ($arguments as $argumentName => $argument) { - if (self::VARARGS_NAME === $argumentName) { - throw new Twig_Error_Syntax(sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments.', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getTemplateLine()); - } - } - - parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write(sprintf('public function get%s(', $this->getAttribute('name'))) - ; - - $count = count($this->getNode('arguments')); - $pos = 0; - foreach ($this->getNode('arguments') as $name => $default) { - $compiler - ->raw('$__'.$name.'__ = ') - ->subcompile($default) - ; - - if (++$pos < $count) { - $compiler->raw(', '); - } - } - - if (PHP_VERSION_ID >= 50600) { - if ($count) { - $compiler->raw(', '); - } - - $compiler->raw('...$__varargs__'); - } - - $compiler - ->raw(")\n") - ->write("{\n") - ->indent() - ; - - $compiler - ->write("\$context = \$this->env->mergeGlobals(array(\n") - ->indent() - ; - - foreach ($this->getNode('arguments') as $name => $default) { - $compiler - ->write('') - ->string($name) - ->raw(' => $__'.$name.'__') - ->raw(",\n") - ; - } - - $compiler - ->write('') - ->string(self::VARARGS_NAME) - ->raw(' => ') - ; - - if (PHP_VERSION_ID >= 50600) { - $compiler->raw("\$__varargs__,\n"); - } else { - $compiler - ->raw('func_num_args() > ') - ->repr($count) - ->raw(' ? array_slice(func_get_args(), ') - ->repr($count) - ->raw(") : array(),\n") - ; - } - - $compiler - ->outdent() - ->write("));\n\n") - ->write("\$blocks = array();\n\n") - ->write("ob_start();\n") - ->write("try {\n") - ->indent() - ->subcompile($this->getNode('body')) - ->outdent() - ->write("} catch (Exception \$e) {\n") - ->indent() - ->write("ob_end_clean();\n\n") - ->write("throw \$e;\n") - ->outdent() - ->write("} catch (Throwable \$e) {\n") - ->indent() - ->write("ob_end_clean();\n\n") - ->write("throw \$e;\n") - ->outdent() - ->write("}\n\n") - ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset());\n") - ->outdent() - ->write("}\n\n") - ; - } -} - -class_alias('Twig_Node_Macro', 'Twig\Node\MacroNode', false); diff --git a/inc/lib/Twig/Node/Module.php b/inc/lib/Twig/Node/Module.php deleted file mode 100644 index 5cd8d050..00000000 --- a/inc/lib/Twig/Node/Module.php +++ /dev/null @@ -1,461 +0,0 @@ - - */ -class Twig_Node_Module extends Twig_Node -{ - private $source; - - public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $name, $source = '') - { - if (!$name instanceof Twig_Source) { - @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $this->source = new Twig_Source($source, $name); - } else { - $this->source = $name; - } - - $nodes = array( - 'body' => $body, - 'blocks' => $blocks, - 'macros' => $macros, - 'traits' => $traits, - 'display_start' => new Twig_Node(), - 'display_end' => new Twig_Node(), - 'constructor_start' => new Twig_Node(), - 'constructor_end' => new Twig_Node(), - 'class_end' => new Twig_Node(), - ); - if (null !== $parent) { - $nodes['parent'] = $parent; - } - - // embedded templates are set as attributes so that they are only visited once by the visitors - parent::__construct($nodes, array( - // source to be remove in 2.0 - 'source' => $this->source->getCode(), - // filename to be remove in 2.0 (use getTemplateName() instead) - 'filename' => $this->source->getName(), - 'index' => null, - 'embedded_templates' => $embeddedTemplates, - ), 1); - - // populate the template name of all node children - $this->setTemplateName($this->source->getName()); - } - - public function setIndex($index) - { - $this->setAttribute('index', $index); - } - - public function compile(Twig_Compiler $compiler) - { - $this->compileTemplate($compiler); - - foreach ($this->getAttribute('embedded_templates') as $template) { - $compiler->subcompile($template); - } - } - - protected function compileTemplate(Twig_Compiler $compiler) - { - if (!$this->getAttribute('index')) { - $compiler->write('compileClassHeader($compiler); - - if ( - count($this->getNode('blocks')) - || count($this->getNode('traits')) - || !$this->hasNode('parent') - || $this->getNode('parent') instanceof Twig_Node_Expression_Constant - || count($this->getNode('constructor_start')) - || count($this->getNode('constructor_end')) - ) { - $this->compileConstructor($compiler); - } - - $this->compileGetParent($compiler); - - $this->compileDisplay($compiler); - - $compiler->subcompile($this->getNode('blocks')); - - $this->compileMacros($compiler); - - $this->compileGetTemplateName($compiler); - - $this->compileIsTraitable($compiler); - - $this->compileDebugInfo($compiler); - - $this->compileGetSource($compiler); - - $this->compileGetSourceContext($compiler); - - $this->compileClassFooter($compiler); - } - - protected function compileGetParent(Twig_Compiler $compiler) - { - if (!$this->hasNode('parent')) { - return; - } - $parent = $this->getNode('parent'); - - $compiler - ->write("protected function doGetParent(array \$context)\n", "{\n") - ->indent() - ->addDebugInfo($parent) - ->write('return ') - ; - - if ($parent instanceof Twig_Node_Expression_Constant) { - $compiler->subcompile($parent); - } else { - $compiler - ->raw('$this->loadTemplate(') - ->subcompile($parent) - ->raw(', ') - ->repr($this->source->getName()) - ->raw(', ') - ->repr($parent->getTemplateLine()) - ->raw(')') - ; - } - - $compiler - ->raw(";\n") - ->outdent() - ->write("}\n\n") - ; - } - - protected function compileClassHeader(Twig_Compiler $compiler) - { - $compiler - ->write("\n\n") - // if the template name contains */, add a blank to avoid a PHP parse error - ->write('/* '.str_replace('*/', '* /', $this->source->getName())." */\n") - ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->source->getName(), $this->getAttribute('index'))) - ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) - ->write("{\n") - ->indent() - ; - } - - protected function compileConstructor(Twig_Compiler $compiler) - { - $compiler - ->write("public function __construct(Twig_Environment \$env)\n", "{\n") - ->indent() - ->subcompile($this->getNode('constructor_start')) - ->write("parent::__construct(\$env);\n\n") - ; - - // parent - if (!$this->hasNode('parent')) { - $compiler->write("\$this->parent = false;\n\n"); - } elseif (($parent = $this->getNode('parent')) && $parent instanceof Twig_Node_Expression_Constant) { - $compiler - ->addDebugInfo($parent) - ->write('$this->parent = $this->loadTemplate(') - ->subcompile($parent) - ->raw(', ') - ->repr($this->source->getName()) - ->raw(', ') - ->repr($parent->getTemplateLine()) - ->raw(");\n") - ; - } - - $countTraits = count($this->getNode('traits')); - if ($countTraits) { - // traits - foreach ($this->getNode('traits') as $i => $trait) { - $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i)); - - $compiler - ->addDebugInfo($trait->getNode('template')) - ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i)) - ->indent() - ->write("throw new Twig_Error_Runtime('Template \"'.") - ->subcompile($trait->getNode('template')) - ->raw(".'\" cannot be used as a trait.');\n") - ->outdent() - ->write("}\n") - ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i)) - ; - - foreach ($trait->getNode('targets') as $key => $value) { - $compiler - ->write(sprintf('if (!isset($_trait_%s_blocks[', $i)) - ->string($key) - ->raw("])) {\n") - ->indent() - ->write("throw new Twig_Error_Runtime(sprintf('Block ") - ->string($key) - ->raw(' is not defined in trait ') - ->subcompile($trait->getNode('template')) - ->raw(".'));\n") - ->outdent() - ->write("}\n\n") - - ->write(sprintf('$_trait_%s_blocks[', $i)) - ->subcompile($value) - ->raw(sprintf('] = $_trait_%s_blocks[', $i)) - ->string($key) - ->raw(sprintf(']; unset($_trait_%s_blocks[', $i)) - ->string($key) - ->raw("]);\n\n") - ; - } - } - - if ($countTraits > 1) { - $compiler - ->write("\$this->traits = array_merge(\n") - ->indent() - ; - - for ($i = 0; $i < $countTraits; ++$i) { - $compiler - ->write(sprintf('$_trait_%s_blocks'.($i == $countTraits - 1 ? '' : ',')."\n", $i)) - ; - } - - $compiler - ->outdent() - ->write(");\n\n") - ; - } else { - $compiler - ->write("\$this->traits = \$_trait_0_blocks;\n\n") - ; - } - - $compiler - ->write("\$this->blocks = array_merge(\n") - ->indent() - ->write("\$this->traits,\n") - ->write("array(\n") - ; - } else { - $compiler - ->write("\$this->blocks = array(\n") - ; - } - - // blocks - $compiler - ->indent() - ; - - foreach ($this->getNode('blocks') as $name => $node) { - $compiler - ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name)) - ; - } - - if ($countTraits) { - $compiler - ->outdent() - ->write(")\n") - ; - } - - $compiler - ->outdent() - ->write(");\n") - ->outdent() - ->subcompile($this->getNode('constructor_end')) - ->write("}\n\n") - ; - } - - protected function compileDisplay(Twig_Compiler $compiler) - { - $compiler - ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n") - ->indent() - ->subcompile($this->getNode('display_start')) - ->subcompile($this->getNode('body')) - ; - - if ($this->hasNode('parent')) { - $parent = $this->getNode('parent'); - $compiler->addDebugInfo($parent); - if ($parent instanceof Twig_Node_Expression_Constant) { - $compiler->write('$this->parent'); - } else { - $compiler->write('$this->getParent($context)'); - } - $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n"); - } - - $compiler - ->subcompile($this->getNode('display_end')) - ->outdent() - ->write("}\n\n") - ; - } - - protected function compileClassFooter(Twig_Compiler $compiler) - { - $compiler - ->subcompile($this->getNode('class_end')) - ->outdent() - ->write("}\n") - ; - } - - protected function compileMacros(Twig_Compiler $compiler) - { - $compiler->subcompile($this->getNode('macros')); - } - - protected function compileGetTemplateName(Twig_Compiler $compiler) - { - $compiler - ->write("public function getTemplateName()\n", "{\n") - ->indent() - ->write('return ') - ->repr($this->source->getName()) - ->raw(";\n") - ->outdent() - ->write("}\n\n") - ; - } - - protected function compileIsTraitable(Twig_Compiler $compiler) - { - // A template can be used as a trait if: - // * it has no parent - // * it has no macros - // * it has no body - // - // Put another way, a template can be used as a trait if it - // only contains blocks and use statements. - $traitable = !$this->hasNode('parent') && 0 === count($this->getNode('macros')); - if ($traitable) { - if ($this->getNode('body') instanceof Twig_Node_Body) { - $nodes = $this->getNode('body')->getNode(0); - } else { - $nodes = $this->getNode('body'); - } - - if (!count($nodes)) { - $nodes = new Twig_Node(array($nodes)); - } - - foreach ($nodes as $node) { - if (!count($node)) { - continue; - } - - if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) { - continue; - } - - if ($node instanceof Twig_Node_BlockReference) { - continue; - } - - $traitable = false; - break; - } - } - - if ($traitable) { - return; - } - - $compiler - ->write("public function isTraitable()\n", "{\n") - ->indent() - ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false')) - ->outdent() - ->write("}\n\n") - ; - } - - protected function compileDebugInfo(Twig_Compiler $compiler) - { - $compiler - ->write("public function getDebugInfo()\n", "{\n") - ->indent() - ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true)))) - ->outdent() - ->write("}\n\n") - ; - } - - protected function compileGetSource(Twig_Compiler $compiler) - { - $compiler - ->write("/** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */\n") - ->write("public function getSource()\n", "{\n") - ->indent() - ->write("@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);\n\n") - ->write('return $this->getSourceContext()->getCode();') - ->raw("\n") - ->outdent() - ->write("}\n\n") - ; - } - - protected function compileGetSourceContext(Twig_Compiler $compiler) - { - $compiler - ->write("public function getSourceContext()\n", "{\n") - ->indent() - ->write('return new Twig_Source(') - ->string($compiler->getEnvironment()->isDebug() ? $this->source->getCode() : '') - ->raw(', ') - ->string($this->source->getName()) - ->raw(', ') - ->string($this->source->getPath()) - ->raw(");\n") - ->outdent() - ->write("}\n") - ; - } - - protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var) - { - if ($node instanceof Twig_Node_Expression_Constant) { - $compiler - ->write(sprintf('%s = $this->loadTemplate(', $var)) - ->subcompile($node) - ->raw(', ') - ->repr($node->getTemplateName()) - ->raw(', ') - ->repr($node->getTemplateLine()) - ->raw(");\n") - ; - } else { - throw new LogicException('Trait templates can only be constant nodes.'); - } - } -} - -class_alias('Twig_Node_Module', 'Twig\Node\ModuleNode', false); diff --git a/inc/lib/Twig/Node/Print.php b/inc/lib/Twig/Node/Print.php deleted file mode 100644 index 374db89b..00000000 --- a/inc/lib/Twig/Node/Print.php +++ /dev/null @@ -1,36 +0,0 @@ - - */ -class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface -{ - public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) - { - parent::__construct(array('expr' => $expr), array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write('echo ') - ->subcompile($this->getNode('expr')) - ->raw(";\n") - ; - } -} - -class_alias('Twig_Node_Print', 'Twig\Node\PrintNode', false); diff --git a/inc/lib/Twig/Node/Sandbox.php b/inc/lib/Twig/Node/Sandbox.php deleted file mode 100644 index 44b30ab9..00000000 --- a/inc/lib/Twig/Node/Sandbox.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -class Twig_Node_Sandbox extends Twig_Node -{ - public function __construct(Twig_NodeInterface $body, $lineno, $tag = null) - { - parent::__construct(array('body' => $body), array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write("\$sandbox = \$this->env->getExtension('Twig_Extension_Sandbox');\n") - ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n") - ->indent() - ->write("\$sandbox->enableSandbox();\n") - ->outdent() - ->write("}\n") - ->subcompile($this->getNode('body')) - ->write("if (!\$alreadySandboxed) {\n") - ->indent() - ->write("\$sandbox->disableSandbox();\n") - ->outdent() - ->write("}\n") - ; - } -} - -class_alias('Twig_Node_Sandbox', 'Twig\Node\SandboxNode', false); diff --git a/inc/lib/Twig/Node/SandboxedModule.php b/inc/lib/Twig/Node/SandboxedModule.php deleted file mode 100644 index be1f5daa..00000000 --- a/inc/lib/Twig/Node/SandboxedModule.php +++ /dev/null @@ -1,60 +0,0 @@ - - */ -class Twig_Node_SandboxedModule extends Twig_Node_Module -{ - protected $usedFilters; - protected $usedTags; - protected $usedFunctions; - - public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions) - { - parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag()); - - $this->setAttribute('index', $node->getAttribute('index')); - - $this->usedFilters = $usedFilters; - $this->usedTags = $usedTags; - $this->usedFunctions = $usedFunctions; - } - - protected function compileDisplayBody(Twig_Compiler $compiler) - { - $compiler->write("\$this->checkSecurity();\n"); - - parent::compileDisplayBody($compiler); - } - - protected function compileDisplayFooter(Twig_Compiler $compiler) - { - parent::compileDisplayFooter($compiler); - - $compiler - ->write("protected function checkSecurity()\n", "{\n") - ->indent() - ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n") - ->indent() - ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n") - ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n") - ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n") - ->outdent() - ->write(");\n") - ->outdent() - ->write("}\n\n") - ; - } -} diff --git a/inc/lib/Twig/Node/SandboxedPrint.php b/inc/lib/Twig/Node/SandboxedPrint.php deleted file mode 100644 index a08f21f5..00000000 --- a/inc/lib/Twig/Node/SandboxedPrint.php +++ /dev/null @@ -1,51 +0,0 @@ - - */ -class Twig_Node_SandboxedPrint extends Twig_Node_Print -{ - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write('echo $this->env->getExtension(\'Twig_Extension_Sandbox\')->ensureToStringAllowed(') - ->subcompile($this->getNode('expr')) - ->raw(");\n") - ; - } - - /** - * Removes node filters. - * - * This is mostly needed when another visitor adds filters (like the escaper one). - * - * @return Twig_Node - */ - protected function removeNodeFilter(Twig_Node $node) - { - if ($node instanceof Twig_Node_Expression_Filter) { - return $this->removeNodeFilter($node->getNode('node')); - } - - return $node; - } -} - -class_alias('Twig_Node_SandboxedPrint', 'Twig\Node\SandboxedPrintNode', false); diff --git a/inc/lib/Twig/Node/Set.php b/inc/lib/Twig/Node/Set.php deleted file mode 100644 index 6c6743ee..00000000 --- a/inc/lib/Twig/Node/Set.php +++ /dev/null @@ -1,98 +0,0 @@ - - */ -class Twig_Node_Set extends Twig_Node implements Twig_NodeCaptureInterface -{ - public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null) - { - parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag); - - /* - * Optimizes the node when capture is used for a large block of text. - * - * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo"); - */ - if ($this->getAttribute('capture')) { - $this->setAttribute('safe', true); - - $values = $this->getNode('values'); - if ($values instanceof Twig_Node_Text) { - $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getTemplateLine())); - $this->setAttribute('capture', false); - } - } - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - if (count($this->getNode('names')) > 1) { - $compiler->write('list('); - foreach ($this->getNode('names') as $idx => $node) { - if ($idx) { - $compiler->raw(', '); - } - - $compiler->subcompile($node); - } - $compiler->raw(')'); - } else { - if ($this->getAttribute('capture')) { - $compiler - ->write("ob_start();\n") - ->subcompile($this->getNode('values')) - ; - } - - $compiler->subcompile($this->getNode('names'), false); - - if ($this->getAttribute('capture')) { - $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())"); - } - } - - if (!$this->getAttribute('capture')) { - $compiler->raw(' = '); - - if (count($this->getNode('names')) > 1) { - $compiler->write('array('); - foreach ($this->getNode('values') as $idx => $value) { - if ($idx) { - $compiler->raw(', '); - } - - $compiler->subcompile($value); - } - $compiler->raw(')'); - } else { - if ($this->getAttribute('safe')) { - $compiler - ->raw("('' === \$tmp = ") - ->subcompile($this->getNode('values')) - ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())") - ; - } else { - $compiler->subcompile($this->getNode('values')); - } - } - } - - $compiler->raw(";\n"); - } -} - -class_alias('Twig_Node_Set', 'Twig\Node\SetNode', false); diff --git a/inc/lib/Twig/Node/SetTemp.php b/inc/lib/Twig/Node/SetTemp.php deleted file mode 100644 index 996fdcde..00000000 --- a/inc/lib/Twig/Node/SetTemp.php +++ /dev/null @@ -1,40 +0,0 @@ - $name), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $name = $this->getAttribute('name'); - $compiler - ->addDebugInfo($this) - ->write('if (isset($context[') - ->string($name) - ->raw('])) { $_') - ->raw($name) - ->raw('_ = $context[') - ->repr($name) - ->raw(']; } else { $_') - ->raw($name) - ->raw("_ = null; }\n") - ; - } -} - -class_alias('Twig_Node_SetTemp', 'Twig\Node\SetTempNode', false); diff --git a/inc/lib/Twig/Node/Spaceless.php b/inc/lib/Twig/Node/Spaceless.php deleted file mode 100644 index 76f90cde..00000000 --- a/inc/lib/Twig/Node/Spaceless.php +++ /dev/null @@ -1,37 +0,0 @@ - - */ -class Twig_Node_Spaceless extends Twig_Node -{ - public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless') - { - parent::__construct(array('body' => $body), array(), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write("ob_start();\n") - ->subcompile($this->getNode('body')) - ->write("echo trim(preg_replace('/>\s+<', ob_get_clean()));\n") - ; - } -} - -class_alias('Twig_Node_Spaceless', 'Twig\Node\SpacelessNode', false); diff --git a/inc/lib/Twig/Node/Text.php b/inc/lib/Twig/Node/Text.php deleted file mode 100644 index f4577fee..00000000 --- a/inc/lib/Twig/Node/Text.php +++ /dev/null @@ -1,36 +0,0 @@ - - */ -class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface -{ - public function __construct($data, $lineno) - { - parent::__construct(array(), array('data' => $data), $lineno); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->addDebugInfo($this) - ->write('echo ') - ->string($this->getAttribute('data')) - ->raw(";\n") - ; - } -} - -class_alias('Twig_Node_Text', 'Twig\Node\TextNode', false); diff --git a/inc/lib/Twig/Node/With.php b/inc/lib/Twig/Node/With.php deleted file mode 100644 index 2ab0ea5d..00000000 --- a/inc/lib/Twig/Node/With.php +++ /dev/null @@ -1,64 +0,0 @@ - - */ -class Twig_Node_With extends Twig_Node -{ - public function __construct(Twig_Node $body, Twig_Node $variables = null, $only = false, $lineno, $tag = null) - { - $nodes = array('body' => $body); - if (null !== $variables) { - $nodes['variables'] = $variables; - } - - parent::__construct($nodes, array('only' => (bool) $only), $lineno, $tag); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler->addDebugInfo($this); - - if ($this->hasNode('variables')) { - $varsName = $compiler->getVarName(); - $compiler - ->write(sprintf('$%s = ', $varsName)) - ->subcompile($this->getNode('variables')) - ->raw(";\n") - ->write(sprintf("if (!is_array(\$%s)) {\n", $varsName)) - ->indent() - ->write("throw new Twig_Error_Runtime('Variables passed to the \"with\" tag must be a hash.');\n") - ->outdent() - ->write("}\n") - ; - - if ($this->getAttribute('only')) { - $compiler->write("\$context = array('_parent' => \$context);\n"); - } else { - $compiler->write("\$context['_parent'] = \$context;\n"); - } - - $compiler->write(sprintf("\$context = array_merge(\$context, \$%s);\n", $varsName)); - } else { - $compiler->write("\$context['_parent'] = \$context;\n"); - } - - $compiler - ->subcompile($this->getNode('body')) - ->write("\$context = \$context['_parent'];\n") - ; - } -} - -class_alias('Twig_Node_With', 'Twig\Node\WithNode', false); diff --git a/inc/lib/Twig/NodeCaptureInterface.php b/inc/lib/Twig/NodeCaptureInterface.php deleted file mode 100644 index 6638834b..00000000 --- a/inc/lib/Twig/NodeCaptureInterface.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -interface Twig_NodeCaptureInterface -{ -} - -class_alias('Twig_NodeCaptureInterface', 'Twig\Node\NodeCaptureInterface', false); diff --git a/inc/lib/Twig/NodeInterface.php b/inc/lib/Twig/NodeInterface.php deleted file mode 100644 index 78e758bd..00000000 --- a/inc/lib/Twig/NodeInterface.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_NodeInterface extends Countable, IteratorAggregate -{ - /** - * Compiles the node to PHP. - */ - public function compile(Twig_Compiler $compiler); - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getLine(); - - public function getNodeTag(); -} diff --git a/inc/lib/Twig/NodeOutputInterface.php b/inc/lib/Twig/NodeOutputInterface.php deleted file mode 100644 index 5a8eaa9c..00000000 --- a/inc/lib/Twig/NodeOutputInterface.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -interface Twig_NodeOutputInterface -{ -} - -class_alias('Twig_NodeOutputInterface', 'Twig\Node\NodeOutputInterface', false); diff --git a/inc/lib/Twig/NodeTraverser.php b/inc/lib/Twig/NodeTraverser.php deleted file mode 100644 index f00a0bf5..00000000 --- a/inc/lib/Twig/NodeTraverser.php +++ /dev/null @@ -1,86 +0,0 @@ - - */ -class Twig_NodeTraverser -{ - protected $env; - protected $visitors = array(); - - /** - * @param Twig_Environment $env - * @param Twig_NodeVisitorInterface[] $visitors - */ - public function __construct(Twig_Environment $env, array $visitors = array()) - { - $this->env = $env; - foreach ($visitors as $visitor) { - $this->addVisitor($visitor); - } - } - - public function addVisitor(Twig_NodeVisitorInterface $visitor) - { - if (!isset($this->visitors[$visitor->getPriority()])) { - $this->visitors[$visitor->getPriority()] = array(); - } - - $this->visitors[$visitor->getPriority()][] = $visitor; - } - - /** - * Traverses a node and calls the registered visitors. - * - * @return Twig_NodeInterface - */ - public function traverse(Twig_NodeInterface $node) - { - ksort($this->visitors); - foreach ($this->visitors as $visitors) { - foreach ($visitors as $visitor) { - $node = $this->traverseForVisitor($visitor, $node); - } - } - - return $node; - } - - protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null) - { - if (null === $node) { - return; - } - - $node = $visitor->enterNode($node, $this->env); - - foreach ($node as $k => $n) { - if (false !== $m = $this->traverseForVisitor($visitor, $n)) { - if ($m !== $n) { - $node->setNode($k, $m); - } - } else { - $node->removeNode($k); - } - } - - return $visitor->leaveNode($node, $this->env); - } -} - -class_alias('Twig_NodeTraverser', 'Twig\NodeTraverser', false); diff --git a/inc/lib/Twig/NodeVisitor/Escaper.php b/inc/lib/Twig/NodeVisitor/Escaper.php deleted file mode 100644 index 1a1ae66f..00000000 --- a/inc/lib/Twig/NodeVisitor/Escaper.php +++ /dev/null @@ -1,154 +0,0 @@ - - */ -class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor -{ - protected $statusStack = array(); - protected $blocks = array(); - protected $safeAnalysis; - protected $traverser; - protected $defaultStrategy = false; - protected $safeVars = array(); - - public function __construct() - { - $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis(); - } - - protected function doEnterNode(Twig_Node $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_Module) { - if ($env->hasExtension('Twig_Extension_Escaper') && $defaultStrategy = $env->getExtension('Twig_Extension_Escaper')->getDefaultStrategy($node->getTemplateName())) { - $this->defaultStrategy = $defaultStrategy; - } - $this->safeVars = array(); - $this->blocks = array(); - } elseif ($node instanceof Twig_Node_AutoEscape) { - $this->statusStack[] = $node->getAttribute('value'); - } elseif ($node instanceof Twig_Node_Block) { - $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env); - } elseif ($node instanceof Twig_Node_Import) { - $this->safeVars[] = $node->getNode('var')->getAttribute('name'); - } - - return $node; - } - - protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_Module) { - $this->defaultStrategy = false; - $this->safeVars = array(); - $this->blocks = array(); - } elseif ($node instanceof Twig_Node_Expression_Filter) { - return $this->preEscapeFilterNode($node, $env); - } elseif ($node instanceof Twig_Node_Print) { - return $this->escapePrintNode($node, $env, $this->needEscaping($env)); - } - - if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) { - array_pop($this->statusStack); - } elseif ($node instanceof Twig_Node_BlockReference) { - $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env); - } - - return $node; - } - - protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type) - { - if (false === $type) { - return $node; - } - - $expression = $node->getNode('expr'); - - if ($this->isSafeFor($type, $expression, $env)) { - return $node; - } - - $class = get_class($node); - - return new $class( - $this->getEscaperFilter($type, $expression), - $node->getTemplateLine() - ); - } - - protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env) - { - $name = $filter->getNode('filter')->getAttribute('value'); - - $type = $env->getFilter($name)->getPreEscape(); - if (null === $type) { - return $filter; - } - - $node = $filter->getNode('node'); - if ($this->isSafeFor($type, $node, $env)) { - return $filter; - } - - $filter->setNode('node', $this->getEscaperFilter($type, $node)); - - return $filter; - } - - protected function isSafeFor($type, Twig_NodeInterface $expression, $env) - { - $safe = $this->safeAnalysis->getSafe($expression); - - if (null === $safe) { - if (null === $this->traverser) { - $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis)); - } - - $this->safeAnalysis->setSafeVars($this->safeVars); - - $this->traverser->traverse($expression); - $safe = $this->safeAnalysis->getSafe($expression); - } - - return in_array($type, $safe) || in_array('all', $safe); - } - - protected function needEscaping(Twig_Environment $env) - { - if (count($this->statusStack)) { - return $this->statusStack[count($this->statusStack) - 1]; - } - - return $this->defaultStrategy ? $this->defaultStrategy : false; - } - - protected function getEscaperFilter($type, Twig_NodeInterface $node) - { - $line = $node->getTemplateLine(); - $name = new Twig_Node_Expression_Constant('escape', $line); - $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line))); - - return new Twig_Node_Expression_Filter($node, $name, $args, $line); - } - - public function getPriority() - { - return 0; - } -} - -class_alias('Twig_NodeVisitor_Escaper', 'Twig\NodeVisitor\EscaperNodeVisitor', false); diff --git a/inc/lib/Twig/NodeVisitor/Optimizer.php b/inc/lib/Twig/NodeVisitor/Optimizer.php deleted file mode 100644 index c55e40ff..00000000 --- a/inc/lib/Twig/NodeVisitor/Optimizer.php +++ /dev/null @@ -1,253 +0,0 @@ - - */ -class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor -{ - const OPTIMIZE_ALL = -1; - const OPTIMIZE_NONE = 0; - const OPTIMIZE_FOR = 2; - const OPTIMIZE_RAW_FILTER = 4; - const OPTIMIZE_VAR_ACCESS = 8; - - protected $loops = array(); - protected $loopsTargets = array(); - protected $optimizers; - protected $prependedNodes = array(); - protected $inABody = false; - - /** - * @param int $optimizers The optimizer mode - */ - public function __construct($optimizers = -1) - { - if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) { - throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); - } - - $this->optimizers = $optimizers; - } - - protected function doEnterNode(Twig_Node $node, Twig_Environment $env) - { - if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { - $this->enterOptimizeFor($node, $env); - } - - if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('Twig_Extension_Sandbox')) { - if ($this->inABody) { - if (!$node instanceof Twig_Node_Expression) { - if ('Twig_Node' !== get_class($node)) { - array_unshift($this->prependedNodes, array()); - } - } else { - $node = $this->optimizeVariables($node, $env); - } - } elseif ($node instanceof Twig_Node_Body) { - $this->inABody = true; - } - } - - return $node; - } - - protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) - { - $expression = $node instanceof Twig_Node_Expression; - - if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { - $this->leaveOptimizeFor($node, $env); - } - - if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) { - $node = $this->optimizeRawFilter($node, $env); - } - - $node = $this->optimizePrintNode($node, $env); - - if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('Twig_Extension_Sandbox')) { - if ($node instanceof Twig_Node_Body) { - $this->inABody = false; - } elseif ($this->inABody) { - if (!$expression && 'Twig_Node' !== get_class($node) && $prependedNodes = array_shift($this->prependedNodes)) { - $nodes = array(); - foreach (array_unique($prependedNodes) as $name) { - $nodes[] = new Twig_Node_SetTemp($name, $node->getTemplateLine()); - } - - $nodes[] = $node; - $node = new Twig_Node($nodes); - } - } - } - - return $node; - } - - protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env) - { - if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) { - $this->prependedNodes[0][] = $node->getAttribute('name'); - - return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getTemplateLine()); - } - - return $node; - } - - /** - * Optimizes print nodes. - * - * It replaces: - * - * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" - * - * @return Twig_NodeInterface - */ - protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env) - { - if (!$node instanceof Twig_Node_Print) { - return $node; - } - - $exprNode = $node->getNode('expr'); - if ( - $exprNode instanceof Twig_Node_Expression_BlockReference || - $exprNode instanceof Twig_Node_Expression_Parent - ) { - $exprNode->setAttribute('output', true); - - return $exprNode; - } - - return $node; - } - - /** - * Removes "raw" filters. - * - * @return Twig_NodeInterface - */ - protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) { - return $node->getNode('node'); - } - - return $node; - } - - /** - * Optimizes "for" tag by removing the "loop" variable creation whenever possible. - */ - protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_For) { - // disable the loop variable by default - $node->setAttribute('with_loop', false); - array_unshift($this->loops, $node); - array_unshift($this->loopsTargets, $node->getNode('value_target')->getAttribute('name')); - array_unshift($this->loopsTargets, $node->getNode('key_target')->getAttribute('name')); - } elseif (!$this->loops) { - // we are outside a loop - return; - } - - // when do we need to add the loop variable back? - - // the loop variable is referenced for the current loop - elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) { - $node->setAttribute('always_defined', true); - $this->addLoopToCurrent(); - } - - // optimize access to loop targets - elseif ($node instanceof Twig_Node_Expression_Name && in_array($node->getAttribute('name'), $this->loopsTargets)) { - $node->setAttribute('always_defined', true); - } - - // block reference - elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) { - $this->addLoopToCurrent(); - } - - // include without the only attribute - elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) { - $this->addLoopToAll(); - } - - // include function without the with_context=false parameter - elseif ($node instanceof Twig_Node_Expression_Function - && 'include' === $node->getAttribute('name') - && (!$node->getNode('arguments')->hasNode('with_context') - || false !== $node->getNode('arguments')->getNode('with_context')->getAttribute('value') - ) - ) { - $this->addLoopToAll(); - } - - // the loop variable is referenced via an attribute - elseif ($node instanceof Twig_Node_Expression_GetAttr - && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant - || 'parent' === $node->getNode('attribute')->getAttribute('value') - ) - && (true === $this->loops[0]->getAttribute('with_loop') - || ($node->getNode('node') instanceof Twig_Node_Expression_Name - && 'loop' === $node->getNode('node')->getAttribute('name') - ) - ) - ) { - $this->addLoopToAll(); - } - } - - /** - * Optimizes "for" tag by removing the "loop" variable creation whenever possible. - */ - protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_For) { - array_shift($this->loops); - array_shift($this->loopsTargets); - array_shift($this->loopsTargets); - } - } - - protected function addLoopToCurrent() - { - $this->loops[0]->setAttribute('with_loop', true); - } - - protected function addLoopToAll() - { - foreach ($this->loops as $loop) { - $loop->setAttribute('with_loop', true); - } - } - - public function getPriority() - { - return 255; - } -} - -class_alias('Twig_NodeVisitor_Optimizer', 'Twig\NodeVisitor\OptimizerNodeVisitor', false); diff --git a/inc/lib/Twig/NodeVisitor/SafeAnalysis.php b/inc/lib/Twig/NodeVisitor/SafeAnalysis.php deleted file mode 100644 index ca31c8fc..00000000 --- a/inc/lib/Twig/NodeVisitor/SafeAnalysis.php +++ /dev/null @@ -1,150 +0,0 @@ -safeVars = $safeVars; - } - - public function getSafe(Twig_NodeInterface $node) - { - $hash = spl_object_hash($node); - if (!isset($this->data[$hash])) { - return; - } - - foreach ($this->data[$hash] as $bucket) { - if ($bucket['key'] !== $node) { - continue; - } - - if (in_array('html_attr', $bucket['value'])) { - $bucket['value'][] = 'html'; - } - - return $bucket['value']; - } - } - - protected function setSafe(Twig_NodeInterface $node, array $safe) - { - $hash = spl_object_hash($node); - if (isset($this->data[$hash])) { - foreach ($this->data[$hash] as &$bucket) { - if ($bucket['key'] === $node) { - $bucket['value'] = $safe; - - return; - } - } - } - $this->data[$hash][] = array( - 'key' => $node, - 'value' => $safe, - ); - } - - protected function doEnterNode(Twig_Node $node, Twig_Environment $env) - { - return $node; - } - - protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_Expression_Constant) { - // constants are marked safe for all - $this->setSafe($node, array('all')); - } elseif ($node instanceof Twig_Node_Expression_BlockReference) { - // blocks are safe by definition - $this->setSafe($node, array('all')); - } elseif ($node instanceof Twig_Node_Expression_Parent) { - // parent block is safe by definition - $this->setSafe($node, array('all')); - } elseif ($node instanceof Twig_Node_Expression_Conditional) { - // intersect safeness of both operands - $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3'))); - $this->setSafe($node, $safe); - } elseif ($node instanceof Twig_Node_Expression_Filter) { - // filter expression is safe when the filter is safe - $name = $node->getNode('filter')->getAttribute('value'); - $args = $node->getNode('arguments'); - if (false !== $filter = $env->getFilter($name)) { - $safe = $filter->getSafe($args); - if (null === $safe) { - $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety()); - } - $this->setSafe($node, $safe); - } else { - $this->setSafe($node, array()); - } - } elseif ($node instanceof Twig_Node_Expression_Function) { - // function expression is safe when the function is safe - $name = $node->getAttribute('name'); - $args = $node->getNode('arguments'); - $function = $env->getFunction($name); - if (false !== $function) { - $this->setSafe($node, $function->getSafe($args)); - } else { - $this->setSafe($node, array()); - } - } elseif ($node instanceof Twig_Node_Expression_MethodCall) { - if ($node->getAttribute('safe')) { - $this->setSafe($node, array('all')); - } else { - $this->setSafe($node, array()); - } - } elseif ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name) { - $name = $node->getNode('node')->getAttribute('name'); - // attributes on template instances are safe - if ('_self' == $name || in_array($name, $this->safeVars)) { - $this->setSafe($node, array('all')); - } else { - $this->setSafe($node, array()); - } - } else { - $this->setSafe($node, array()); - } - - return $node; - } - - protected function intersectSafe(array $a = null, array $b = null) - { - if (null === $a || null === $b) { - return array(); - } - - if (in_array('all', $a)) { - return $b; - } - - if (in_array('all', $b)) { - return $a; - } - - return array_intersect($a, $b); - } - - public function getPriority() - { - return 0; - } -} - -class_alias('Twig_NodeVisitor_SafeAnalysis', 'Twig\NodeVisitor\SafeAnalysisNodeVisitor', false); diff --git a/inc/lib/Twig/NodeVisitor/Sandbox.php b/inc/lib/Twig/NodeVisitor/Sandbox.php deleted file mode 100644 index 71aa4f02..00000000 --- a/inc/lib/Twig/NodeVisitor/Sandbox.php +++ /dev/null @@ -1,82 +0,0 @@ - - */ -class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor -{ - protected $inAModule = false; - protected $tags; - protected $filters; - protected $functions; - - protected function doEnterNode(Twig_Node $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_Module) { - $this->inAModule = true; - $this->tags = array(); - $this->filters = array(); - $this->functions = array(); - - return $node; - } elseif ($this->inAModule) { - // look for tags - if ($node->getNodeTag() && !isset($this->tags[$node->getNodeTag()])) { - $this->tags[$node->getNodeTag()] = $node; - } - - // look for filters - if ($node instanceof Twig_Node_Expression_Filter && !isset($this->filters[$node->getNode('filter')->getAttribute('value')])) { - $this->filters[$node->getNode('filter')->getAttribute('value')] = $node; - } - - // look for functions - if ($node instanceof Twig_Node_Expression_Function && !isset($this->functions[$node->getAttribute('name')])) { - $this->functions[$node->getAttribute('name')] = $node; - } - - // the .. operator is equivalent to the range() function - if ($node instanceof Twig_Node_Expression_Binary_Range && !isset($this->functions['range'])) { - $this->functions['range'] = $node; - } - - // wrap print to check __toString() calls - if ($node instanceof Twig_Node_Print) { - return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getTemplateLine(), $node->getNodeTag()); - } - } - - return $node; - } - - protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_Module) { - $this->inAModule = false; - - $node->setNode('display_start', new Twig_Node(array(new Twig_Node_CheckSecurity($this->filters, $this->tags, $this->functions), $node->getNode('display_start')))); - } - - return $node; - } - - public function getPriority() - { - return 0; - } -} - -class_alias('Twig_NodeVisitor_Sandbox', 'Twig\NodeVisitor\SandboxNodeVisitor', false); diff --git a/inc/lib/Twig/NodeVisitorInterface.php b/inc/lib/Twig/NodeVisitorInterface.php deleted file mode 100644 index 1270a372..00000000 --- a/inc/lib/Twig/NodeVisitorInterface.php +++ /dev/null @@ -1,45 +0,0 @@ - - */ -interface Twig_NodeVisitorInterface -{ - /** - * Called before child nodes are visited. - * - * @return Twig_NodeInterface The modified node - */ - public function enterNode(Twig_NodeInterface $node, Twig_Environment $env); - - /** - * Called after child nodes are visited. - * - * @return Twig_NodeInterface|false The modified node or false if the node must be removed - */ - public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env); - - /** - * Returns the priority for this visitor. - * - * Priority should be between -10 and 10 (0 is the default). - * - * @return int The priority level - */ - public function getPriority(); -} - -class_alias('Twig_NodeVisitorInterface', 'Twig\NodeVisitor\NodeVisitorInterface', false); -class_exists('Twig_Environment'); -class_exists('Twig_Node'); diff --git a/inc/lib/Twig/Parser.php b/inc/lib/Twig/Parser.php deleted file mode 100644 index 6de879a5..00000000 --- a/inc/lib/Twig/Parser.php +++ /dev/null @@ -1,412 +0,0 @@ - - */ -class Twig_Parser implements Twig_ParserInterface -{ - protected $stack = array(); - protected $stream; - protected $parent; - protected $handlers; - protected $visitors; - protected $expressionParser; - protected $blocks; - protected $blockStack; - protected $macros; - protected $env; - protected $reservedMacroNames; - protected $importedSymbols; - protected $traits; - protected $embeddedTemplates = array(); - private $varNameSalt = 0; - - public function __construct(Twig_Environment $env) - { - $this->env = $env; - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getEnvironment() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - return $this->env; - } - - public function getVarName() - { - return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->stream->getSourceContext()->getCode().$this->varNameSalt++)); - } - - /** - * @deprecated since 1.27 (to be removed in 2.0). Use $parser->getStream()->getSourceContext()->getPath() instead. - */ - public function getFilename() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use $parser->getStream()->getSourceContext()->getPath() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->stream->getSourceContext()->getName(); - } - - public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false) - { - // push all variables into the stack to keep the current state of the parser - // using get_object_vars() instead of foreach would lead to https://bugs.php.net/71336 - // This hack can be removed when min version if PHP 7.0 - $vars = array(); - foreach ($this as $k => $v) { - $vars[$k] = $v; - } - - unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']); - $this->stack[] = $vars; - - // tag handlers - if (null === $this->handlers) { - $this->handlers = $this->env->getTokenParsers(); - $this->handlers->setParser($this); - } - - // node visitors - if (null === $this->visitors) { - $this->visitors = $this->env->getNodeVisitors(); - } - - if (null === $this->expressionParser) { - $this->expressionParser = new Twig_ExpressionParser($this, $this->env); - } - - $this->stream = $stream; - $this->parent = null; - $this->blocks = array(); - $this->macros = array(); - $this->traits = array(); - $this->blockStack = array(); - $this->importedSymbols = array(array()); - $this->embeddedTemplates = array(); - $this->varNameSalt = 0; - - try { - $body = $this->subparse($test, $dropNeedle); - - if (null !== $this->parent && null === $body = $this->filterBodyNodes($body)) { - $body = new Twig_Node(); - } - } catch (Twig_Error_Syntax $e) { - if (!$e->getSourceContext()) { - $e->setSourceContext($this->stream->getSourceContext()); - } - - if (!$e->getTemplateLine()) { - $e->setTemplateLine($this->stream->getCurrent()->getLine()); - } - - throw $e; - } - - $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $stream->getSourceContext()); - - $traverser = new Twig_NodeTraverser($this->env, $this->visitors); - - $node = $traverser->traverse($node); - - // restore previous stack so previous parse() call can resume working - foreach (array_pop($this->stack) as $key => $val) { - $this->$key = $val; - } - - return $node; - } - - public function subparse($test, $dropNeedle = false) - { - $lineno = $this->getCurrentToken()->getLine(); - $rv = array(); - while (!$this->stream->isEOF()) { - switch ($this->getCurrentToken()->getType()) { - case Twig_Token::TEXT_TYPE: - $token = $this->stream->next(); - $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine()); - break; - - case Twig_Token::VAR_START_TYPE: - $token = $this->stream->next(); - $expr = $this->expressionParser->parseExpression(); - $this->stream->expect(Twig_Token::VAR_END_TYPE); - $rv[] = new Twig_Node_Print($expr, $token->getLine()); - break; - - case Twig_Token::BLOCK_START_TYPE: - $this->stream->next(); - $token = $this->getCurrentToken(); - - if (Twig_Token::NAME_TYPE !== $token->getType()) { - throw new Twig_Error_Syntax('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext()); - } - - if (null !== $test && call_user_func($test, $token)) { - if ($dropNeedle) { - $this->stream->next(); - } - - if (1 === count($rv)) { - return $rv[0]; - } - - return new Twig_Node($rv, array(), $lineno); - } - - $subparser = $this->handlers->getTokenParser($token->getValue()); - if (null === $subparser) { - if (null !== $test) { - $e = new Twig_Error_Syntax(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()); - - if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) { - $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno)); - } - } else { - $e = new Twig_Error_Syntax(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()); - $e->addSuggestions($token->getValue(), array_keys($this->env->getTags())); - } - - throw $e; - } - - $this->stream->next(); - - $node = $subparser->parse($token); - if (null !== $node) { - $rv[] = $node; - } - break; - - default: - throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', $this->getCurrentToken()->getLine(), $this->stream->getSourceContext()); - } - } - - if (1 === count($rv)) { - return $rv[0]; - } - - return new Twig_Node($rv, array(), $lineno); - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function addHandler($name, $class) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - $this->handlers[$name] = $class; - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - $this->visitors[] = $visitor; - } - - public function getBlockStack() - { - return $this->blockStack; - } - - public function peekBlockStack() - { - return $this->blockStack[count($this->blockStack) - 1]; - } - - public function popBlockStack() - { - array_pop($this->blockStack); - } - - public function pushBlockStack($name) - { - $this->blockStack[] = $name; - } - - public function hasBlock($name) - { - return isset($this->blocks[$name]); - } - - public function getBlock($name) - { - return $this->blocks[$name]; - } - - public function setBlock($name, Twig_Node_Block $value) - { - $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getTemplateLine()); - } - - public function hasMacro($name) - { - return isset($this->macros[$name]); - } - - public function setMacro($name, Twig_Node_Macro $node) - { - if ($this->isReservedMacroName($name)) { - throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword.', $name), $node->getTemplateLine(), $this->stream->getSourceContext()); - } - - $this->macros[$name] = $node; - } - - public function isReservedMacroName($name) - { - if (null === $this->reservedMacroNames) { - $this->reservedMacroNames = array(); - $r = new ReflectionClass($this->env->getBaseTemplateClass()); - foreach ($r->getMethods() as $method) { - $methodName = strtolower($method->getName()); - - if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) { - $this->reservedMacroNames[] = substr($methodName, 3); - } - } - } - - return in_array(strtolower($name), $this->reservedMacroNames); - } - - public function addTrait($trait) - { - $this->traits[] = $trait; - } - - public function hasTraits() - { - return count($this->traits) > 0; - } - - public function embedTemplate(Twig_Node_Module $template) - { - $template->setIndex(mt_rand()); - - $this->embeddedTemplates[] = $template; - } - - public function addImportedSymbol($type, $alias, $name = null, Twig_Node_Expression $node = null) - { - $this->importedSymbols[0][$type][$alias] = array('name' => $name, 'node' => $node); - } - - public function getImportedSymbol($type, $alias) - { - foreach ($this->importedSymbols as $functions) { - if (isset($functions[$type][$alias])) { - return $functions[$type][$alias]; - } - } - } - - public function isMainScope() - { - return 1 === count($this->importedSymbols); - } - - public function pushLocalScope() - { - array_unshift($this->importedSymbols, array()); - } - - public function popLocalScope() - { - array_shift($this->importedSymbols); - } - - /** - * @return Twig_ExpressionParser - */ - public function getExpressionParser() - { - return $this->expressionParser; - } - - public function getParent() - { - return $this->parent; - } - - public function setParent($parent) - { - $this->parent = $parent; - } - - /** - * @return Twig_TokenStream - */ - public function getStream() - { - return $this->stream; - } - - /** - * @return Twig_Token - */ - public function getCurrentToken() - { - return $this->stream->getCurrent(); - } - - protected function filterBodyNodes(Twig_NodeInterface $node) - { - // check that the body does not contain non-empty output nodes - if ( - ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data'))) - || - (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface) - ) { - if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) { - throw new Twig_Error_Syntax('A template that extends another one cannot start with a byte order mark (BOM); it must be removed.', $node->getTemplateLine(), $this->stream->getSourceContext()); - } - - throw new Twig_Error_Syntax('A template that extends another one cannot include content outside Twig blocks. Did you forget to put the content inside a {% block %} tag?', $node->getTemplateLine(), $this->stream->getSourceContext()); - } - - // bypass nodes that will "capture" the output - if ($node instanceof Twig_NodeCaptureInterface) { - return $node; - } - - if ($node instanceof Twig_NodeOutputInterface) { - return; - } - - foreach ($node as $k => $n) { - if (null !== $n && null === $this->filterBodyNodes($n)) { - $node->removeNode($k); - } - } - - return $node; - } -} - -class_alias('Twig_Parser', 'Twig\Parser', false); -class_exists('Twig_Node'); -class_exists('Twig_TokenStream'); diff --git a/inc/lib/Twig/ParserInterface.php b/inc/lib/Twig/ParserInterface.php deleted file mode 100644 index 85c6e67b..00000000 --- a/inc/lib/Twig/ParserInterface.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_ParserInterface -{ - /** - * Converts a token stream to a node tree. - * - * @return Twig_Node_Module - * - * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong - */ - public function parse(Twig_TokenStream $stream); -} diff --git a/inc/lib/Twig/Profiler/Dumper/Base.php b/inc/lib/Twig/Profiler/Dumper/Base.php deleted file mode 100644 index 913afd4f..00000000 --- a/inc/lib/Twig/Profiler/Dumper/Base.php +++ /dev/null @@ -1,62 +0,0 @@ - - */ -abstract class Twig_Profiler_Dumper_Base -{ - private $root; - - public function dump(Twig_Profiler_Profile $profile) - { - return $this->dumpProfile($profile); - } - - abstract protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix); - - abstract protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix); - - abstract protected function formatTime(Twig_Profiler_Profile $profile, $percent); - - private function dumpProfile(Twig_Profiler_Profile $profile, $prefix = '', $sibling = false) - { - if ($profile->isRoot()) { - $this->root = $profile->getDuration(); - $start = $profile->getName(); - } else { - if ($profile->isTemplate()) { - $start = $this->formatTemplate($profile, $prefix); - } else { - $start = $this->formatNonTemplate($profile, $prefix); - } - $prefix .= $sibling ? '│ ' : ' '; - } - - $percent = $this->root ? $profile->getDuration() / $this->root * 100 : 0; - - if ($profile->getDuration() * 1000 < 1) { - $str = $start."\n"; - } else { - $str = sprintf("%s %s\n", $start, $this->formatTime($profile, $percent)); - } - - $nCount = count($profile->getProfiles()); - foreach ($profile as $i => $p) { - $str .= $this->dumpProfile($p, $prefix, $i + 1 !== $nCount); - } - - return $str; - } -} - -class_alias('Twig_Profiler_Dumper_Base', 'Twig\Profiler\Dumper\BaseDumper', false); -class_exists('Twig_Profiler_Profile'); diff --git a/inc/lib/Twig/Profiler/Dumper/Blackfire.php b/inc/lib/Twig/Profiler/Dumper/Blackfire.php deleted file mode 100644 index 7a33baf2..00000000 --- a/inc/lib/Twig/Profiler/Dumper/Blackfire.php +++ /dev/null @@ -1,72 +0,0 @@ - - * - * @final - */ -class Twig_Profiler_Dumper_Blackfire -{ - public function dump(Twig_Profiler_Profile $profile) - { - $data = array(); - $this->dumpProfile('main()', $profile, $data); - $this->dumpChildren('main()', $profile, $data); - - $start = sprintf('%f', microtime(true)); - $str = << $values) { - $str .= "{$name}//{$values['ct']} {$values['wt']} {$values['mu']} {$values['pmu']}\n"; - } - - return $str; - } - - private function dumpChildren($parent, Twig_Profiler_Profile $profile, &$data) - { - foreach ($profile as $p) { - if ($p->isTemplate()) { - $name = $p->getTemplate(); - } else { - $name = sprintf('%s::%s(%s)', $p->getTemplate(), $p->getType(), $p->getName()); - } - $this->dumpProfile(sprintf('%s==>%s', $parent, $name), $p, $data); - $this->dumpChildren($name, $p, $data); - } - } - - private function dumpProfile($edge, Twig_Profiler_Profile $profile, &$data) - { - if (isset($data[$edge])) { - $data[$edge]['ct'] += 1; - $data[$edge]['wt'] += floor($profile->getDuration() * 1000000); - $data[$edge]['mu'] += $profile->getMemoryUsage(); - $data[$edge]['pmu'] += $profile->getPeakMemoryUsage(); - } else { - $data[$edge] = array( - 'ct' => 1, - 'wt' => floor($profile->getDuration() * 1000000), - 'mu' => $profile->getMemoryUsage(), - 'pmu' => $profile->getPeakMemoryUsage(), - ); - } - } -} - -class_alias('Twig_Profiler_Dumper_Blackfire', 'Twig\Profiler\Dumper\BlackfireDumper', false); diff --git a/inc/lib/Twig/Profiler/Dumper/Html.php b/inc/lib/Twig/Profiler/Dumper/Html.php deleted file mode 100644 index b57a2551..00000000 --- a/inc/lib/Twig/Profiler/Dumper/Html.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * @final - */ -class Twig_Profiler_Dumper_Html extends Twig_Profiler_Dumper_Base -{ - private static $colors = array( - 'block' => '#dfd', - 'macro' => '#ddf', - 'template' => '#ffd', - 'big' => '#d44', - ); - - public function dump(Twig_Profiler_Profile $profile) - { - return '
'.parent::dump($profile).'
'; - } - - protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix) - { - return sprintf('%s└ %s', $prefix, self::$colors['template'], $profile->getTemplate()); - } - - protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix) - { - return sprintf('%s└ %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), isset(self::$colors[$profile->getType()]) ? self::$colors[$profile->getType()] : 'auto', $profile->getName()); - } - - protected function formatTime(Twig_Profiler_Profile $profile, $percent) - { - return sprintf('%.2fms/%.0f%%', $percent > 20 ? self::$colors['big'] : 'auto', $profile->getDuration() * 1000, $percent); - } -} - -class_alias('Twig_Profiler_Dumper_Html', 'Twig\Profiler\Dumper\HtmlDumper', false); diff --git a/inc/lib/Twig/Profiler/Dumper/Text.php b/inc/lib/Twig/Profiler/Dumper/Text.php deleted file mode 100644 index 69d2c4bf..00000000 --- a/inc/lib/Twig/Profiler/Dumper/Text.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * @final - */ -class Twig_Profiler_Dumper_Text extends Twig_Profiler_Dumper_Base -{ - protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix) - { - return sprintf('%s└ %s', $prefix, $profile->getTemplate()); - } - - protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix) - { - return sprintf('%s└ %s::%s(%s)', $prefix, $profile->getTemplate(), $profile->getType(), $profile->getName()); - } - - protected function formatTime(Twig_Profiler_Profile $profile, $percent) - { - return sprintf('%.2fms/%.0f%%', $profile->getDuration() * 1000, $percent); - } -} - -class_alias('Twig_Profiler_Dumper_Text', 'Twig\Profiler\Dumper\TextDumper', false); diff --git a/inc/lib/Twig/Profiler/Node/EnterProfile.php b/inc/lib/Twig/Profiler/Node/EnterProfile.php deleted file mode 100644 index 69c8f797..00000000 --- a/inc/lib/Twig/Profiler/Node/EnterProfile.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -class Twig_Profiler_Node_EnterProfile extends Twig_Node -{ - public function __construct($extensionName, $type, $name, $varName) - { - parent::__construct(array(), array('extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName)); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->write(sprintf('$%s = $this->env->getExtension(', $this->getAttribute('var_name'))) - ->repr($this->getAttribute('extension_name')) - ->raw(");\n") - ->write(sprintf('$%s->enter($%s = new Twig_Profiler_Profile($this->getTemplateName(), ', $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) - ->repr($this->getAttribute('type')) - ->raw(', ') - ->repr($this->getAttribute('name')) - ->raw("));\n\n") - ; - } -} - -class_alias('Twig_Profiler_Node_EnterProfile', 'Twig\Profiler\Node\EnterProfileNode', false); diff --git a/inc/lib/Twig/Profiler/Node/LeaveProfile.php b/inc/lib/Twig/Profiler/Node/LeaveProfile.php deleted file mode 100644 index d1d6a7cc..00000000 --- a/inc/lib/Twig/Profiler/Node/LeaveProfile.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -class Twig_Profiler_Node_LeaveProfile extends Twig_Node -{ - public function __construct($varName) - { - parent::__construct(array(), array('var_name' => $varName)); - } - - public function compile(Twig_Compiler $compiler) - { - $compiler - ->write("\n") - ->write(sprintf("\$%s->leave(\$%s);\n\n", $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) - ; - } -} - -class_alias('Twig_Profiler_Node_LeaveProfile', 'Twig\Profiler\Node\LeaveProfileNode', false); diff --git a/inc/lib/Twig/Profiler/NodeVisitor/Profiler.php b/inc/lib/Twig/Profiler/NodeVisitor/Profiler.php deleted file mode 100644 index 5db41fea..00000000 --- a/inc/lib/Twig/Profiler/NodeVisitor/Profiler.php +++ /dev/null @@ -1,67 +0,0 @@ - - * - * @final - */ -class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor -{ - private $extensionName; - - public function __construct($extensionName) - { - $this->extensionName = $extensionName; - } - - protected function doEnterNode(Twig_Node $node, Twig_Environment $env) - { - return $node; - } - - protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) - { - if ($node instanceof Twig_Node_Module) { - $varName = $this->getVarName(); - $node->setNode('display_start', new Twig_Node(array(new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::TEMPLATE, $node->getTemplateName(), $varName), $node->getNode('display_start')))); - $node->setNode('display_end', new Twig_Node(array(new Twig_Profiler_Node_LeaveProfile($varName), $node->getNode('display_end')))); - } elseif ($node instanceof Twig_Node_Block) { - $varName = $this->getVarName(); - $node->setNode('body', new Twig_Node_Body(array( - new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::BLOCK, $node->getAttribute('name'), $varName), - $node->getNode('body'), - new Twig_Profiler_Node_LeaveProfile($varName), - ))); - } elseif ($node instanceof Twig_Node_Macro) { - $varName = $this->getVarName(); - $node->setNode('body', new Twig_Node_Body(array( - new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::MACRO, $node->getAttribute('name'), $varName), - $node->getNode('body'), - new Twig_Profiler_Node_LeaveProfile($varName), - ))); - } - - return $node; - } - - private function getVarName() - { - return sprintf('__internal_%s', hash('sha256', $this->extensionName)); - } - - public function getPriority() - { - return 0; - } -} - -class_alias('Twig_Profiler_NodeVisitor_Profiler', 'Twig\Profiler\NodeVisitor\ProfilerNodeVisitor', false); diff --git a/inc/lib/Twig/Profiler/Profile.php b/inc/lib/Twig/Profiler/Profile.php deleted file mode 100644 index 3fdc1a8a..00000000 --- a/inc/lib/Twig/Profiler/Profile.php +++ /dev/null @@ -1,170 +0,0 @@ - - * - * @final - */ -class Twig_Profiler_Profile implements IteratorAggregate, Serializable -{ - const ROOT = 'ROOT'; - const BLOCK = 'block'; - const TEMPLATE = 'template'; - const MACRO = 'macro'; - - private $template; - private $name; - private $type; - private $starts = array(); - private $ends = array(); - private $profiles = array(); - - public function __construct($template = 'main', $type = self::ROOT, $name = 'main') - { - $this->template = $template; - $this->type = $type; - $this->name = 0 === strpos($name, '__internal_') ? 'INTERNAL' : $name; - $this->enter(); - } - - public function getTemplate() - { - return $this->template; - } - - public function getType() - { - return $this->type; - } - - public function getName() - { - return $this->name; - } - - public function isRoot() - { - return self::ROOT === $this->type; - } - - public function isTemplate() - { - return self::TEMPLATE === $this->type; - } - - public function isBlock() - { - return self::BLOCK === $this->type; - } - - public function isMacro() - { - return self::MACRO === $this->type; - } - - public function getProfiles() - { - return $this->profiles; - } - - public function addProfile(Twig_Profiler_Profile $profile) - { - $this->profiles[] = $profile; - } - - /** - * Returns the duration in microseconds. - * - * @return int - */ - public function getDuration() - { - if ($this->isRoot() && $this->profiles) { - // for the root node with children, duration is the sum of all child durations - $duration = 0; - foreach ($this->profiles as $profile) { - $duration += $profile->getDuration(); - } - - return $duration; - } - - return isset($this->ends['wt']) && isset($this->starts['wt']) ? $this->ends['wt'] - $this->starts['wt'] : 0; - } - - /** - * Returns the memory usage in bytes. - * - * @return int - */ - public function getMemoryUsage() - { - return isset($this->ends['mu']) && isset($this->starts['mu']) ? $this->ends['mu'] - $this->starts['mu'] : 0; - } - - /** - * Returns the peak memory usage in bytes. - * - * @return int - */ - public function getPeakMemoryUsage() - { - return isset($this->ends['pmu']) && isset($this->starts['pmu']) ? $this->ends['pmu'] - $this->starts['pmu'] : 0; - } - - /** - * Starts the profiling. - */ - public function enter() - { - $this->starts = array( - 'wt' => microtime(true), - 'mu' => memory_get_usage(), - 'pmu' => memory_get_peak_usage(), - ); - } - - /** - * Stops the profiling. - */ - public function leave() - { - $this->ends = array( - 'wt' => microtime(true), - 'mu' => memory_get_usage(), - 'pmu' => memory_get_peak_usage(), - ); - } - - public function reset() - { - $this->starts = $this->ends = $this->profiles = array(); - $this->enter(); - } - - public function getIterator() - { - return new ArrayIterator($this->profiles); - } - - public function serialize() - { - return serialize(array($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles)); - } - - public function unserialize($data) - { - list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = unserialize($data); - } -} - -class_alias('Twig_Profiler_Profile', 'Twig\Profiler\Profile', false); diff --git a/inc/lib/Twig/RuntimeLoaderInterface.php b/inc/lib/Twig/RuntimeLoaderInterface.php deleted file mode 100644 index f5eb14e0..00000000 --- a/inc/lib/Twig/RuntimeLoaderInterface.php +++ /dev/null @@ -1,29 +0,0 @@ - - */ -interface Twig_RuntimeLoaderInterface -{ - /** - * Creates the runtime implementation of a Twig element (filter/function/test). - * - * @param string $class A runtime class - * - * @return object|null The runtime instance or null if the loader does not know how to create the runtime for this class - */ - public function load($class); -} - -class_alias('Twig_RuntimeLoaderInterface', 'Twig\RuntimeLoader\RuntimeLoaderInterface', false); diff --git a/inc/lib/Twig/Sandbox/SecurityError.php b/inc/lib/Twig/Sandbox/SecurityError.php deleted file mode 100644 index b6707e38..00000000 --- a/inc/lib/Twig/Sandbox/SecurityError.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -class Twig_Sandbox_SecurityError extends Twig_Error -{ -} - -class_alias('Twig_Sandbox_SecurityError', 'Twig\Sandbox\SecurityError', false); diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php deleted file mode 100644 index 0ba33276..00000000 --- a/inc/lib/Twig/Sandbox/SecurityNotAllowedFilterError.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -class Twig_Sandbox_SecurityNotAllowedFilterError extends Twig_Sandbox_SecurityError -{ - private $filterName; - - public function __construct($message, $functionName, $lineno = -1, $filename = null, Exception $previous = null) - { - parent::__construct($message, $lineno, $filename, $previous); - $this->filterName = $functionName; - } - - public function getFilterName() - { - return $this->filterName; - } -} - -class_alias('Twig_Sandbox_SecurityNotAllowedFilterError', 'Twig\Sandbox\SecurityNotAllowedFilterError', false); diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php deleted file mode 100644 index aa391429..00000000 --- a/inc/lib/Twig/Sandbox/SecurityNotAllowedFunctionError.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -class Twig_Sandbox_SecurityNotAllowedFunctionError extends Twig_Sandbox_SecurityError -{ - private $functionName; - - public function __construct($message, $functionName, $lineno = -1, $filename = null, Exception $previous = null) - { - parent::__construct($message, $lineno, $filename, $previous); - $this->functionName = $functionName; - } - - public function getFunctionName() - { - return $this->functionName; - } -} - -class_alias('Twig_Sandbox_SecurityNotAllowedFunctionError', 'Twig\Sandbox\SecurityNotAllowedFunctionError', false); diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php deleted file mode 100644 index 93012fe9..00000000 --- a/inc/lib/Twig/Sandbox/SecurityNotAllowedMethodError.php +++ /dev/null @@ -1,40 +0,0 @@ - - */ -class Twig_Sandbox_SecurityNotAllowedMethodError extends Twig_Sandbox_SecurityError -{ - private $className; - private $methodName; - - public function __construct($message, $className, $methodName, $lineno = -1, $filename = null, Exception $previous = null) - { - parent::__construct($message, $lineno, $filename, $previous); - $this->className = $className; - $this->methodName = $methodName; - } - - public function getClassName() - { - return $this->className; - } - - public function getMethodName() - { - return $this->methodName; - } -} - -class_alias('Twig_Sandbox_SecurityNotAllowedMethodError', 'Twig\Sandbox\SecurityNotAllowedMethodError', false); diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php deleted file mode 100644 index f27969c1..00000000 --- a/inc/lib/Twig/Sandbox/SecurityNotAllowedPropertyError.php +++ /dev/null @@ -1,40 +0,0 @@ - - */ -class Twig_Sandbox_SecurityNotAllowedPropertyError extends Twig_Sandbox_SecurityError -{ - private $className; - private $propertyName; - - public function __construct($message, $className, $propertyName, $lineno = -1, $filename = null, Exception $previous = null) - { - parent::__construct($message, $lineno, $filename, $previous); - $this->className = $className; - $this->propertyName = $propertyName; - } - - public function getClassName() - { - return $this->className; - } - - public function getPropertyName() - { - return $this->propertyName; - } -} - -class_alias('Twig_Sandbox_SecurityNotAllowedPropertyError', 'Twig\Sandbox\SecurityNotAllowedPropertyError', false); diff --git a/inc/lib/Twig/Sandbox/SecurityNotAllowedTagError.php b/inc/lib/Twig/Sandbox/SecurityNotAllowedTagError.php deleted file mode 100644 index 4bbd2238..00000000 --- a/inc/lib/Twig/Sandbox/SecurityNotAllowedTagError.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -class Twig_Sandbox_SecurityNotAllowedTagError extends Twig_Sandbox_SecurityError -{ - private $tagName; - - public function __construct($message, $tagName, $lineno = -1, $filename = null, Exception $previous = null) - { - parent::__construct($message, $lineno, $filename, $previous); - $this->tagName = $tagName; - } - - public function getTagName() - { - return $this->tagName; - } -} - -class_alias('Twig_Sandbox_SecurityNotAllowedTagError', 'Twig\Sandbox\SecurityNotAllowedTagError', false); diff --git a/inc/lib/Twig/Sandbox/SecurityPolicy.php b/inc/lib/Twig/Sandbox/SecurityPolicy.php deleted file mode 100644 index dca0b82b..00000000 --- a/inc/lib/Twig/Sandbox/SecurityPolicy.php +++ /dev/null @@ -1,125 +0,0 @@ - - */ -class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface -{ - protected $allowedTags; - protected $allowedFilters; - protected $allowedMethods; - protected $allowedProperties; - protected $allowedFunctions; - - public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array()) - { - $this->allowedTags = $allowedTags; - $this->allowedFilters = $allowedFilters; - $this->setAllowedMethods($allowedMethods); - $this->allowedProperties = $allowedProperties; - $this->allowedFunctions = $allowedFunctions; - } - - public function setAllowedTags(array $tags) - { - $this->allowedTags = $tags; - } - - public function setAllowedFilters(array $filters) - { - $this->allowedFilters = $filters; - } - - public function setAllowedMethods(array $methods) - { - $this->allowedMethods = array(); - foreach ($methods as $class => $m) { - $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m)); - } - } - - public function setAllowedProperties(array $properties) - { - $this->allowedProperties = $properties; - } - - public function setAllowedFunctions(array $functions) - { - $this->allowedFunctions = $functions; - } - - public function checkSecurity($tags, $filters, $functions) - { - foreach ($tags as $tag) { - if (!in_array($tag, $this->allowedTags)) { - throw new Twig_Sandbox_SecurityNotAllowedTagError(sprintf('Tag "%s" is not allowed.', $tag), $tag); - } - } - - foreach ($filters as $filter) { - if (!in_array($filter, $this->allowedFilters)) { - throw new Twig_Sandbox_SecurityNotAllowedFilterError(sprintf('Filter "%s" is not allowed.', $filter), $filter); - } - } - - foreach ($functions as $function) { - if (!in_array($function, $this->allowedFunctions)) { - throw new Twig_Sandbox_SecurityNotAllowedFunctionError(sprintf('Function "%s" is not allowed.', $function), $function); - } - } - } - - public function checkMethodAllowed($obj, $method) - { - if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) { - return true; - } - - $allowed = false; - $method = strtolower($method); - foreach ($this->allowedMethods as $class => $methods) { - if ($obj instanceof $class) { - $allowed = in_array($method, $methods); - - break; - } - } - - if (!$allowed) { - $class = get_class($obj); - throw new Twig_Sandbox_SecurityNotAllowedMethodError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method); - } - } - - public function checkPropertyAllowed($obj, $property) - { - $allowed = false; - foreach ($this->allowedProperties as $class => $properties) { - if ($obj instanceof $class) { - $allowed = in_array($property, is_array($properties) ? $properties : array($properties)); - - break; - } - } - - if (!$allowed) { - $class = get_class($obj); - throw new Twig_Sandbox_SecurityNotAllowedPropertyError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property); - } - } -} - -class_alias('Twig_Sandbox_SecurityPolicy', 'Twig\Sandbox\SecurityPolicy', false); diff --git a/inc/lib/Twig/Sandbox/SecurityPolicyInterface.php b/inc/lib/Twig/Sandbox/SecurityPolicyInterface.php deleted file mode 100644 index 88f64447..00000000 --- a/inc/lib/Twig/Sandbox/SecurityPolicyInterface.php +++ /dev/null @@ -1,26 +0,0 @@ - - */ -interface Twig_Sandbox_SecurityPolicyInterface -{ - public function checkSecurity($tags, $filters, $functions); - - public function checkMethodAllowed($obj, $method); - - public function checkPropertyAllowed($obj, $method); -} - -class_alias('Twig_Sandbox_SecurityPolicyInterface', 'Twig\Sandbox\SecurityPolicyInterface', false); diff --git a/inc/lib/Twig/SimpleFilter.php b/inc/lib/Twig/SimpleFilter.php deleted file mode 100644 index ee4c0aeb..00000000 --- a/inc/lib/Twig/SimpleFilter.php +++ /dev/null @@ -1,121 +0,0 @@ - - */ -class Twig_SimpleFilter -{ - protected $name; - protected $callable; - protected $options; - protected $arguments = array(); - - public function __construct($name, $callable, array $options = array()) - { - $this->name = $name; - $this->callable = $callable; - $this->options = array_merge(array( - 'needs_environment' => false, - 'needs_context' => false, - 'is_variadic' => false, - 'is_safe' => null, - 'is_safe_callback' => null, - 'pre_escape' => null, - 'preserves_safety' => null, - 'node_class' => 'Twig_Node_Expression_Filter', - 'deprecated' => false, - 'alternative' => null, - ), $options); - } - - public function getName() - { - return $this->name; - } - - public function getCallable() - { - return $this->callable; - } - - public function getNodeClass() - { - return $this->options['node_class']; - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Twig_Node $filterArgs) - { - if (null !== $this->options['is_safe']) { - return $this->options['is_safe']; - } - - if (null !== $this->options['is_safe_callback']) { - return call_user_func($this->options['is_safe_callback'], $filterArgs); - } - } - - public function getPreservesSafety() - { - return $this->options['preserves_safety']; - } - - public function getPreEscape() - { - return $this->options['pre_escape']; - } - - public function isVariadic() - { - return $this->options['is_variadic']; - } - - public function isDeprecated() - { - return (bool) $this->options['deprecated']; - } - - public function getDeprecatedVersion() - { - return $this->options['deprecated']; - } - - public function getAlternative() - { - return $this->options['alternative']; - } -} - -class_alias('Twig_SimpleFilter', 'Twig\TwigFilter', false); diff --git a/inc/lib/Twig/SimpleFunction.php b/inc/lib/Twig/SimpleFunction.php deleted file mode 100644 index a6aa7ca7..00000000 --- a/inc/lib/Twig/SimpleFunction.php +++ /dev/null @@ -1,111 +0,0 @@ - - */ -class Twig_SimpleFunction -{ - protected $name; - protected $callable; - protected $options; - protected $arguments = array(); - - public function __construct($name, $callable, array $options = array()) - { - $this->name = $name; - $this->callable = $callable; - $this->options = array_merge(array( - 'needs_environment' => false, - 'needs_context' => false, - 'is_variadic' => false, - 'is_safe' => null, - 'is_safe_callback' => null, - 'node_class' => 'Twig_Node_Expression_Function', - 'deprecated' => false, - 'alternative' => null, - ), $options); - } - - public function getName() - { - return $this->name; - } - - public function getCallable() - { - return $this->callable; - } - - public function getNodeClass() - { - return $this->options['node_class']; - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Twig_Node $functionArgs) - { - if (null !== $this->options['is_safe']) { - return $this->options['is_safe']; - } - - if (null !== $this->options['is_safe_callback']) { - return call_user_func($this->options['is_safe_callback'], $functionArgs); - } - - return array(); - } - - public function isVariadic() - { - return $this->options['is_variadic']; - } - - public function isDeprecated() - { - return (bool) $this->options['deprecated']; - } - - public function getDeprecatedVersion() - { - return $this->options['deprecated']; - } - - public function getAlternative() - { - return $this->options['alternative']; - } -} - -class_alias('Twig_SimpleFunction', 'Twig\TwigFunction', false); diff --git a/inc/lib/Twig/SimpleTest.php b/inc/lib/Twig/SimpleTest.php deleted file mode 100644 index fee5778b..00000000 --- a/inc/lib/Twig/SimpleTest.php +++ /dev/null @@ -1,73 +0,0 @@ - - */ -class Twig_SimpleTest -{ - protected $name; - protected $callable; - protected $options; - - public function __construct($name, $callable, array $options = array()) - { - $this->name = $name; - $this->callable = $callable; - $this->options = array_merge(array( - 'is_variadic' => false, - 'node_class' => 'Twig_Node_Expression_Test', - 'deprecated' => false, - 'alternative' => null, - ), $options); - } - - public function getName() - { - return $this->name; - } - - public function getCallable() - { - return $this->callable; - } - - public function getNodeClass() - { - return $this->options['node_class']; - } - - public function isVariadic() - { - return $this->options['is_variadic']; - } - - public function isDeprecated() - { - return (bool) $this->options['deprecated']; - } - - public function getDeprecatedVersion() - { - return $this->options['deprecated']; - } - - public function getAlternative() - { - return $this->options['alternative']; - } -} - -class_alias('Twig_SimpleTest', 'Twig\TwigTest', false); diff --git a/inc/lib/Twig/Source.php b/inc/lib/Twig/Source.php deleted file mode 100644 index bd8d869f..00000000 --- a/inc/lib/Twig/Source.php +++ /dev/null @@ -1,53 +0,0 @@ - - */ -class Twig_Source -{ - private $code; - private $name; - private $path; - - /** - * @param string $code The template source code - * @param string $name The template logical name - * @param string $path The filesystem path of the template if any - */ - public function __construct($code, $name, $path = '') - { - $this->code = $code; - $this->name = $name; - $this->path = $path; - } - - public function getCode() - { - return $this->code; - } - - public function getName() - { - return $this->name; - } - - public function getPath() - { - return $this->path; - } -} - -class_alias('Twig_Source', 'Twig\Source', false); diff --git a/inc/lib/Twig/SourceContextLoaderInterface.php b/inc/lib/Twig/SourceContextLoaderInterface.php deleted file mode 100644 index a6e8c425..00000000 --- a/inc/lib/Twig/SourceContextLoaderInterface.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * @deprecated since 1.27 (to be removed in 3.0) - */ -interface Twig_SourceContextLoaderInterface -{ - /** - * Returns the source context for a given template logical name. - * - * @param string $name The template logical name - * - * @return Twig_Source - * - * @throws Twig_Error_Loader When $name is not found - */ - public function getSourceContext($name); -} - -class_alias('Twig_SourceContextLoaderInterface', 'Twig\Loader\SourceContextLoaderInterface', false); diff --git a/inc/lib/Twig/Template.php b/inc/lib/Twig/Template.php deleted file mode 100644 index 3709232a..00000000 --- a/inc/lib/Twig/Template.php +++ /dev/null @@ -1,708 +0,0 @@ -load() - * instead, which returns an instance of Twig_TemplateWrapper. - * - * @author Fabien Potencier - * - * @internal - */ -abstract class Twig_Template implements Twig_TemplateInterface -{ - /** - * @internal - */ - protected static $cache = array(); - - protected $parent; - protected $parents = array(); - protected $env; - protected $blocks = array(); - protected $traits = array(); - - public function __construct(Twig_Environment $env) - { - $this->env = $env; - } - - /** - * @internal this method will be removed in 2.0 and is only used internally to provide an upgrade path from 1.x to 2.0 - */ - public function __toString() - { - return $this->getTemplateName(); - } - - /** - * Returns the template name. - * - * @return string The template name - */ - abstract public function getTemplateName(); - - /** - * Returns debug information about the template. - * - * @return array Debug information - * - * @internal - */ - public function getDebugInfo() - { - return array(); - } - - /** - * Returns the template source code. - * - * @return string The template source code - * - * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead - */ - public function getSource() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); - - return ''; - } - - /** - * Returns information about the original template source code. - * - * @return Twig_Source - */ - public function getSourceContext() - { - return new Twig_Source('', $this->getTemplateName()); - } - - /** - * @deprecated since 1.20 (to be removed in 2.0) - */ - public function getEnvironment() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.20 and will be removed in 2.0.', E_USER_DEPRECATED); - - return $this->env; - } - - /** - * Returns the parent template. - * - * This method is for internal use only and should never be called - * directly. - * - * @param array $context - * - * @return Twig_TemplateInterface|false The parent template or false if there is no parent - * - * @internal - */ - public function getParent(array $context) - { - if (null !== $this->parent) { - return $this->parent; - } - - try { - $parent = $this->doGetParent($context); - - if (false === $parent) { - return false; - } - - if ($parent instanceof self) { - return $this->parents[$parent->getTemplateName()] = $parent; - } - - if (!isset($this->parents[$parent])) { - $this->parents[$parent] = $this->loadTemplate($parent); - } - } catch (Twig_Error_Loader $e) { - $e->setSourceContext(null); - $e->guess(); - - throw $e; - } - - return $this->parents[$parent]; - } - - protected function doGetParent(array $context) - { - return false; - } - - public function isTraitable() - { - return true; - } - - /** - * Displays a parent block. - * - * This method is for internal use only and should never be called - * directly. - * - * @param string $name The block name to display from the parent - * @param array $context The context - * @param array $blocks The current set of blocks - * - * @internal - */ - public function displayParentBlock($name, array $context, array $blocks = array()) - { - $name = (string) $name; - - if (isset($this->traits[$name])) { - $this->traits[$name][0]->displayBlock($name, $context, $blocks, false); - } elseif (false !== $parent = $this->getParent($context)) { - $parent->displayBlock($name, $context, $blocks, false); - } else { - throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext()); - } - } - - /** - * Displays a block. - * - * This method is for internal use only and should never be called - * directly. - * - * @param string $name The block name to display - * @param array $context The context - * @param array $blocks The current set of blocks - * @param bool $useBlocks Whether to use the current set of blocks - * - * @internal - */ - public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true) - { - $name = (string) $name; - - if ($useBlocks && isset($blocks[$name])) { - $template = $blocks[$name][0]; - $block = $blocks[$name][1]; - } elseif (isset($this->blocks[$name])) { - $template = $this->blocks[$name][0]; - $block = $this->blocks[$name][1]; - } else { - $template = null; - $block = null; - } - - // avoid RCEs when sandbox is enabled - if (null !== $template && !$template instanceof self) { - throw new LogicException('A block must be a method on a Twig_Template instance.'); - } - - if (null !== $template) { - try { - $template->$block($context, $blocks); - } catch (Twig_Error $e) { - if (!$e->getSourceContext()) { - $e->setSourceContext($template->getSourceContext()); - } - - // this is mostly useful for Twig_Error_Loader exceptions - // see Twig_Error_Loader - if (false === $e->getTemplateLine()) { - $e->setTemplateLine(-1); - $e->guess(); - } - - throw $e; - } catch (Exception $e) { - throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e); - } - } elseif (false !== $parent = $this->getParent($context)) { - $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false); - } else { - @trigger_error(sprintf('Silent display of undefined block "%s" in template "%s" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block(\'%s\') is defined" expression to test for block existence.', $name, $this->getTemplateName(), $name), E_USER_DEPRECATED); - } - } - - /** - * Renders a parent block. - * - * This method is for internal use only and should never be called - * directly. - * - * @param string $name The block name to render from the parent - * @param array $context The context - * @param array $blocks The current set of blocks - * - * @return string The rendered block - * - * @internal - */ - public function renderParentBlock($name, array $context, array $blocks = array()) - { - ob_start(); - $this->displayParentBlock($name, $context, $blocks); - - return ob_get_clean(); - } - - /** - * Renders a block. - * - * This method is for internal use only and should never be called - * directly. - * - * @param string $name The block name to render - * @param array $context The context - * @param array $blocks The current set of blocks - * @param bool $useBlocks Whether to use the current set of blocks - * - * @return string The rendered block - * - * @internal - */ - public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true) - { - ob_start(); - $this->displayBlock($name, $context, $blocks, $useBlocks); - - return ob_get_clean(); - } - - /** - * Returns whether a block exists or not in the current context of the template. - * - * This method checks blocks defined in the current template - * or defined in "used" traits or defined in parent templates. - * - * @param string $name The block name - * @param array $context The context - * @param array $blocks The current set of blocks - * - * @return bool true if the block exists, false otherwise - * - * @internal - */ - public function hasBlock($name, array $context = null, array $blocks = array()) - { - if (null === $context) { - @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); - - return isset($this->blocks[(string) $name]); - } - - if (isset($blocks[$name])) { - return $blocks[$name][0] instanceof self; - } - - if (isset($this->blocks[$name])) { - return true; - } - - if (false !== $parent = $this->getParent($context)) { - return $parent->hasBlock($name, $context); - } - - return false; - } - - /** - * Returns all block names in the current context of the template. - * - * This method checks blocks defined in the current template - * or defined in "used" traits or defined in parent templates. - * - * @param array $context The context - * @param array $blocks The current set of blocks - * - * @return array An array of block names - * - * @internal - */ - public function getBlockNames(array $context = null, array $blocks = array()) - { - if (null === $context) { - @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); - - return array_keys($this->blocks); - } - - $names = array_merge(array_keys($blocks), array_keys($this->blocks)); - - if (false !== $parent = $this->getParent($context)) { - $names = array_merge($names, $parent->getBlockNames($context)); - } - - return array_unique($names); - } - - protected function loadTemplate($template, $templateName = null, $line = null, $index = null) - { - try { - if (is_array($template)) { - return $this->env->resolveTemplate($template); - } - - if ($template instanceof self) { - return $template; - } - - if ($template instanceof Twig_TemplateWrapper) { - return $template; - } - - return $this->env->loadTemplate($template, $index); - } catch (Twig_Error $e) { - if (!$e->getSourceContext()) { - $e->setSourceContext($templateName ? new Twig_Source('', $templateName) : $this->getSourceContext()); - } - - if ($e->getTemplateLine()) { - throw $e; - } - - if (!$line) { - $e->guess(); - } else { - $e->setTemplateLine($line); - } - - throw $e; - } - } - - /** - * Returns all blocks. - * - * This method is for internal use only and should never be called - * directly. - * - * @return array An array of blocks - * - * @internal - */ - public function getBlocks() - { - return $this->blocks; - } - - public function display(array $context, array $blocks = array()) - { - $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks)); - } - - public function render(array $context) - { - $level = ob_get_level(); - ob_start(); - try { - $this->display($context); - } catch (Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; - } catch (Throwable $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; - } - - return ob_get_clean(); - } - - protected function displayWithErrorHandling(array $context, array $blocks = array()) - { - try { - $this->doDisplay($context, $blocks); - } catch (Twig_Error $e) { - if (!$e->getSourceContext()) { - $e->setSourceContext($this->getSourceContext()); - } - - // this is mostly useful for Twig_Error_Loader exceptions - // see Twig_Error_Loader - if (false === $e->getTemplateLine()) { - $e->setTemplateLine(-1); - $e->guess(); - } - - throw $e; - } catch (Exception $e) { - throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e); - } - } - - /** - * Auto-generated method to display the template with the given context. - * - * @param array $context An array of parameters to pass to the template - * @param array $blocks An array of blocks to pass to the template - */ - abstract protected function doDisplay(array $context, array $blocks = array()); - - /** - * Returns a variable from the context. - * - * This method is for internal use only and should never be called - * directly. - * - * This method should not be overridden in a sub-class as this is an - * implementation detail that has been introduced to optimize variable - * access for versions of PHP before 5.4. This is not a way to override - * the way to get a variable value. - * - * @param array $context The context - * @param string $item The variable to return from the context - * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not - * - * @return mixed The content of the context variable - * - * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode - * - * @internal - */ - final protected function getContext($context, $item, $ignoreStrictCheck = false) - { - if (!array_key_exists($item, $context)) { - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist.', $item), -1, $this->getSourceContext()); - } - - return $context[$item]; - } - - /** - * Returns the attribute value for a given array/object. - * - * @param mixed $object The object or array from where to get the item - * @param mixed $item The item to get from the array or object - * @param array $arguments An array of arguments to pass if the item is an object method - * @param string $type The type of attribute (@see Twig_Template constants) - * @param bool $isDefinedTest Whether this is only a defined check - * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not - * - * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true - * - * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false - * - * @internal - */ - protected function getAttribute($object, $item, array $arguments = array(), $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) - { - // array - if (self::METHOD_CALL !== $type) { - $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item; - - if ((is_array($object) && (isset($object[$arrayItem]) || array_key_exists($arrayItem, $object))) - || ($object instanceof ArrayAccess && isset($object[$arrayItem])) - ) { - if ($isDefinedTest) { - return true; - } - - return $object[$arrayItem]; - } - - if (self::ARRAY_CALL === $type || !is_object($object)) { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - if ($object instanceof ArrayAccess) { - $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, get_class($object)); - } elseif (is_object($object)) { - $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, get_class($object)); - } elseif (is_array($object)) { - if (empty($object)) { - $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem); - } else { - $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); - } - } elseif (self::ARRAY_CALL === $type) { - if (null === $object) { - $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item); - } else { - $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, gettype($object), $object); - } - } elseif (null === $object) { - $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item); - } else { - $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, gettype($object), $object); - } - - throw new Twig_Error_Runtime($message, -1, $this->getSourceContext()); - } - } - - if (!is_object($object)) { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - if (null === $object) { - $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); - } elseif (is_array($object)) { - $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item); - } else { - $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, gettype($object), $object); - } - - throw new Twig_Error_Runtime($message, -1, $this->getSourceContext()); - } - - // object property - if (self::METHOD_CALL !== $type && !$object instanceof self) { // Twig_Template does not have public properties, and we don't want to allow access to internal ones - if (isset($object->$item) || array_key_exists((string) $item, $object)) { - if ($isDefinedTest) { - return true; - } - - if ($this->env->hasExtension('Twig_Extension_Sandbox')) { - $this->env->getExtension('Twig_Extension_Sandbox')->checkPropertyAllowed($object, $item); - } - - return $object->$item; - } - } - - $class = get_class($object); - - // object method - if (!isset(self::$cache[$class])) { - // get_class_methods returns all methods accessible in the scope, but we only want public ones to be accessible in templates - if ($object instanceof self) { - $ref = new ReflectionClass($class); - $methods = array(); - - foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $refMethod) { - // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment - if ('getenvironment' !== strtolower($refMethod->name)) { - $methods[] = $refMethod->name; - } - } - } else { - $methods = get_class_methods($object); - } - // sort values to have consistent behavior, so that "get" methods win precedence over "is" methods - sort($methods); - - $cache = array(); - - foreach ($methods as $method) { - $cache[$method] = $method; - $cache[$lcName = strtolower($method)] = $method; - - if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) { - $name = substr($method, 3); - $lcName = substr($lcName, 3); - } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) { - $name = substr($method, 2); - $lcName = substr($lcName, 2); - } else { - continue; - } - - // skip get() and is() methods (in which case, $name is empty) - if ($name) { - if (!isset($cache[$name])) { - $cache[$name] = $method; - } - if (!isset($cache[$lcName])) { - $cache[$lcName] = $method; - } - } - } - self::$cache[$class] = $cache; - } - - $call = false; - if (isset(self::$cache[$class][$item])) { - $method = self::$cache[$class][$item]; - } elseif (isset(self::$cache[$class][$lcItem = strtolower($item)])) { - $method = self::$cache[$class][$lcItem]; - } elseif (isset(self::$cache[$class]['__call'])) { - $method = $item; - $call = true; - } else { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - throw new Twig_Error_Runtime(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), -1, $this->getSourceContext()); - } - - if ($isDefinedTest) { - return true; - } - - if ($this->env->hasExtension('Twig_Extension_Sandbox')) { - $this->env->getExtension('Twig_Extension_Sandbox')->checkMethodAllowed($object, $method); - } - - // Some objects throw exceptions when they have __call, and the method we try - // to call is not supported. If ignoreStrictCheck is true, we should return null. - try { - if (!$arguments) { - $ret = $object->$method(); - } else { - $ret = call_user_func_array(array($object, $method), $arguments); - } - } catch (BadMethodCallException $e) { - if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { - return; - } - throw $e; - } - - // @deprecated in 1.28 - if ($object instanceof Twig_TemplateInterface) { - $self = $object->getTemplateName() === $this->getTemplateName(); - $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $item, $object->getTemplateName(), $this->getTemplateName()); - if ('renderBlock' === $method || 'displayBlock' === $method) { - $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ? '' : ', template'); - } elseif ('hasBlock' === $method) { - $message .= sprintf(' Use "block("%s"%s) is defined" instead).', $arguments[0], $self ? '' : ', template'); - } elseif ('render' === $method || 'display' === $method) { - $message .= sprintf(' Use include("%s") instead).', $object->getTemplateName()); - } - @trigger_error($message, E_USER_DEPRECATED); - - return '' === $ret ? '' : new Twig_Markup($ret, $this->env->getCharset()); - } - - return $ret; - } -} - -class_alias('Twig_Template', 'Twig\Template', false); diff --git a/inc/lib/Twig/TemplateInterface.php b/inc/lib/Twig/TemplateInterface.php deleted file mode 100644 index 457ef7d7..00000000 --- a/inc/lib/Twig/TemplateInterface.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 3.0) - */ -interface Twig_TemplateInterface -{ - const ANY_CALL = 'any'; - const ARRAY_CALL = 'array'; - const METHOD_CALL = 'method'; - - /** - * Renders the template with the given context and returns it as string. - * - * @param array $context An array of parameters to pass to the template - * - * @return string The rendered template - */ - public function render(array $context); - - /** - * Displays the template with the given context. - * - * @param array $context An array of parameters to pass to the template - * @param array $blocks An array of blocks to pass to the template - */ - public function display(array $context, array $blocks = array()); - - /** - * Returns the bound environment for this template. - * - * @return Twig_Environment - */ - public function getEnvironment(); -} diff --git a/inc/lib/Twig/TemplateWrapper.php b/inc/lib/Twig/TemplateWrapper.php deleted file mode 100644 index 497f6e98..00000000 --- a/inc/lib/Twig/TemplateWrapper.php +++ /dev/null @@ -1,133 +0,0 @@ - - */ -final class Twig_TemplateWrapper -{ - private $env; - private $template; - - /** - * This method is for internal use only and should never be called - * directly (use Twig_Environment::load() instead). - * - * @internal - */ - public function __construct(Twig_Environment $env, Twig_Template $template) - { - $this->env = $env; - $this->template = $template; - } - - /** - * Renders the template. - * - * @param array $context An array of parameters to pass to the template - * - * @return string The rendered template - */ - public function render($context = array()) - { - return $this->template->render($context); - } - - /** - * Displays the template. - * - * @param array $context An array of parameters to pass to the template - */ - public function display($context = array()) - { - $this->template->display($context); - } - - /** - * Checks if a block is defined. - * - * @param string $name The block name - * @param array $context An array of parameters to pass to the template - * - * @return bool - */ - public function hasBlock($name, $context = array()) - { - return $this->template->hasBlock($name, $context); - } - - /** - * Returns defined block names in the template. - * - * @param array $context An array of parameters to pass to the template - * - * @return string[] An array of defined template block names - */ - public function getBlockNames($context = array()) - { - return $this->template->getBlockNames($context); - } - - /** - * Renders a template block. - * - * @param string $name The block name to render - * @param array $context An array of parameters to pass to the template - * - * @return string The rendered block - */ - public function renderBlock($name, $context = array()) - { - $context = $this->env->mergeGlobals($context); - $level = ob_get_level(); - ob_start(); - try { - $this->template->displayBlock($name, $context); - } catch (Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; - } catch (Throwable $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; - } - - return ob_get_clean(); - } - - /** - * Displays a template block. - * - * @param string $name The block name to render - * @param array $context An array of parameters to pass to the template - */ - public function displayBlock($name, $context = array()) - { - $this->template->displayBlock($name, $this->env->mergeGlobals($context)); - } - - /** - * @return Twig_Source - */ - public function getSourceContext() - { - return $this->template->getSourceContext(); - } -} - -class_alias('Twig_TemplateWrapper', 'Twig\TemplateWrapper', false); diff --git a/inc/lib/Twig/Test.php b/inc/lib/Twig/Test.php deleted file mode 100644 index b450ec62..00000000 --- a/inc/lib/Twig/Test.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface -{ - protected $options; - protected $arguments = array(); - - public function __construct(array $options = array()) - { - $this->options = array_merge(array( - 'callable' => null, - ), $options); - } - - public function getCallable() - { - return $this->options['callable']; - } -} diff --git a/inc/lib/Twig/Test/Function.php b/inc/lib/Twig/Test/Function.php deleted file mode 100644 index 9e83c3f8..00000000 --- a/inc/lib/Twig/Test/Function.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Test_Function extends Twig_Test -{ - protected $function; - - public function __construct($function, array $options = array()) - { - $options['callable'] = $function; - - parent::__construct($options); - - $this->function = $function; - } - - public function compile() - { - return $this->function; - } -} diff --git a/inc/lib/Twig/Test/IntegrationTestCase.php b/inc/lib/Twig/Test/IntegrationTestCase.php deleted file mode 100644 index 016951aa..00000000 --- a/inc/lib/Twig/Test/IntegrationTestCase.php +++ /dev/null @@ -1,249 +0,0 @@ - - * @author Karma Dordrak - */ -abstract class Twig_Test_IntegrationTestCase extends TestCase -{ - /** - * @return string - */ - abstract protected function getFixturesDir(); - - /** - * @return Twig_RuntimeLoaderInterface[] - */ - protected function getRuntimeLoaders() - { - return array(); - } - - /** - * @return Twig_ExtensionInterface[] - */ - protected function getExtensions() - { - return array(); - } - - /** - * @return Twig_SimpleFilter[] - */ - protected function getTwigFilters() - { - return array(); - } - - /** - * @return Twig_SimpleFunction[] - */ - protected function getTwigFunctions() - { - return array(); - } - - /** - * @return Twig_SimpleTest[] - */ - protected function getTwigTests() - { - return array(); - } - - /** - * @dataProvider getTests - */ - public function testIntegration($file, $message, $condition, $templates, $exception, $outputs) - { - $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); - } - - /** - * @dataProvider getLegacyTests - * @group legacy - */ - public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs) - { - $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); - } - - public function getTests($name, $legacyTests = false) - { - $fixturesDir = realpath($this->getFixturesDir()); - $tests = array(); - - foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($fixturesDir), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - if (!preg_match('/\.test$/', $file)) { - continue; - } - - if ($legacyTests xor false !== strpos($file->getRealpath(), '.legacy.test')) { - continue; - } - - $test = file_get_contents($file->getRealpath()); - - if (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { - $message = $match[1]; - $condition = $match[2]; - $templates = self::parseTemplates($match[3]); - $exception = $match[5]; - $outputs = array(array(null, $match[4], null, '')); - } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { - $message = $match[1]; - $condition = $match[2]; - $templates = self::parseTemplates($match[3]); - $exception = false; - preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER); - } else { - throw new InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file))); - } - - $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs); - } - - if ($legacyTests && empty($tests)) { - // add a dummy test to avoid a PHPUnit message - return array(array('not', '-', '', array(), '', array())); - } - - return $tests; - } - - public function getLegacyTests() - { - return $this->getTests('testLegacyIntegration', true); - } - - protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs) - { - if (!$outputs) { - $this->markTestSkipped('no legacy tests to run'); - } - - if ($condition) { - eval('$ret = '.$condition.';'); - if (!$ret) { - $this->markTestSkipped($condition); - } - } - - $loader = new Twig_Loader_Array($templates); - - foreach ($outputs as $i => $match) { - $config = array_merge(array( - 'cache' => false, - 'strict_variables' => true, - ), $match[2] ? eval($match[2].';') : array()); - $twig = new Twig_Environment($loader, $config); - $twig->addGlobal('global', 'global'); - foreach ($this->getRuntimeLoaders() as $runtimeLoader) { - $twig->addRuntimeLoader($runtimeLoader); - } - - foreach ($this->getExtensions() as $extension) { - $twig->addExtension($extension); - } - - foreach ($this->getTwigFilters() as $filter) { - $twig->addFilter($filter); - } - - foreach ($this->getTwigTests() as $test) { - $twig->addTest($test); - } - - foreach ($this->getTwigFunctions() as $function) { - $twig->addFunction($function); - } - - // avoid using the same PHP class name for different cases - // only for PHP 5.2+ - if (PHP_VERSION_ID >= 50300) { - $p = new ReflectionProperty($twig, 'templateClassPrefix'); - $p->setAccessible(true); - $p->setValue($twig, '__TwigTemplate_'.hash('sha256', uniqid(mt_rand(), true), false).'_'); - } - - try { - $template = $twig->loadTemplate('index.twig'); - } catch (Exception $e) { - if (false !== $exception) { - $message = $e->getMessage(); - $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $message))); - $last = substr($message, strlen($message) - 1); - $this->assertTrue('.' === $last || '?' === $last, $message, 'Exception message must end with a dot or a question mark.'); - - return; - } - - throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); - } - - try { - $output = trim($template->render(eval($match[1].';')), "\n "); - } catch (Exception $e) { - if (false !== $exception) { - $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); - - return; - } - - $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); - - $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage())); - } - - if (false !== $exception) { - list($class) = explode(':', $exception); - $constraintClass = class_exists('PHPUnit\Framework\Constraint\Exception') ? 'PHPUnit\Framework\Constraint\Exception' : 'PHPUnit_Framework_Constraint_Exception'; - $this->assertThat(null, new $constraintClass($class)); - } - - $expected = trim($match[3], "\n "); - - if ($expected !== $output) { - printf("Compiled templates that failed on case %d:\n", $i + 1); - - foreach (array_keys($templates) as $name) { - echo "Template: $name\n"; - $loader = $twig->getLoader(); - if (!$loader instanceof Twig_SourceContextLoaderInterface) { - $source = new Twig_Source($loader->getSource($name), $name); - } else { - $source = $loader->getSourceContext($name); - } - echo $twig->compile($twig->parse($twig->tokenize($source))); - } - } - $this->assertEquals($expected, $output, $message.' (in '.$file.')'); - } - } - - protected static function parseTemplates($test) - { - $templates = array(); - preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2]; - } - - return $templates; - } -} - -class_alias('Twig_Test_IntegrationTestCase', 'Twig\Test\IntegrationTestCase', false); diff --git a/inc/lib/Twig/Test/Method.php b/inc/lib/Twig/Test/Method.php deleted file mode 100644 index feccd5db..00000000 --- a/inc/lib/Twig/Test/Method.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Test_Method extends Twig_Test -{ - protected $extension; - protected $method; - - public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) - { - $options['callable'] = array($extension, $method); - - parent::__construct($options); - - $this->extension = $extension; - $this->method = $method; - } - - public function compile() - { - return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method); - } -} diff --git a/inc/lib/Twig/Test/Node.php b/inc/lib/Twig/Test/Node.php deleted file mode 100644 index 6098a527..00000000 --- a/inc/lib/Twig/Test/Node.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_Test_Node extends Twig_Test -{ - protected $class; - - public function __construct($class, array $options = array()) - { - parent::__construct($options); - - $this->class = $class; - } - - public function getClass() - { - return $this->class; - } - - public function compile() - { - } -} diff --git a/inc/lib/Twig/Test/NodeTestCase.php b/inc/lib/Twig/Test/NodeTestCase.php deleted file mode 100644 index 47942675..00000000 --- a/inc/lib/Twig/Test/NodeTestCase.php +++ /dev/null @@ -1,75 +0,0 @@ -assertNodeCompilation($source, $node, $environment, $isPattern); - } - - public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null, $isPattern = false) - { - $compiler = $this->getCompiler($environment); - $compiler->compile($node); - - if ($isPattern) { - $this->assertStringMatchesFormat($source, trim($compiler->getSource())); - } else { - $this->assertEquals($source, trim($compiler->getSource())); - } - } - - protected function getCompiler(Twig_Environment $environment = null) - { - return new Twig_Compiler(null === $environment ? $this->getEnvironment() : $environment); - } - - protected function getEnvironment() - { - return new Twig_Environment(new Twig_Loader_Array(array())); - } - - protected function getVariableGetter($name, $line = false) - { - $line = $line > 0 ? "// line {$line}\n" : ''; - - if (PHP_VERSION_ID >= 70000) { - return sprintf('%s($context["%s"] ?? null)', $line, $name, $name); - } - - if (PHP_VERSION_ID >= 50400) { - return sprintf('%s(isset($context["%s"]) ? $context["%s"] : null)', $line, $name, $name); - } - - return sprintf('%s$this->getContext($context, "%s")', $line, $name); - } - - protected function getAttributeGetter() - { - if (function_exists('twig_template_get_attributes')) { - return 'twig_template_get_attributes($this, '; - } - - return '$this->getAttribute('; - } -} - -class_alias('Twig_Test_NodeTestCase', 'Twig\Test\NodeTestCase', false); -class_exists('Twig_Environment'); -class_exists('Twig_Node'); diff --git a/inc/lib/Twig/TestCallableInterface.php b/inc/lib/Twig/TestCallableInterface.php deleted file mode 100644 index 51ecb9a2..00000000 --- a/inc/lib/Twig/TestCallableInterface.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_TestCallableInterface -{ - public function getCallable(); -} diff --git a/inc/lib/Twig/TestInterface.php b/inc/lib/Twig/TestInterface.php deleted file mode 100644 index 91664075..00000000 --- a/inc/lib/Twig/TestInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_TestInterface -{ - /** - * Compiles a test. - * - * @return string The PHP code for the test - */ - public function compile(); -} diff --git a/inc/lib/Twig/Token.php b/inc/lib/Twig/Token.php deleted file mode 100644 index 89066869..00000000 --- a/inc/lib/Twig/Token.php +++ /dev/null @@ -1,207 +0,0 @@ - - * - * @final - */ -class Twig_Token -{ - protected $value; - protected $type; - protected $lineno; - - const EOF_TYPE = -1; - const TEXT_TYPE = 0; - const BLOCK_START_TYPE = 1; - const VAR_START_TYPE = 2; - const BLOCK_END_TYPE = 3; - const VAR_END_TYPE = 4; - const NAME_TYPE = 5; - const NUMBER_TYPE = 6; - const STRING_TYPE = 7; - const OPERATOR_TYPE = 8; - const PUNCTUATION_TYPE = 9; - const INTERPOLATION_START_TYPE = 10; - const INTERPOLATION_END_TYPE = 11; - - /** - * @param int $type The type of the token - * @param string $value The token value - * @param int $lineno The line position in the source - */ - public function __construct($type, $value, $lineno) - { - $this->type = $type; - $this->value = $value; - $this->lineno = $lineno; - } - - public function __toString() - { - return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value); - } - - /** - * Tests the current token for a type and/or a value. - * - * Parameters may be: - * * just type - * * type and value (or array of possible values) - * * just value (or array of possible values) (NAME_TYPE is used as type) - * - * @param array|string|int $type The type to test - * @param array|string|null $values The token value - * - * @return bool - */ - public function test($type, $values = null) - { - if (null === $values && !is_int($type)) { - $values = $type; - $type = self::NAME_TYPE; - } - - return ($this->type === $type) && ( - null === $values || - (is_array($values) && in_array($this->value, $values)) || - $this->value == $values - ); - } - - /** - * @return int - */ - public function getLine() - { - return $this->lineno; - } - - /** - * @return int - */ - public function getType() - { - return $this->type; - } - - /** - * @return string - */ - public function getValue() - { - return $this->value; - } - - /** - * Returns the constant representation (internal) of a given type. - * - * @param int $type The type as an integer - * @param bool $short Whether to return a short representation or not - * - * @return string The string representation - */ - public static function typeToString($type, $short = false) - { - switch ($type) { - case self::EOF_TYPE: - $name = 'EOF_TYPE'; - break; - case self::TEXT_TYPE: - $name = 'TEXT_TYPE'; - break; - case self::BLOCK_START_TYPE: - $name = 'BLOCK_START_TYPE'; - break; - case self::VAR_START_TYPE: - $name = 'VAR_START_TYPE'; - break; - case self::BLOCK_END_TYPE: - $name = 'BLOCK_END_TYPE'; - break; - case self::VAR_END_TYPE: - $name = 'VAR_END_TYPE'; - break; - case self::NAME_TYPE: - $name = 'NAME_TYPE'; - break; - case self::NUMBER_TYPE: - $name = 'NUMBER_TYPE'; - break; - case self::STRING_TYPE: - $name = 'STRING_TYPE'; - break; - case self::OPERATOR_TYPE: - $name = 'OPERATOR_TYPE'; - break; - case self::PUNCTUATION_TYPE: - $name = 'PUNCTUATION_TYPE'; - break; - case self::INTERPOLATION_START_TYPE: - $name = 'INTERPOLATION_START_TYPE'; - break; - case self::INTERPOLATION_END_TYPE: - $name = 'INTERPOLATION_END_TYPE'; - break; - default: - throw new LogicException(sprintf('Token of type "%s" does not exist.', $type)); - } - - return $short ? $name : 'Twig_Token::'.$name; - } - - /** - * Returns the English representation of a given type. - * - * @param int $type The type as an integer - * - * @return string The string representation - */ - public static function typeToEnglish($type) - { - switch ($type) { - case self::EOF_TYPE: - return 'end of template'; - case self::TEXT_TYPE: - return 'text'; - case self::BLOCK_START_TYPE: - return 'begin of statement block'; - case self::VAR_START_TYPE: - return 'begin of print statement'; - case self::BLOCK_END_TYPE: - return 'end of statement block'; - case self::VAR_END_TYPE: - return 'end of print statement'; - case self::NAME_TYPE: - return 'name'; - case self::NUMBER_TYPE: - return 'number'; - case self::STRING_TYPE: - return 'string'; - case self::OPERATOR_TYPE: - return 'operator'; - case self::PUNCTUATION_TYPE: - return 'punctuation'; - case self::INTERPOLATION_START_TYPE: - return 'begin of string interpolation'; - case self::INTERPOLATION_END_TYPE: - return 'end of string interpolation'; - default: - throw new LogicException(sprintf('Token of type "%s" does not exist.', $type)); - } - } -} - -class_alias('Twig_Token', 'Twig\Token', false); diff --git a/inc/lib/Twig/TokenParser.php b/inc/lib/Twig/TokenParser.php deleted file mode 100644 index 1b4de14d..00000000 --- a/inc/lib/Twig/TokenParser.php +++ /dev/null @@ -1,33 +0,0 @@ - - */ -abstract class Twig_TokenParser implements Twig_TokenParserInterface -{ - /** - * @var Twig_Parser - */ - protected $parser; - - /** - * Sets the parser associated with this token parser. - */ - public function setParser(Twig_Parser $parser) - { - $this->parser = $parser; - } -} - -class_alias('Twig_TokenParser', 'Twig\TokenParser\AbstractTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/AutoEscape.php b/inc/lib/Twig/TokenParser/AutoEscape.php deleted file mode 100644 index a20dedd1..00000000 --- a/inc/lib/Twig/TokenParser/AutoEscape.php +++ /dev/null @@ -1,83 +0,0 @@ - - * {% autoescape true %} - * Everything will be automatically escaped in this block - * {% endautoescape %} - * - * {% autoescape false %} - * Everything will be outputed as is in this block - * {% endautoescape %} - * - * {% autoescape true js %} - * Everything will be automatically escaped in this block - * using the js escaping strategy - * {% endautoescape %} - * - * - * @final - */ -class Twig_TokenParser_AutoEscape extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $lineno = $token->getLine(); - $stream = $this->parser->getStream(); - - if ($stream->test(Twig_Token::BLOCK_END_TYPE)) { - $value = 'html'; - } else { - $expr = $this->parser->getExpressionParser()->parseExpression(); - if (!$expr instanceof Twig_Node_Expression_Constant) { - throw new Twig_Error_Syntax('An escaping strategy must be a string or a bool.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - $value = $expr->getAttribute('value'); - - $compat = true === $value || false === $value; - - if (true === $value) { - $value = 'html'; - } - - if ($compat && $stream->test(Twig_Token::NAME_TYPE)) { - @trigger_error('Using the autoescape tag with "true" or "false" before the strategy name is deprecated since version 1.21.', E_USER_DEPRECATED); - - if (false === $value) { - throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - - $value = $stream->next()->getValue(); - } - } - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag()); - } - - public function decideBlockEnd(Twig_Token $token) - { - return $token->test('endautoescape'); - } - - public function getTag() - { - return 'autoescape'; - } -} - -class_alias('Twig_TokenParser_AutoEscape', 'Twig\TokenParser\AutoEscapeTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Block.php b/inc/lib/Twig/TokenParser/Block.php deleted file mode 100644 index f30f86b5..00000000 --- a/inc/lib/Twig/TokenParser/Block.php +++ /dev/null @@ -1,73 +0,0 @@ - - * {% block head %} - * - * {% block title %}{% endblock %} - My Webpage - * {% endblock %} - * - * - * @final - */ -class Twig_TokenParser_Block extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $lineno = $token->getLine(); - $stream = $this->parser->getStream(); - $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - if ($this->parser->hasBlock($name)) { - throw new Twig_Error_Syntax(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getTemplateLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno)); - $this->parser->pushLocalScope(); - $this->parser->pushBlockStack($name); - - if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) { - $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) { - $value = $token->getValue(); - - if ($value != $name) { - throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - } - } else { - $body = new Twig_Node(array( - new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno), - )); - } - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - $block->setNode('body', $body); - $this->parser->popBlockStack(); - $this->parser->popLocalScope(); - - return new Twig_Node_BlockReference($name, $lineno, $this->getTag()); - } - - public function decideBlockEnd(Twig_Token $token) - { - return $token->test('endblock'); - } - - public function getTag() - { - return 'block'; - } -} - -class_alias('Twig_TokenParser_Block', 'Twig\TokenParser\BlockTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Do.php b/inc/lib/Twig/TokenParser/Do.php deleted file mode 100644 index 8ce08808..00000000 --- a/inc/lib/Twig/TokenParser/Do.php +++ /dev/null @@ -1,34 +0,0 @@ -parser->getExpressionParser()->parseExpression(); - - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - - return new Twig_Node_Do($expr, $token->getLine(), $this->getTag()); - } - - public function getTag() - { - return 'do'; - } -} - -class_alias('Twig_TokenParser_Do', 'Twig\TokenParser\DoTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Embed.php b/inc/lib/Twig/TokenParser/Embed.php deleted file mode 100644 index 44644cc6..00000000 --- a/inc/lib/Twig/TokenParser/Embed.php +++ /dev/null @@ -1,67 +0,0 @@ -parser->getStream(); - - $parent = $this->parser->getExpressionParser()->parseExpression(); - - list($variables, $only, $ignoreMissing) = $this->parseArguments(); - - $parentToken = $fakeParentToken = new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()); - if ($parent instanceof Twig_Node_Expression_Constant) { - $parentToken = new Twig_Token(Twig_Token::STRING_TYPE, $parent->getAttribute('value'), $token->getLine()); - } elseif ($parent instanceof Twig_Node_Expression_Name) { - $parentToken = new Twig_Token(Twig_Token::NAME_TYPE, $parent->getAttribute('name'), $token->getLine()); - } - - // inject a fake parent to make the parent() function work - $stream->injectTokens(array( - new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()), - new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()), - $parentToken, - new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()), - )); - - $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true); - - // override the parent with the correct one - if ($fakeParentToken === $parentToken) { - $module->setNode('parent', $parent); - } - - $this->parser->embedTemplate($module); - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - return new Twig_Node_Embed($module->getTemplateName(), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); - } - - public function decideBlockEnd(Twig_Token $token) - { - return $token->test('endembed'); - } - - public function getTag() - { - return 'embed'; - } -} - -class_alias('Twig_TokenParser_Embed', 'Twig\TokenParser\EmbedTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Extends.php b/inc/lib/Twig/TokenParser/Extends.php deleted file mode 100644 index 31168cce..00000000 --- a/inc/lib/Twig/TokenParser/Extends.php +++ /dev/null @@ -1,46 +0,0 @@ - - * {% extends "base.html" %} - * - * - * @final - */ -class Twig_TokenParser_Extends extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $stream = $this->parser->getStream(); - - if (!$this->parser->isMainScope()) { - throw new Twig_Error_Syntax('Cannot extend from a block.', $token->getLine(), $stream->getSourceContext()); - } - - if (null !== $this->parser->getParent()) { - throw new Twig_Error_Syntax('Multiple extends tags are forbidden.', $token->getLine(), $stream->getSourceContext()); - } - $this->parser->setParent($this->parser->getExpressionParser()->parseExpression()); - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - } - - public function getTag() - { - return 'extends'; - } -} - -class_alias('Twig_TokenParser_Extends', 'Twig\TokenParser\ExtendsTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Filter.php b/inc/lib/Twig/TokenParser/Filter.php deleted file mode 100644 index 76017829..00000000 --- a/inc/lib/Twig/TokenParser/Filter.php +++ /dev/null @@ -1,53 +0,0 @@ - - * {% filter upper %} - * This text becomes uppercase - * {% endfilter %} - * - * - * @final - */ -class Twig_TokenParser_Filter extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $name = $this->parser->getVarName(); - $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), null, $token->getLine(), $this->getTag()); - - $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag()); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - - $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - - $block = new Twig_Node_Block($name, $body, $token->getLine()); - $this->parser->setBlock($name, $block); - - return new Twig_Node_Print($filter, $token->getLine(), $this->getTag()); - } - - public function decideBlockEnd(Twig_Token $token) - { - return $token->test('endfilter'); - } - - public function getTag() - { - return 'filter'; - } -} - -class_alias('Twig_TokenParser_Filter', 'Twig\TokenParser\FilterTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Flush.php b/inc/lib/Twig/TokenParser/Flush.php deleted file mode 100644 index 51832c77..00000000 --- a/inc/lib/Twig/TokenParser/Flush.php +++ /dev/null @@ -1,34 +0,0 @@ -parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - - return new Twig_Node_Flush($token->getLine(), $this->getTag()); - } - - public function getTag() - { - return 'flush'; - } -} - -class_alias('Twig_TokenParser_Flush', 'Twig\TokenParser\FlushTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/For.php b/inc/lib/Twig/TokenParser/For.php deleted file mode 100644 index 8e737c5f..00000000 --- a/inc/lib/Twig/TokenParser/For.php +++ /dev/null @@ -1,127 +0,0 @@ - - *
    - * {% for user in users %} - *
  • {{ user.username|e }}
  • - * {% endfor %} - *
- * - * - * @final - */ -class Twig_TokenParser_For extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $lineno = $token->getLine(); - $stream = $this->parser->getStream(); - $targets = $this->parser->getExpressionParser()->parseAssignmentExpression(); - $stream->expect(Twig_Token::OPERATOR_TYPE, 'in'); - $seq = $this->parser->getExpressionParser()->parseExpression(); - - $ifexpr = null; - if ($stream->nextIf(Twig_Token::NAME_TYPE, 'if')) { - $ifexpr = $this->parser->getExpressionParser()->parseExpression(); - } - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $body = $this->parser->subparse(array($this, 'decideForFork')); - if ('else' == $stream->next()->getValue()) { - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $else = $this->parser->subparse(array($this, 'decideForEnd'), true); - } else { - $else = null; - } - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - if (count($targets) > 1) { - $keyTarget = $targets->getNode(0); - $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getTemplateLine()); - $valueTarget = $targets->getNode(1); - $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getTemplateLine()); - } else { - $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno); - $valueTarget = $targets->getNode(0); - $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getTemplateLine()); - } - - if ($ifexpr) { - $this->checkLoopUsageCondition($stream, $ifexpr); - $this->checkLoopUsageBody($stream, $body); - } - - return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag()); - } - - public function decideForFork(Twig_Token $token) - { - return $token->test(array('else', 'endfor')); - } - - public function decideForEnd(Twig_Token $token) - { - return $token->test('endfor'); - } - - // the loop variable cannot be used in the condition - protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node) - { - if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { - throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition.', $node->getTemplateLine(), $stream->getSourceContext()); - } - - foreach ($node as $n) { - if (!$n) { - continue; - } - - $this->checkLoopUsageCondition($stream, $n); - } - } - - // check usage of non-defined loop-items - // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include) - protected function checkLoopUsageBody(Twig_TokenStream $stream, Twig_NodeInterface $node) - { - if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { - $attribute = $node->getNode('attribute'); - if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) { - throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition.', $attribute->getAttribute('value')), $node->getTemplateLine(), $stream->getSourceContext()); - } - } - - // should check for parent.loop.XXX usage - if ($node instanceof Twig_Node_For) { - return; - } - - foreach ($node as $n) { - if (!$n) { - continue; - } - - $this->checkLoopUsageBody($stream, $n); - } - } - - public function getTag() - { - return 'for'; - } -} - -class_alias('Twig_TokenParser_For', 'Twig\TokenParser\ForTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/From.php b/inc/lib/Twig/TokenParser/From.php deleted file mode 100644 index f3053da4..00000000 --- a/inc/lib/Twig/TokenParser/From.php +++ /dev/null @@ -1,66 +0,0 @@ - - * {% from 'forms.html' import forms %} - * - * - * @final - */ -class Twig_TokenParser_From extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $macro = $this->parser->getExpressionParser()->parseExpression(); - $stream = $this->parser->getStream(); - $stream->expect('import'); - - $targets = array(); - do { - $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - - $alias = $name; - if ($stream->nextIf('as')) { - $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - } - - $targets[$name] = $alias; - - if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { - break; - } - } while (true); - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag()); - - foreach ($targets as $name => $alias) { - if ($this->parser->isReservedMacroName($name)) { - throw new Twig_Error_Syntax(sprintf('"%s" cannot be an imported macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()); - } - - $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $node->getNode('var')); - } - - return $node; - } - - public function getTag() - { - return 'from'; - } -} - -class_alias('Twig_TokenParser_From', 'Twig\TokenParser\FromTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/If.php b/inc/lib/Twig/TokenParser/If.php deleted file mode 100644 index f081df3a..00000000 --- a/inc/lib/Twig/TokenParser/If.php +++ /dev/null @@ -1,86 +0,0 @@ - - * {% if users %} - *
    - * {% for user in users %} - *
  • {{ user.username|e }}
  • - * {% endfor %} - *
- * {% endif %} - * - * - * @final - */ -class Twig_TokenParser_If extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $lineno = $token->getLine(); - $expr = $this->parser->getExpressionParser()->parseExpression(); - $stream = $this->parser->getStream(); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $body = $this->parser->subparse(array($this, 'decideIfFork')); - $tests = array($expr, $body); - $else = null; - - $end = false; - while (!$end) { - switch ($stream->next()->getValue()) { - case 'else': - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $else = $this->parser->subparse(array($this, 'decideIfEnd')); - break; - - case 'elseif': - $expr = $this->parser->getExpressionParser()->parseExpression(); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $body = $this->parser->subparse(array($this, 'decideIfFork')); - $tests[] = $expr; - $tests[] = $body; - break; - - case 'endif': - $end = true; - break; - - default: - throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d).', $lineno), $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - } - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag()); - } - - public function decideIfFork(Twig_Token $token) - { - return $token->test(array('elseif', 'else', 'endif')); - } - - public function decideIfEnd(Twig_Token $token) - { - return $token->test(array('endif')); - } - - public function getTag() - { - return 'if'; - } -} - -class_alias('Twig_TokenParser_If', 'Twig\TokenParser\IfTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Import.php b/inc/lib/Twig/TokenParser/Import.php deleted file mode 100644 index 47802f50..00000000 --- a/inc/lib/Twig/TokenParser/Import.php +++ /dev/null @@ -1,41 +0,0 @@ - - * {% import 'forms.html' as forms %} - * - * - * @final - */ -class Twig_TokenParser_Import extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $macro = $this->parser->getExpressionParser()->parseExpression(); - $this->parser->getStream()->expect('as'); - $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine()); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - - $this->parser->addImportedSymbol('template', $var->getAttribute('name')); - - return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag()); - } - - public function getTag() - { - return 'import'; - } -} - -class_alias('Twig_TokenParser_Import', 'Twig\TokenParser\ImportTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Include.php b/inc/lib/Twig/TokenParser/Include.php deleted file mode 100644 index 309f11db..00000000 --- a/inc/lib/Twig/TokenParser/Include.php +++ /dev/null @@ -1,65 +0,0 @@ - - * {% include 'header.html' %} - * Body - * {% include 'footer.html' %} - * - */ -class Twig_TokenParser_Include extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $expr = $this->parser->getExpressionParser()->parseExpression(); - - list($variables, $only, $ignoreMissing) = $this->parseArguments(); - - return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); - } - - protected function parseArguments() - { - $stream = $this->parser->getStream(); - - $ignoreMissing = false; - if ($stream->nextIf(Twig_Token::NAME_TYPE, 'ignore')) { - $stream->expect(Twig_Token::NAME_TYPE, 'missing'); - - $ignoreMissing = true; - } - - $variables = null; - if ($stream->nextIf(Twig_Token::NAME_TYPE, 'with')) { - $variables = $this->parser->getExpressionParser()->parseExpression(); - } - - $only = false; - if ($stream->nextIf(Twig_Token::NAME_TYPE, 'only')) { - $only = true; - } - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - return array($variables, $only, $ignoreMissing); - } - - public function getTag() - { - return 'include'; - } -} - -class_alias('Twig_TokenParser_Include', 'Twig\TokenParser\IncludeTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Macro.php b/inc/lib/Twig/TokenParser/Macro.php deleted file mode 100644 index 4287934b..00000000 --- a/inc/lib/Twig/TokenParser/Macro.php +++ /dev/null @@ -1,60 +0,0 @@ - - * {% macro input(name, value, type, size) %} - * - * {% endmacro %} - * - * - * @final - */ -class Twig_TokenParser_Macro extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $lineno = $token->getLine(); - $stream = $this->parser->getStream(); - $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - - $arguments = $this->parser->getExpressionParser()->parseArguments(true, true); - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $this->parser->pushLocalScope(); - $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) { - $value = $token->getValue(); - - if ($value != $name) { - throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - } - $this->parser->popLocalScope(); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag())); - } - - public function decideBlockEnd(Twig_Token $token) - { - return $token->test('endmacro'); - } - - public function getTag() - { - return 'macro'; - } -} - -class_alias('Twig_TokenParser_Macro', 'Twig\TokenParser\MacroTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Sandbox.php b/inc/lib/Twig/TokenParser/Sandbox.php deleted file mode 100644 index 7fc70d9a..00000000 --- a/inc/lib/Twig/TokenParser/Sandbox.php +++ /dev/null @@ -1,61 +0,0 @@ - - * {% sandbox %} - * {% include 'user.html' %} - * {% endsandbox %} - * - * - * @see https://twig.symfony.com/doc/api.html#sandbox-extension for details - * - * @final - */ -class Twig_TokenParser_Sandbox extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $stream = $this->parser->getStream(); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - // in a sandbox tag, only include tags are allowed - if (!$body instanceof Twig_Node_Include) { - foreach ($body as $node) { - if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) { - continue; - } - - if (!$node instanceof Twig_Node_Include) { - throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section.', $node->getTemplateLine(), $stream->getSourceContext()); - } - } - } - - return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag()); - } - - public function decideBlockEnd(Twig_Token $token) - { - return $token->test('endsandbox'); - } - - public function getTag() - { - return 'sandbox'; - } -} - -class_alias('Twig_TokenParser_Sandbox', 'Twig\TokenParser\SandboxTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Set.php b/inc/lib/Twig/TokenParser/Set.php deleted file mode 100644 index 48c6b3ae..00000000 --- a/inc/lib/Twig/TokenParser/Set.php +++ /dev/null @@ -1,75 +0,0 @@ - - * {% set foo = 'foo' %} - * - * {% set foo = [1, 2] %} - * - * {% set foo = {'foo': 'bar'} %} - * - * {% set foo = 'foo' ~ 'bar' %} - * - * {% set foo, bar = 'foo', 'bar' %} - * - * {% set foo %}Some content{% endset %} - * - * - * @final - */ -class Twig_TokenParser_Set extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $lineno = $token->getLine(); - $stream = $this->parser->getStream(); - $names = $this->parser->getExpressionParser()->parseAssignmentExpression(); - - $capture = false; - if ($stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) { - $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - if (count($names) !== count($values)) { - throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - } else { - $capture = true; - - if (count($names) > 1) { - throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - $stream->expect(Twig_Token::BLOCK_END_TYPE); - } - - return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag()); - } - - public function decideBlockEnd(Twig_Token $token) - { - return $token->test('endset'); - } - - public function getTag() - { - return 'set'; - } -} - -class_alias('Twig_TokenParser_Set', 'Twig\TokenParser\SetTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Spaceless.php b/inc/lib/Twig/TokenParser/Spaceless.php deleted file mode 100644 index cecf27c6..00000000 --- a/inc/lib/Twig/TokenParser/Spaceless.php +++ /dev/null @@ -1,51 +0,0 @@ - - * {% spaceless %} - *
- * foo - *
- * {% endspaceless %} - * - * {# output will be
foo
#} - * - * - * @final - */ -class Twig_TokenParser_Spaceless extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $lineno = $token->getLine(); - - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - - return new Twig_Node_Spaceless($body, $lineno, $this->getTag()); - } - - public function decideSpacelessEnd(Twig_Token $token) - { - return $token->test('endspaceless'); - } - - public function getTag() - { - return 'spaceless'; - } -} - -class_alias('Twig_TokenParser_Spaceless', 'Twig\TokenParser\SpacelessTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/Use.php b/inc/lib/Twig/TokenParser/Use.php deleted file mode 100644 index 1ab24e2c..00000000 --- a/inc/lib/Twig/TokenParser/Use.php +++ /dev/null @@ -1,70 +0,0 @@ - - * {% extends "base.html" %} - * - * {% use "blocks.html" %} - * - * {% block title %}{% endblock %} - * {% block content %}{% endblock %} - * - * - * @see https://twig.symfony.com/doc/templates.html#horizontal-reuse for details. - * - * @final - */ -class Twig_TokenParser_Use extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $template = $this->parser->getExpressionParser()->parseExpression(); - $stream = $this->parser->getStream(); - - if (!$template instanceof Twig_Node_Expression_Constant) { - throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - - $targets = array(); - if ($stream->nextIf('with')) { - do { - $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - - $alias = $name; - if ($stream->nextIf('as')) { - $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - } - - $targets[$name] = new Twig_Node_Expression_Constant($alias, -1); - - if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { - break; - } - } while (true); - } - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets)))); - - return new Twig_Node(); - } - - public function getTag() - { - return 'use'; - } -} - -class_alias('Twig_TokenParser_Use', 'Twig\TokenParser\UseTokenParser', false); diff --git a/inc/lib/Twig/TokenParser/With.php b/inc/lib/Twig/TokenParser/With.php deleted file mode 100644 index 7a692597..00000000 --- a/inc/lib/Twig/TokenParser/With.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * @final - */ -class Twig_TokenParser_With extends Twig_TokenParser -{ - public function parse(Twig_Token $token) - { - $stream = $this->parser->getStream(); - - $variables = null; - $only = false; - if (!$stream->test(Twig_Token::BLOCK_END_TYPE)) { - $variables = $this->parser->getExpressionParser()->parseExpression(); - $only = $stream->nextIf(Twig_Token::NAME_TYPE, 'only'); - } - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - $body = $this->parser->subparse(array($this, 'decideWithEnd'), true); - - $stream->expect(Twig_Token::BLOCK_END_TYPE); - - return new Twig_Node_With($body, $variables, $only, $token->getLine(), $this->getTag()); - } - - public function decideWithEnd(Twig_Token $token) - { - return $token->test('endwith'); - } - - public function getTag() - { - return 'with'; - } -} - -class_alias('Twig_TokenParser_With', 'Twig\TokenParser\WithTokenParser', false); diff --git a/inc/lib/Twig/TokenParserBroker.php b/inc/lib/Twig/TokenParserBroker.php deleted file mode 100644 index 0d7d6e52..00000000 --- a/inc/lib/Twig/TokenParserBroker.php +++ /dev/null @@ -1,120 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface -{ - protected $parser; - protected $parsers = array(); - protected $brokers = array(); - - /** - * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances - * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances - * @param bool $triggerDeprecationError - */ - public function __construct($parsers = array(), $brokers = array(), $triggerDeprecationError = true) - { - if ($triggerDeprecationError) { - @trigger_error('The '.__CLASS__.' class is deprecated since version 1.12 and will be removed in 2.0.', E_USER_DEPRECATED); - } - - foreach ($parsers as $parser) { - if (!$parser instanceof Twig_TokenParserInterface) { - throw new LogicException('$parsers must a an array of Twig_TokenParserInterface.'); - } - $this->parsers[$parser->getTag()] = $parser; - } - foreach ($brokers as $broker) { - if (!$broker instanceof Twig_TokenParserBrokerInterface) { - throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface.'); - } - $this->brokers[] = $broker; - } - } - - public function addTokenParser(Twig_TokenParserInterface $parser) - { - $this->parsers[$parser->getTag()] = $parser; - } - - public function removeTokenParser(Twig_TokenParserInterface $parser) - { - $name = $parser->getTag(); - if (isset($this->parsers[$name]) && $parser === $this->parsers[$name]) { - unset($this->parsers[$name]); - } - } - - public function addTokenParserBroker(self $broker) - { - $this->brokers[] = $broker; - } - - public function removeTokenParserBroker(self $broker) - { - if (false !== $pos = array_search($broker, $this->brokers)) { - unset($this->brokers[$pos]); - } - } - - /** - * Gets a suitable TokenParser for a tag. - * - * First looks in parsers, then in brokers. - * - * @param string $tag A tag name - * - * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found - */ - public function getTokenParser($tag) - { - if (isset($this->parsers[$tag])) { - return $this->parsers[$tag]; - } - $broker = end($this->brokers); - while (false !== $broker) { - $parser = $broker->getTokenParser($tag); - if (null !== $parser) { - return $parser; - } - $broker = prev($this->brokers); - } - } - - public function getParsers() - { - return $this->parsers; - } - - public function getParser() - { - return $this->parser; - } - - public function setParser(Twig_ParserInterface $parser) - { - $this->parser = $parser; - foreach ($this->parsers as $tokenParser) { - $tokenParser->setParser($parser); - } - foreach ($this->brokers as $broker) { - $broker->setParser($parser); - } - } -} diff --git a/inc/lib/Twig/TokenParserBrokerInterface.php b/inc/lib/Twig/TokenParserBrokerInterface.php deleted file mode 100644 index 6c93f5ea..00000000 --- a/inc/lib/Twig/TokenParserBrokerInterface.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -interface Twig_TokenParserBrokerInterface -{ - /** - * Gets a TokenParser suitable for a tag. - * - * @param string $tag A tag name - * - * @return Twig_TokenParserInterface|null A Twig_TokenParserInterface or null if no suitable TokenParser was found - */ - public function getTokenParser($tag); - - /** - * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of. - */ - public function setParser(Twig_ParserInterface $parser); - - /** - * Gets the Twig_ParserInterface. - * - * @return null|Twig_ParserInterface A Twig_ParserInterface instance or null - */ - public function getParser(); -} diff --git a/inc/lib/Twig/TokenParserInterface.php b/inc/lib/Twig/TokenParserInterface.php deleted file mode 100644 index 14acc808..00000000 --- a/inc/lib/Twig/TokenParserInterface.php +++ /dev/null @@ -1,43 +0,0 @@ - - */ -interface Twig_TokenParserInterface -{ - /** - * Sets the parser associated with this token parser. - */ - public function setParser(Twig_Parser $parser); - - /** - * Parses a token and returns a node. - * - * @return Twig_NodeInterface - * - * @throws Twig_Error_Syntax - */ - public function parse(Twig_Token $token); - - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ - public function getTag(); -} - -class_alias('Twig_TokenParserInterface', 'Twig\TokenParser\TokenParserInterface', false); -class_exists('Twig_Parser'); -class_exists('Twig_Token'); diff --git a/inc/lib/Twig/TokenStream.php b/inc/lib/Twig/TokenStream.php deleted file mode 100644 index 81c043ca..00000000 --- a/inc/lib/Twig/TokenStream.php +++ /dev/null @@ -1,196 +0,0 @@ - - */ -class Twig_TokenStream -{ - protected $tokens; - protected $current = 0; - protected $filename; - - private $source; - - /** - * @param array $tokens An array of tokens - * @param string|null $name The name of the template which tokens are associated with - * @param string|null $source The source code associated with the tokens - */ - public function __construct(array $tokens, $name = null, $source = null) - { - if (!$name instanceof Twig_Source) { - if (null !== $name || null !== $source) { - @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED); - } - $this->source = new Twig_Source($source, $name); - } else { - $this->source = $name; - } - - $this->tokens = $tokens; - - // deprecated, not used anymore, to be removed in 2.0 - $this->filename = $this->source->getName(); - } - - public function __toString() - { - return implode("\n", $this->tokens); - } - - public function injectTokens(array $tokens) - { - $this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current)); - } - - /** - * Sets the pointer to the next token and returns the old one. - * - * @return Twig_Token - */ - public function next() - { - if (!isset($this->tokens[++$this->current])) { - throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source); - } - - return $this->tokens[$this->current - 1]; - } - - /** - * Tests a token, sets the pointer to the next one and returns it or throws a syntax error. - * - * @return Twig_Token|null The next token if the condition is true, null otherwise - */ - public function nextIf($primary, $secondary = null) - { - if ($this->tokens[$this->current]->test($primary, $secondary)) { - return $this->next(); - } - } - - /** - * Tests a token and returns it or throws a syntax error. - * - * @return Twig_Token - */ - public function expect($type, $value = null, $message = null) - { - $token = $this->tokens[$this->current]; - if (!$token->test($type, $value)) { - $line = $token->getLine(); - throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s).', - $message ? $message.'. ' : '', - Twig_Token::typeToEnglish($token->getType()), $token->getValue(), - Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''), - $line, - $this->source - ); - } - $this->next(); - - return $token; - } - - /** - * Looks at the next token. - * - * @param int $number - * - * @return Twig_Token - */ - public function look($number = 1) - { - if (!isset($this->tokens[$this->current + $number])) { - throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source); - } - - return $this->tokens[$this->current + $number]; - } - - /** - * Tests the current token. - * - * @return bool - */ - public function test($primary, $secondary = null) - { - return $this->tokens[$this->current]->test($primary, $secondary); - } - - /** - * Checks if end of stream was reached. - * - * @return bool - */ - public function isEOF() - { - return Twig_Token::EOF_TYPE === $this->tokens[$this->current]->getType(); - } - - /** - * @return Twig_Token - */ - public function getCurrent() - { - return $this->tokens[$this->current]; - } - - /** - * Gets the name associated with this stream (null if not defined). - * - * @return string|null - * - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->source->getName(); - } - - /** - * Gets the source code associated with this stream. - * - * @return string - * - * @internal Don't use this as it might be empty depending on the environment configuration - * - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getSource() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->source->getCode(); - } - - /** - * Gets the source associated with this stream. - * - * @return Twig_Source - * - * @internal - */ - public function getSourceContext() - { - return $this->source; - } -} - -class_alias('Twig_TokenStream', 'Twig\TokenStream', false); diff --git a/inc/lib/Twig/Util/DeprecationCollector.php b/inc/lib/Twig/Util/DeprecationCollector.php deleted file mode 100644 index c7bf53be..00000000 --- a/inc/lib/Twig/Util/DeprecationCollector.php +++ /dev/null @@ -1,86 +0,0 @@ - - * - * @final - */ -class Twig_Util_DeprecationCollector -{ - private $twig; - private $deprecations; - - public function __construct(Twig_Environment $twig) - { - $this->twig = $twig; - } - - /** - * Returns deprecations for templates contained in a directory. - * - * @param string $dir A directory where templates are stored - * @param string $ext Limit the loaded templates by extension - * - * @return array An array of deprecations - */ - public function collectDir($dir, $ext = '.twig') - { - $iterator = new RegexIterator( - new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::LEAVES_ONLY - ), '{'.preg_quote($ext).'$}' - ); - - return $this->collect(new Twig_Util_TemplateDirIterator($iterator)); - } - - /** - * Returns deprecations for passed templates. - * - * @param Traversable $iterator An iterator of templates (where keys are template names and values the contents of the template) - * - * @return array An array of deprecations - */ - public function collect(Traversable $iterator) - { - $this->deprecations = array(); - - set_error_handler(array($this, 'errorHandler')); - - foreach ($iterator as $name => $contents) { - try { - $this->twig->parse($this->twig->tokenize(new Twig_Source($contents, $name))); - } catch (Twig_Error_Syntax $e) { - // ignore templates containing syntax errors - } - } - - restore_error_handler(); - - $deprecations = $this->deprecations; - $this->deprecations = array(); - - return $deprecations; - } - - /** - * @internal - */ - public function errorHandler($type, $msg) - { - if (E_USER_DEPRECATED === $type) { - $this->deprecations[] = $msg; - } - } -} - -class_alias('Twig_Util_DeprecationCollector', 'Twig\Util\DeprecationCollector', false); diff --git a/inc/lib/Twig/Util/TemplateDirIterator.php b/inc/lib/Twig/Util/TemplateDirIterator.php deleted file mode 100644 index c8682335..00000000 --- a/inc/lib/Twig/Util/TemplateDirIterator.php +++ /dev/null @@ -1,28 +0,0 @@ - - */ -class Twig_Util_TemplateDirIterator extends IteratorIterator -{ - public function current() - { - return file_get_contents(parent::current()); - } - - public function key() - { - return (string) parent::key(); - } -} - -class_alias('Twig_Util_TemplateDirIterator', 'Twig\Util\TemplateDirIterator', false); diff --git a/inc/lib/minify/FirePHP.php b/inc/lib/minify/FirePHP.php deleted file mode 100755 index d301a641..00000000 --- a/inc/lib/minify/FirePHP.php +++ /dev/null @@ -1,1370 +0,0 @@ - - * @license http://www.opensource.org/licenses/bsd-license.php - * @package FirePHP - */ - - -/** - * Sends the given data to the FirePHP Firefox Extension. - * The data can be displayed in the Firebug Console or in the - * "Server" request tab. - * - * For more information see: http://www.firephp.org/ - * - * @copyright Copyright (C) 2007-2008 Christoph Dorn - * @author Christoph Dorn - * @license http://www.opensource.org/licenses/bsd-license.php - * @package FirePHP - */ -class FirePHP { - - /** - * FirePHP version - * - * @var string - */ - const VERSION = '0.2.0'; - - /** - * Firebug LOG level - * - * Logs a message to firebug console. - * - * @var string - */ - const LOG = 'LOG'; - - /** - * Firebug INFO level - * - * Logs a message to firebug console and displays an info icon before the message. - * - * @var string - */ - const INFO = 'INFO'; - - /** - * Firebug WARN level - * - * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. - * - * @var string - */ - const WARN = 'WARN'; - - /** - * Firebug ERROR level - * - * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. - * - * @var string - */ - const ERROR = 'ERROR'; - - /** - * Dumps a variable to firebug's server panel - * - * @var string - */ - const DUMP = 'DUMP'; - - /** - * Displays a stack trace in firebug console - * - * @var string - */ - const TRACE = 'TRACE'; - - /** - * Displays an exception in firebug console - * - * Increments the firebug error count. - * - * @var string - */ - const EXCEPTION = 'EXCEPTION'; - - /** - * Displays an table in firebug console - * - * @var string - */ - const TABLE = 'TABLE'; - - /** - * Starts a group in firebug console - * - * @var string - */ - const GROUP_START = 'GROUP_START'; - - /** - * Ends a group in firebug console - * - * @var string - */ - const GROUP_END = 'GROUP_END'; - - /** - * Singleton instance of FirePHP - * - * @var FirePHP - */ - protected static $instance = null; - - /** - * Wildfire protocol message index - * - * @var int - */ - protected $messageIndex = 1; - - /** - * Options for the library - * - * @var array - */ - protected $options = array(); - - /** - * Filters used to exclude object members when encoding - * - * @var array - */ - protected $objectFilters = array(); - - /** - * A stack of objects used to detect recursion during object encoding - * - * @var object - */ - protected $objectStack = array(); - - /** - * Flag to enable/disable logging - * - * @var boolean - */ - protected $enabled = true; - - /** - * The object constructor - */ - function __construct() { - $this->options['maxObjectDepth'] = 10; - $this->options['maxArrayDepth'] = 20; - $this->options['useNativeJsonEncode'] = true; - $this->options['includeLineNumbers'] = true; - } - - /** - * When the object gets serialized only include specific object members. - * - * @return array - */ - public function __sleep() { - return array('options','objectFilters','enabled'); - } - - /** - * Gets singleton instance of FirePHP - * - * @param boolean $AutoCreate - * @return FirePHP - */ - public static function getInstance($AutoCreate=false) { - if($AutoCreate===true && !self::$instance) { - self::init(); - } - return self::$instance; - } - - /** - * Creates FirePHP object and stores it for singleton access - * - * @return FirePHP - */ - public static function init() { - return self::$instance = new self(); - } - - /** - * Enable and disable logging to Firebug - * - * @param boolean $Enabled TRUE to enable, FALSE to disable - * @return void - */ - public function setEnabled($Enabled) { - $this->enabled = $Enabled; - } - - /** - * Check if logging is enabled - * - * @return boolean TRUE if enabled - */ - public function getEnabled() { - return $this->enabled; - } - - /** - * Specify a filter to be used when encoding an object - * - * Filters are used to exclude object members. - * - * @param string $Class The class name of the object - * @param array $Filter An array or members to exclude - * @return void - */ - public function setObjectFilter($Class, $Filter) { - $this->objectFilters[$Class] = $Filter; - } - - /** - * Set some options for the library - * - * Options: - * - maxObjectDepth: The maximum depth to traverse objects (default: 10) - * - maxArrayDepth: The maximum depth to traverse arrays (default: 20) - * - useNativeJsonEncode: If true will use json_encode() (default: true) - * - includeLineNumbers: If true will include line numbers and filenames (default: true) - * - * @param array $Options The options to be set - * @return void - */ - public function setOptions($Options) { - $this->options = array_merge($this->options,$Options); - } - - /** - * Register FirePHP as your error handler - * - * Will throw exceptions for each php error. - */ - public function registerErrorHandler() - { - //NOTE: The following errors will not be caught by this error handler: - // E_ERROR, E_PARSE, E_CORE_ERROR, - // E_CORE_WARNING, E_COMPILE_ERROR, - // E_COMPILE_WARNING, E_STRICT - - set_error_handler(array($this,'errorHandler')); - } - - /** - * FirePHP's error handler - * - * Throws exception for each php error that will occur. - * - * @param int $errno - * @param string $errstr - * @param string $errfile - * @param int $errline - * @param array $errcontext - */ - public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) - { - // Don't throw exception if error reporting is switched off - if (error_reporting() == 0) { - return; - } - // Only throw exceptions for errors we are asking for - if (error_reporting() & $errno) { - throw new ErrorException($errstr, 0, $errno, $errfile, $errline); - } - } - - /** - * Register FirePHP as your exception handler - */ - public function registerExceptionHandler() - { - set_exception_handler(array($this,'exceptionHandler')); - } - - /** - * FirePHP's exception handler - * - * Logs all exceptions to your firebug console and then stops the script. - * - * @param Exception $Exception - * @throws Exception - */ - function exceptionHandler($Exception) { - $this->fb($Exception); - } - - /** - * Set custom processor url for FirePHP - * - * @param string $URL - */ - public function setProcessorUrl($URL) - { - $this->setHeader('X-FirePHP-ProcessorURL', $URL); - } - - /** - * Set custom renderer url for FirePHP - * - * @param string $URL - */ - public function setRendererUrl($URL) - { - $this->setHeader('X-FirePHP-RendererURL', $URL); - } - - /** - * Start a group for following messages - * - * @param string $Name - * @return true - * @throws Exception - */ - public function group($Name) { - return $this->fb(null, $Name, FirePHP::GROUP_START); - } - - /** - * Ends a group you have started before - * - * @return true - * @throws Exception - */ - public function groupEnd() { - return $this->fb(null, null, FirePHP::GROUP_END); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::LOG - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function log($Object, $Label=null) { - return $this->fb($Object, $Label, FirePHP::LOG); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::INFO - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function info($Object, $Label=null) { - return $this->fb($Object, $Label, FirePHP::INFO); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::WARN - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function warn($Object, $Label=null) { - return $this->fb($Object, $Label, FirePHP::WARN); - } - - /** - * Log object with label to firebug console - * - * @see FirePHP::ERROR - * @param mixes $Object - * @param string $Label - * @return true - * @throws Exception - */ - public function error($Object, $Label=null) { - return $this->fb($Object, $Label, FirePHP::ERROR); - } - - /** - * Dumps key and variable to firebug server panel - * - * @see FirePHP::DUMP - * @param string $Key - * @param mixed $Variable - * @return true - * @throws Exception - */ - public function dump($Key, $Variable) { - return $this->fb($Variable, $Key, FirePHP::DUMP); - } - - /** - * Log a trace in the firebug console - * - * @see FirePHP::TRACE - * @param string $Label - * @return true - * @throws Exception - */ - public function trace($Label) { - return $this->fb($Label, FirePHP::TRACE); - } - - /** - * Log a table in the firebug console - * - * @see FirePHP::TABLE - * @param string $Label - * @param string $Table - * @return true - * @throws Exception - */ - public function table($Label, $Table) { - return $this->fb($Table, $Label, FirePHP::TABLE); - } - - /** - * Check if FirePHP is installed on client - * - * @return boolean - */ - public function detectClientExtension() { - /* Check if FirePHP is installed on client */ - if(!@preg_match_all('/\sFirePHP\/([\.|\d]*)\s?/si',$this->getUserAgent(),$m) || - !version_compare($m[1][0],'0.0.6','>=')) { - return false; - } - return true; - } - - /** - * Log varible to Firebug - * - * @see http://www.firephp.org/Wiki/Reference/Fb - * @param mixed $Object The variable to be logged - * @return true Return TRUE if message was added to headers, FALSE otherwise - * @throws Exception - */ - public function fb($Object) { - - if(!$this->enabled) { - return false; - } - - if (headers_sent($filename, $linenum)) { - throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); - } - - $Type = null; - $Label = null; - - if(func_num_args()==1) { - } else - if(func_num_args()==2) { - switch(func_get_arg(1)) { - case self::LOG: - case self::INFO: - case self::WARN: - case self::ERROR: - case self::DUMP: - case self::TRACE: - case self::EXCEPTION: - case self::TABLE: - case self::GROUP_START: - case self::GROUP_END: - $Type = func_get_arg(1); - break; - default: - $Label = func_get_arg(1); - break; - } - } else - if(func_num_args()==3) { - $Type = func_get_arg(2); - $Label = func_get_arg(1); - } else { - throw $this->newException('Wrong number of arguments to fb() function!'); - } - - - if(!$this->detectClientExtension()) { - return false; - } - - $meta = array(); - $skipFinalObjectEncode = false; - - if($Object instanceof Exception) { - - $meta['file'] = $this->_escapeTraceFile($Object->getFile()); - $meta['line'] = $Object->getLine(); - - $trace = $Object->getTrace(); - if($Object instanceof ErrorException - && isset($trace[0]['function']) - && $trace[0]['function']=='errorHandler' - && isset($trace[0]['class']) - && $trace[0]['class']=='FirePHP') { - - $severity = false; - switch($Object->getSeverity()) { - case E_WARNING: $severity = 'E_WARNING'; break; - case E_NOTICE: $severity = 'E_NOTICE'; break; - case E_USER_ERROR: $severity = 'E_USER_ERROR'; break; - case E_USER_WARNING: $severity = 'E_USER_WARNING'; break; - case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break; - case E_STRICT: $severity = 'E_STRICT'; break; - case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break; - case E_DEPRECATED: $severity = 'E_DEPRECATED'; break; - case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break; - } - - $Object = array('Class'=>get_class($Object), - 'Message'=>$severity.': '.$Object->getMessage(), - 'File'=>$this->_escapeTraceFile($Object->getFile()), - 'Line'=>$Object->getLine(), - 'Type'=>'trigger', - 'Trace'=>$this->_escapeTrace(array_splice($trace,2))); - $skipFinalObjectEncode = true; - } else { - $Object = array('Class'=>get_class($Object), - 'Message'=>$Object->getMessage(), - 'File'=>$this->_escapeTraceFile($Object->getFile()), - 'Line'=>$Object->getLine(), - 'Type'=>'throw', - 'Trace'=>$this->_escapeTrace($trace)); - $skipFinalObjectEncode = true; - } - $Type = self::EXCEPTION; - - } else - if($Type==self::TRACE) { - - $trace = debug_backtrace(); - if(!$trace) return false; - for( $i=0 ; $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' - || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { - /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ - } else - if(isset($trace[$i]['class']) - && isset($trace[$i+1]['file']) - && $trace[$i]['class']=='FirePHP' - && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { - /* Skip fb() */ - } else - if($trace[$i]['function']=='fb' - || $trace[$i]['function']=='trace' - || $trace[$i]['function']=='send') { - $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'', - 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'', - 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'', - 'Message'=>$trace[$i]['args'][0], - 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'', - 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'', - 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'', - 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1))); - - $skipFinalObjectEncode = true; - $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; - $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; - break; - } - } - - } else - if($Type==self::TABLE) { - - if(isset($Object[0]) && is_string($Object[0])) { - $Object[1] = $this->encodeTable($Object[1]); - } else { - $Object = $this->encodeTable($Object); - } - - $skipFinalObjectEncode = true; - - } else { - if($Type===null) { - $Type = self::LOG; - } - } - - if($this->options['includeLineNumbers']) { - if(!isset($meta['file']) || !isset($meta['line'])) { - - $trace = debug_backtrace(); - for( $i=0 ; $trace && $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' - || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { - /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ - } else - if(isset($trace[$i]['class']) - && isset($trace[$i+1]['file']) - && $trace[$i]['class']=='FirePHP' - && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { - /* Skip fb() */ - } else - if(isset($trace[$i]['file']) - && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') { - /* Skip FB::fb() */ - } else { - $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; - $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; - break; - } - } - - } - } else { - unset($meta['file']); - unset($meta['line']); - } - - $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); - $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION); - - $structure_index = 1; - if($Type==self::DUMP) { - $structure_index = 2; - $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); - } else { - $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); - } - - if($Type==self::DUMP) { - $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}'; - } else { - $msg_meta = array('Type'=>$Type); - if($Label!==null) { - $msg_meta['Label'] = $Label; - } - if(isset($meta['file'])) { - $msg_meta['File'] = $meta['file']; - } - if(isset($meta['line'])) { - $msg_meta['Line'] = $meta['line']; - } - $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']'; - } - - $parts = explode("\n",chunk_split($msg, 5000, "\n")); - - for( $i=0 ; $i2) { - // Message needs to be split into multiple parts - $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, - (($i==0)?strlen($msg):'') - . '|' . $part . '|' - . (($isetHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, - strlen($part) . '|' . $part . '|'); - } - - $this->messageIndex++; - - if ($this->messageIndex > 99999) { - throw new Exception('Maximum number (99,999) of messages reached!'); - } - } - } - - $this->setHeader('X-Wf-1-Index',$this->messageIndex-1); - - return true; - } - - /** - * Standardizes path for windows systems. - * - * @param string $Path - * @return string - */ - protected function _standardizePath($Path) { - return preg_replace('/\\\\+/','/',$Path); - } - - /** - * Escape trace path for windows systems - * - * @param array $Trace - * @return array - */ - protected function _escapeTrace($Trace) { - if(!$Trace) return $Trace; - for( $i=0 ; $i_escapeTraceFile($Trace[$i]['file']); - } - if(isset($Trace[$i]['args'])) { - $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']); - } - } - return $Trace; - } - - /** - * Escape file information of trace for windows systems - * - * @param string $File - * @return string - */ - protected function _escapeTraceFile($File) { - /* Check if we have a windows filepath */ - if(strpos($File,'\\')) { - /* First strip down to single \ */ - - $file = preg_replace('/\\\\+/','\\',$File); - - return $file; - } - return $File; - } - - /** - * Send header - * - * @param string $Name - * @param string_type $Value - */ - protected function setHeader($Name, $Value) { - return header($Name.': '.$Value); - } - - /** - * Get user agent - * - * @return string|false - */ - protected function getUserAgent() { - if(!isset($_SERVER['HTTP_USER_AGENT'])) return false; - return $_SERVER['HTTP_USER_AGENT']; - } - - /** - * Returns a new exception - * - * @param string $Message - * @return Exception - */ - protected function newException($Message) { - return new Exception($Message); - } - - /** - * Encode an object into a JSON string - * - * Uses PHP's jeson_encode() if available - * - * @param object $Object The object to be encoded - * @return string The JSON string - */ - protected function jsonEncode($Object, $skipObjectEncode=false) - { - if(!$skipObjectEncode) { - $Object = $this->encodeObject($Object); - } - - if(function_exists('json_encode') - && $this->options['useNativeJsonEncode']!=false) { - - return json_encode($Object); - } else { - return $this->json_encode($Object); - } - } - - /** - * Encodes a table by encoding each row and column with encodeObject() - * - * @param array $Table The table to be encoded - * @return array - */ - protected function encodeTable($Table) { - if(!$Table) return $Table; - for( $i=0 ; $iencodeObject($Table[$i][$j]); - } - } - } - return $Table; - } - - /** - * Encodes an object including members with - * protected and private visibility - * - * @param Object $Object The object to be encoded - * @param int $Depth The current traversal depth - * @return array All members of the object - */ - protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1) - { - $return = array(); - - if (is_object($Object)) { - - if ($ObjectDepth > $this->options['maxObjectDepth']) { - return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **'; - } - - foreach ($this->objectStack as $refVal) { - if ($refVal === $Object) { - return '** Recursion ('.get_class($Object).') **'; - } - } - array_push($this->objectStack, $Object); - - $return['__className'] = $class = get_class($Object); - - $reflectionClass = new ReflectionClass($class); - $properties = array(); - foreach( $reflectionClass->getProperties() as $property) { - $properties[$property->getName()] = $property; - } - - $members = (array)$Object; - - foreach( $properties as $raw_name => $property ) { - - $name = $raw_name; - if($property->isStatic()) { - $name = 'static:'.$name; - } - if($property->isPublic()) { - $name = 'public:'.$name; - } else - if($property->isPrivate()) { - $name = 'private:'.$name; - $raw_name = "\0".$class."\0".$raw_name; - } else - if($property->isProtected()) { - $name = 'protected:'.$name; - $raw_name = "\0".'*'."\0".$raw_name; - } - - if(!(isset($this->objectFilters[$class]) - && is_array($this->objectFilters[$class]) - && in_array($raw_name,$this->objectFilters[$class]))) { - - if(array_key_exists($raw_name,$members) - && !$property->isStatic()) { - - $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1); - - } else { - if(method_exists($property,'setAccessible')) { - $property->setAccessible(true); - $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1); - } else - if($property->isPublic()) { - $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1); - } else { - $return[$name] = '** Need PHP 5.3 to get value **'; - } - } - } else { - $return[$name] = '** Excluded by Filter **'; - } - } - - // Include all members that are not defined in the class - // but exist in the object - foreach( $members as $raw_name => $value ) { - - $name = $raw_name; - - if ($name{0} == "\0") { - $parts = explode("\0", $name); - $name = $parts[2]; - } - - if(!isset($properties[$name])) { - $name = 'undeclared:'.$name; - - if(!(isset($this->objectFilters[$class]) - && is_array($this->objectFilters[$class]) - && in_array($raw_name,$this->objectFilters[$class]))) { - - $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1); - } else { - $return[$name] = '** Excluded by Filter **'; - } - } - } - - array_pop($this->objectStack); - - } elseif (is_array($Object)) { - - if ($ArrayDepth > $this->options['maxArrayDepth']) { - return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **'; - } - - foreach ($Object as $key => $val) { - - // Encoding the $GLOBALS PHP array causes an infinite loop - // if the recursion is not reset here as it contains - // a reference to itself. This is the only way I have come up - // with to stop infinite recursion in this case. - if($key=='GLOBALS' - && is_array($val) - && array_key_exists('GLOBALS',$val)) { - $val['GLOBALS'] = '** Recursion (GLOBALS) **'; - } - - $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1); - } - } else { - if(self::is_utf8($Object)) { - return $Object; - } else { - return utf8_encode($Object); - } - } - return $return; - } - - /** - * Returns true if $string is valid UTF-8 and false otherwise. - * - * @param mixed $str String to be tested - * @return boolean - */ - protected static function is_utf8($str) { - $c=0; $b=0; - $bits=0; - $len=strlen($str); - for($i=0; $i<$len; $i++){ - $c=ord($str[$i]); - if($c > 128){ - if(($c >= 254)) return false; - elseif($c >= 252) $bits=6; - elseif($c >= 248) $bits=5; - elseif($c >= 240) $bits=4; - elseif($c >= 224) $bits=3; - elseif($c >= 192) $bits=2; - else return false; - if(($i+$bits) > $len) return false; - while($bits > 1){ - $i++; - $b=ord($str[$i]); - if($b < 128 || $b > 191) return false; - $bits--; - } - } - } - return true; - } - - /** - * Converts to and from JSON format. - * - * JSON (JavaScript Object Notation) is a lightweight data-interchange - * format. It is easy for humans to read and write. It is easy for machines - * to parse and generate. It is based on a subset of the JavaScript - * Programming Language, Standard ECMA-262 3rd Edition - December 1999. - * This feature can also be found in Python. JSON is a text format that is - * completely language independent but uses conventions that are familiar - * to programmers of the C-family of languages, including C, C++, C#, Java, - * JavaScript, Perl, TCL, and many others. These properties make JSON an - * ideal data-interchange language. - * - * This package provides a simple encoder and decoder for JSON notation. It - * is intended for use with client-side Javascript applications that make - * use of HTTPRequest to perform server communication functions - data can - * be encoded into JSON notation for use in a client-side javascript, or - * decoded from incoming Javascript requests. JSON format is native to - * Javascript, and can be directly eval()'ed with no further parsing - * overhead - * - * All strings should be in ASCII or UTF-8 format! - * - * LICENSE: Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: Redistributions of source code must retain the - * above copyright notice, this list of conditions and the following - * disclaimer. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * @category - * @package Services_JSON - * @author Michal Migurski - * @author Matt Knapp - * @author Brett Stimmerman - * @author Christoph Dorn - * @copyright 2005 Michal Migurski - * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ - * @license http://www.opensource.org/licenses/bsd-license.php - * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 - */ - - - /** - * Keep a list of objects as we descend into the array so we can detect recursion. - */ - private $json_objectStack = array(); - - - /** - * convert a string from one UTF-8 char to one UTF-16 char - * - * Normally should be handled by mb_convert_encoding, but - * provides a slower PHP-only method for installations - * that lack the multibye string extension. - * - * @param string $utf8 UTF-8 character - * @return string UTF-16 character - * @access private - */ - private function json_utf82utf16($utf8) - { - // oh please oh please oh please oh please oh please - if(function_exists('mb_convert_encoding')) { - return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); - } - - switch(strlen($utf8)) { - case 1: - // this case should never be reached, because we are in ASCII range - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return $utf8; - - case 2: - // return a UTF-16 character from a 2-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr(0x07 & (ord($utf8{0}) >> 2)) - . chr((0xC0 & (ord($utf8{0}) << 6)) - | (0x3F & ord($utf8{1}))); - - case 3: - // return a UTF-16 character from a 3-byte UTF-8 char - // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - return chr((0xF0 & (ord($utf8{0}) << 4)) - | (0x0F & (ord($utf8{1}) >> 2))) - . chr((0xC0 & (ord($utf8{1}) << 6)) - | (0x7F & ord($utf8{2}))); - } - - // ignoring UTF-32 for now, sorry - return ''; - } - - /** - * encodes an arbitrary variable into JSON format - * - * @param mixed $var any number, boolean, string, array, or object to be encoded. - * see argument 1 to Services_JSON() above for array-parsing behavior. - * if var is a strng, note that encode() always expects it - * to be in ASCII or UTF-8 format! - * - * @return mixed JSON string representation of input var or an error if a problem occurs - * @access public - */ - private function json_encode($var) - { - - if(is_object($var)) { - if(in_array($var,$this->json_objectStack)) { - return '"** Recursion **"'; - } - } - - switch (gettype($var)) { - case 'boolean': - return $var ? 'true' : 'false'; - - case 'NULL': - return 'null'; - - case 'integer': - return (int) $var; - - case 'double': - case 'float': - return (float) $var; - - case 'string': - // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT - $ascii = ''; - $strlen_var = strlen($var); - - /* - * Iterate over every character in the string, - * escaping with a slash or encoding to UTF-8 where necessary - */ - for ($c = 0; $c < $strlen_var; ++$c) { - - $ord_var_c = ord($var{$c}); - - switch (true) { - case $ord_var_c == 0x08: - $ascii .= '\b'; - break; - case $ord_var_c == 0x09: - $ascii .= '\t'; - break; - case $ord_var_c == 0x0A: - $ascii .= '\n'; - break; - case $ord_var_c == 0x0C: - $ascii .= '\f'; - break; - case $ord_var_c == 0x0D: - $ascii .= '\r'; - break; - - case $ord_var_c == 0x22: - case $ord_var_c == 0x2F: - case $ord_var_c == 0x5C: - // double quote, slash, slosh - $ascii .= '\\'.$var{$c}; - break; - - case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): - // characters U-00000000 - U-0000007F (same as ASCII) - $ascii .= $var{$c}; - break; - - case (($ord_var_c & 0xE0) == 0xC0): - // characters U-00000080 - U-000007FF, mask 110XXXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, ord($var{$c + 1})); - $c += 1; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF0) == 0xE0): - // characters U-00000800 - U-0000FFFF, mask 1110XXXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2})); - $c += 2; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xF8) == 0xF0): - // characters U-00010000 - U-001FFFFF, mask 11110XXX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3})); - $c += 3; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFC) == 0xF8): - // characters U-00200000 - U-03FFFFFF, mask 111110XX - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4})); - $c += 4; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - - case (($ord_var_c & 0xFE) == 0xFC): - // characters U-04000000 - U-7FFFFFFF, mask 1111110X - // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - $char = pack('C*', $ord_var_c, - ord($var{$c + 1}), - ord($var{$c + 2}), - ord($var{$c + 3}), - ord($var{$c + 4}), - ord($var{$c + 5})); - $c += 5; - $utf16 = $this->json_utf82utf16($char); - $ascii .= sprintf('\u%04s', bin2hex($utf16)); - break; - } - } - - return '"'.$ascii.'"'; - - case 'array': - /* - * As per JSON spec if any array key is not an integer - * we must treat the the whole array as an object. We - * also try to catch a sparsely populated associative - * array with numeric keys here because some JS engines - * will create an array with empty indexes up to - * max_index which can cause memory issues and because - * the keys, which may be relevant, will be remapped - * otherwise. - * - * As per the ECMA and JSON specification an object may - * have any string as a property. Unfortunately due to - * a hole in the ECMA specification if the key is a - * ECMA reserved word or starts with a digit the - * parameter is only accessible using ECMAScript's - * bracket notation. - */ - - // treat as a JSON object - if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { - - $this->json_objectStack[] = $var; - - $properties = array_map(array($this, 'json_name_value'), - array_keys($var), - array_values($var)); - - array_pop($this->json_objectStack); - - foreach($properties as $property) { - if($property instanceof Exception) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - } - - $this->json_objectStack[] = $var; - - // treat it like a regular array - $elements = array_map(array($this, 'json_encode'), $var); - - array_pop($this->json_objectStack); - - foreach($elements as $element) { - if($element instanceof Exception) { - return $element; - } - } - - return '[' . join(',', $elements) . ']'; - - case 'object': - $vars = self::encodeObject($var); - - $this->json_objectStack[] = $var; - - $properties = array_map(array($this, 'json_name_value'), - array_keys($vars), - array_values($vars)); - - array_pop($this->json_objectStack); - - foreach($properties as $property) { - if($property instanceof Exception) { - return $property; - } - } - - return '{' . join(',', $properties) . '}'; - - default: - return null; - } - } - - /** - * array-walking function for use in generating JSON-formatted name-value pairs - * - * @param string $name name of key to use - * @param mixed $value reference to an array element to be encoded - * - * @return string JSON-formatted name-value pair, like '"name":value' - * @access private - */ - private function json_name_value($name, $value) - { - // Encoding the $GLOBALS PHP array causes an infinite loop - // if the recursion is not reset here as it contains - // a reference to itself. This is the only way I have come up - // with to stop infinite recursion in this case. - if($name=='GLOBALS' - && is_array($value) - && array_key_exists('GLOBALS',$value)) { - $value['GLOBALS'] = '** Recursion **'; - } - - $encoded_value = $this->json_encode($value); - - if($encoded_value instanceof Exception) { - return $encoded_value; - } - - return $this->json_encode(strval($name)) . ':' . $encoded_value; - } -} diff --git a/inc/lib/minify/HTTP/ConditionalGet.php b/inc/lib/minify/HTTP/ConditionalGet.php deleted file mode 100755 index 93b7e75d..00000000 --- a/inc/lib/minify/HTTP/ConditionalGet.php +++ /dev/null @@ -1,366 +0,0 @@ - - * list($updateTime, $content) = getDbUpdateAndContent(); - * $cg = new HTTP_ConditionalGet(array( - * 'lastModifiedTime' => $updateTime - * ,'isPublic' => true - * )); - * $cg->sendHeaders(); - * if ($cg->cacheIsValid) { - * exit(); - * } - * echo $content; - * - * - * E.g. Shortcut for the above - * - * HTTP_ConditionalGet::check($updateTime, true); // exits if client has cache - * echo $content; - * - * - * E.g. Content from DB with no update time: - * - * $content = getContentFromDB(); - * $cg = new HTTP_ConditionalGet(array( - * 'contentHash' => md5($content) - * )); - * $cg->sendHeaders(); - * if ($cg->cacheIsValid) { - * exit(); - * } - * echo $content; - * - * - * E.g. Static content with some static includes: - * - * // before content - * $cg = new HTTP_ConditionalGet(array( - * 'lastUpdateTime' => max( - * filemtime(__FILE__) - * ,filemtime('/path/to/header.inc') - * ,filemtime('/path/to/footer.inc') - * ) - * )); - * $cg->sendHeaders(); - * if ($cg->cacheIsValid) { - * exit(); - * } - * - * @package Minify - * @subpackage HTTP - * @author Stephen Clay - */ -class HTTP_ConditionalGet { - - /** - * Does the client have a valid copy of the requested resource? - * - * You'll want to check this after instantiating the object. If true, do - * not send content, just call sendHeaders() if you haven't already. - * - * @var bool - */ - public $cacheIsValid = null; - - /** - * @param array $spec options - * - * 'isPublic': (bool) if false, the Cache-Control header will contain - * "private", allowing only browser caching. (default false) - * - * 'lastModifiedTime': (int) if given, both ETag AND Last-Modified headers - * will be sent with content. This is recommended. - * - * 'encoding': (string) if set, the header "Vary: Accept-Encoding" will - * always be sent and a truncated version of the encoding will be appended - * to the ETag. E.g. "pub123456;gz". This will also trigger a more lenient - * checking of the client's If-None-Match header, as the encoding portion of - * the ETag will be stripped before comparison. - * - * 'contentHash': (string) if given, only the ETag header can be sent with - * content (only HTTP1.1 clients can conditionally GET). The given string - * should be short with no quote characters and always change when the - * resource changes (recommend md5()). This is not needed/used if - * lastModifiedTime is given. - * - * 'eTag': (string) if given, this will be used as the ETag header rather - * than values based on lastModifiedTime or contentHash. Also the encoding - * string will not be appended to the given value as described above. - * - * 'invalidate': (bool) if true, the client cache will be considered invalid - * without testing. Effectively this disables conditional GET. - * (default false) - * - * 'maxAge': (int) if given, this will set the Cache-Control max-age in - * seconds, and also set the Expires header to the equivalent GMT date. - * After the max-age period has passed, the browser will again send a - * conditional GET to revalidate its cache. - */ - public function __construct($spec) - { - $scope = (isset($spec['isPublic']) && $spec['isPublic']) - ? 'public' - : 'private'; - $maxAge = 0; - // backwards compatibility (can be removed later) - if (isset($spec['setExpires']) - && is_numeric($spec['setExpires']) - && ! isset($spec['maxAge'])) { - $spec['maxAge'] = $spec['setExpires'] - $_SERVER['REQUEST_TIME']; - } - if (isset($spec['maxAge'])) { - $maxAge = $spec['maxAge']; - $this->_headers['Expires'] = self::gmtDate( - $_SERVER['REQUEST_TIME'] + $spec['maxAge'] - ); - } - $etagAppend = ''; - if (isset($spec['encoding'])) { - $this->_stripEtag = true; - $this->_headers['Vary'] = 'Accept-Encoding'; - if ('' !== $spec['encoding']) { - if (0 === strpos($spec['encoding'], 'x-')) { - $spec['encoding'] = substr($spec['encoding'], 2); - } - $etagAppend = ';' . substr($spec['encoding'], 0, 2); - } - } - if (isset($spec['lastModifiedTime'])) { - $this->_setLastModified($spec['lastModifiedTime']); - if (isset($spec['eTag'])) { // Use it - $this->_setEtag($spec['eTag'], $scope); - } else { // base both headers on time - $this->_setEtag($spec['lastModifiedTime'] . $etagAppend, $scope); - } - } elseif (isset($spec['eTag'])) { // Use it - $this->_setEtag($spec['eTag'], $scope); - } elseif (isset($spec['contentHash'])) { // Use the hash as the ETag - $this->_setEtag($spec['contentHash'] . $etagAppend, $scope); - } - $privacy = ($scope === 'private') - ? ', private' - : ''; - $this->_headers['Cache-Control'] = "max-age={$maxAge}{$privacy}"; - // invalidate cache if disabled, otherwise check - $this->cacheIsValid = (isset($spec['invalidate']) && $spec['invalidate']) - ? false - : $this->_isCacheValid(); - } - - /** - * Get array of output headers to be sent - * - * In the case of 304 responses, this array will only contain the response - * code header: array('_responseCode' => 'HTTP/1.0 304 Not Modified') - * - * Otherwise something like: - * - * array( - * 'Cache-Control' => 'max-age=0, public' - * ,'ETag' => '"foobar"' - * ) - * - * - * @return array - */ - public function getHeaders() - { - return $this->_headers; - } - - /** - * Set the Content-Length header in bytes - * - * With most PHP configs, as long as you don't flush() output, this method - * is not needed and PHP will buffer all output and set Content-Length for - * you. Otherwise you'll want to call this to let the client know up front. - * - * @param int $bytes - * - * @return int copy of input $bytes - */ - public function setContentLength($bytes) - { - return $this->_headers['Content-Length'] = $bytes; - } - - /** - * Send headers - * - * @see getHeaders() - * - * Note this doesn't "clear" the headers. Calling sendHeaders() will - * call header() again (but probably have not effect) and getHeaders() will - * still return the headers. - * - * @return null - */ - public function sendHeaders() - { - $headers = $this->_headers; - if (array_key_exists('_responseCode', $headers)) { - // FastCGI environments require 3rd arg to header() to be set - list(, $code) = explode(' ', $headers['_responseCode'], 3); - header($headers['_responseCode'], true, $code); - unset($headers['_responseCode']); - } - foreach ($headers as $name => $val) { - header($name . ': ' . $val); - } - } - - /** - * Exit if the client's cache is valid for this resource - * - * This is a convenience method for common use of the class - * - * @param int $lastModifiedTime if given, both ETag AND Last-Modified headers - * will be sent with content. This is recommended. - * - * @param bool $isPublic (default false) if true, the Cache-Control header - * will contain "public", allowing proxies to cache the content. Otherwise - * "private" will be sent, allowing only browser caching. - * - * @param array $options (default empty) additional options for constructor - */ - public static function check($lastModifiedTime = null, $isPublic = false, $options = array()) - { - if (null !== $lastModifiedTime) { - $options['lastModifiedTime'] = (int)$lastModifiedTime; - } - $options['isPublic'] = (bool)$isPublic; - $cg = new HTTP_ConditionalGet($options); - $cg->sendHeaders(); - if ($cg->cacheIsValid) { - exit(); - } - } - - - /** - * Get a GMT formatted date for use in HTTP headers - * - * - * header('Expires: ' . HTTP_ConditionalGet::gmtdate($time)); - * - * - * @param int $time unix timestamp - * - * @return string - */ - public static function gmtDate($time) - { - return gmdate('D, d M Y H:i:s \G\M\T', $time); - } - - protected $_headers = array(); - protected $_lmTime = null; - protected $_etag = null; - protected $_stripEtag = false; - - /** - * @param string $hash - * - * @param string $scope - */ - protected function _setEtag($hash, $scope) - { - $this->_etag = '"' . substr($scope, 0, 3) . $hash . '"'; - $this->_headers['ETag'] = $this->_etag; - } - - /** - * @param int $time - */ - protected function _setLastModified($time) - { - $this->_lmTime = (int)$time; - $this->_headers['Last-Modified'] = self::gmtDate($time); - } - - /** - * Determine validity of client cache and queue 304 header if valid - * - * @return bool - */ - protected function _isCacheValid() - { - if (null === $this->_etag) { - // lmTime is copied to ETag, so this condition implies that the - // server sent neither ETag nor Last-Modified, so the client can't - // possibly has a valid cache. - return false; - } - $isValid = ($this->resourceMatchedEtag() || $this->resourceNotModified()); - if ($isValid) { - $this->_headers['_responseCode'] = 'HTTP/1.0 304 Not Modified'; - } - return $isValid; - } - - /** - * @return bool - */ - protected function resourceMatchedEtag() - { - if (!isset($_SERVER['HTTP_IF_NONE_MATCH'])) { - return false; - } - $clientEtagList = get_magic_quotes_gpc() - ? stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) - : $_SERVER['HTTP_IF_NONE_MATCH']; - $clientEtags = explode(',', $clientEtagList); - - $compareTo = $this->normalizeEtag($this->_etag); - foreach ($clientEtags as $clientEtag) { - if ($this->normalizeEtag($clientEtag) === $compareTo) { - // respond with the client's matched ETag, even if it's not what - // we would've sent by default - $this->_headers['ETag'] = trim($clientEtag); - return true; - } - } - return false; - } - - /** - * @param string $etag - * - * @return string - */ - protected function normalizeEtag($etag) { - $etag = trim($etag); - return $this->_stripEtag - ? preg_replace('/;\\w\\w"$/', '"', $etag) - : $etag; - } - - /** - * @return bool - */ - protected function resourceNotModified() - { - if (!isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { - return false; - } - // strip off IE's extra data (semicolon) - list($ifModifiedSince) = explode(';', $_SERVER['HTTP_IF_MODIFIED_SINCE'], 2); - if (strtotime($ifModifiedSince) >= $this->_lmTime) { - // Apache 2.2's behavior. If there was no ETag match, send the - // non-encoded version of the ETag value. - $this->_headers['ETag'] = $this->normalizeEtag($this->_etag); - return true; - } - return false; - } -} diff --git a/inc/lib/minify/HTTP/Encoder.php b/inc/lib/minify/HTTP/Encoder.php deleted file mode 100755 index 8f347793..00000000 --- a/inc/lib/minify/HTTP/Encoder.php +++ /dev/null @@ -1,335 +0,0 @@ - - * // Send a CSS file, compressed if possible - * $he = new HTTP_Encoder(array( - * 'content' => file_get_contents($cssFile) - * ,'type' => 'text/css' - * )); - * $he->encode(); - * $he->sendAll(); - * - * - * - * // Shortcut to encoding output - * header('Content-Type: text/css'); // needed if not HTML - * HTTP_Encoder::output($css); - * - * - * - * // Just sniff for the accepted encoding - * $encoding = HTTP_Encoder::getAcceptedEncoding(); - * - * - * For more control over headers, use getHeaders() and getData() and send your - * own output. - * - * Note: If you don't need header mgmt, use PHP's native gzencode, gzdeflate, - * and gzcompress functions for gzip, deflate, and compress-encoding - * respectively. - * - * @package Minify - * @subpackage HTTP - * @author Stephen Clay - */ -class HTTP_Encoder { - - /** - * Should the encoder allow HTTP encoding to IE6? - * - * If you have many IE6 users and the bandwidth savings is worth troubling - * some of them, set this to true. - * - * By default, encoding is only offered to IE7+. When this is true, - * getAcceptedEncoding() will return an encoding for IE6 if its user agent - * string contains "SV1". This has been documented in many places as "safe", - * but there seem to be remaining, intermittent encoding bugs in patched - * IE6 on the wild web. - * - * @var bool - */ - public static $encodeToIe6 = true; - - - /** - * Default compression level for zlib operations - * - * This level is used if encode() is not given a $compressionLevel - * - * @var int - */ - public static $compressionLevel = 6; - - - /** - * Get an HTTP Encoder object - * - * @param array $spec options - * - * 'content': (string required) content to be encoded - * - * 'type': (string) if set, the Content-Type header will have this value. - * - * 'method: (string) only set this if you are forcing a particular encoding - * method. If not set, the best method will be chosen by getAcceptedEncoding() - * The available methods are 'gzip', 'deflate', 'compress', and '' (no - * encoding) - */ - public function __construct($spec) - { - $this->_useMbStrlen = (function_exists('mb_strlen') - && (ini_get('mbstring.func_overload') !== '') - && ((int)ini_get('mbstring.func_overload') & 2)); - $this->_content = $spec['content']; - $this->_headers['Content-Length'] = $this->_useMbStrlen - ? (string)mb_strlen($this->_content, '8bit') - : (string)strlen($this->_content); - if (isset($spec['type'])) { - $this->_headers['Content-Type'] = $spec['type']; - } - if (isset($spec['method']) - && in_array($spec['method'], array('gzip', 'deflate', 'compress', ''))) - { - $this->_encodeMethod = array($spec['method'], $spec['method']); - } else { - $this->_encodeMethod = self::getAcceptedEncoding(); - } - } - - /** - * Get content in current form - * - * Call after encode() for encoded content. - * - * @return string - */ - public function getContent() - { - return $this->_content; - } - - /** - * Get array of output headers to be sent - * - * E.g. - * - * array( - * 'Content-Length' => '615' - * ,'Content-Encoding' => 'x-gzip' - * ,'Vary' => 'Accept-Encoding' - * ) - * - * - * @return array - */ - public function getHeaders() - { - return $this->_headers; - } - - /** - * Send output headers - * - * You must call this before headers are sent and it probably cannot be - * used in conjunction with zlib output buffering / mod_gzip. Errors are - * not handled purposefully. - * - * @see getHeaders() - */ - public function sendHeaders() - { - foreach ($this->_headers as $name => $val) { - header($name . ': ' . $val); - } - } - - /** - * Send output headers and content - * - * A shortcut for sendHeaders() and echo getContent() - * - * You must call this before headers are sent and it probably cannot be - * used in conjunction with zlib output buffering / mod_gzip. Errors are - * not handled purposefully. - */ - public function sendAll() - { - $this->sendHeaders(); - echo $this->_content; - } - - /** - * Determine the client's best encoding method from the HTTP Accept-Encoding - * header. - * - * If no Accept-Encoding header is set, or the browser is IE before v6 SP2, - * this will return ('', ''), the "identity" encoding. - * - * A syntax-aware scan is done of the Accept-Encoding, so the method must - * be non 0. The methods are favored in order of gzip, deflate, then - * compress. Deflate is always smallest and generally faster, but is - * rarely sent by servers, so client support could be buggier. - * - * @param bool $allowCompress allow the older compress encoding - * - * @param bool $allowDeflate allow the more recent deflate encoding - * - * @return array two values, 1st is the actual encoding method, 2nd is the - * alias of that method to use in the Content-Encoding header (some browsers - * call gzip "x-gzip" etc.) - */ - public static function getAcceptedEncoding($allowCompress = true, $allowDeflate = true) - { - // @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - - if (! isset($_SERVER['HTTP_ACCEPT_ENCODING']) - || self::isBuggyIe()) - { - return array('', ''); - } - $ae = $_SERVER['HTTP_ACCEPT_ENCODING']; - // gzip checks (quick) - if (0 === strpos($ae, 'gzip,') // most browsers - || 0 === strpos($ae, 'deflate, gzip,') // opera - ) { - return array('gzip', 'gzip'); - } - // gzip checks (slow) - if (preg_match( - '@(?:^|,)\\s*((?:x-)?gzip)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' - ,$ae - ,$m)) { - return array('gzip', $m[1]); - } - if ($allowDeflate) { - // deflate checks - $aeRev = strrev($ae); - if (0 === strpos($aeRev, 'etalfed ,') // ie, webkit - || 0 === strpos($aeRev, 'etalfed,') // gecko - || 0 === strpos($ae, 'deflate,') // opera - // slow parsing - || preg_match( - '@(?:^|,)\\s*deflate\\s*(?:$|,|;\\s*q=(?:0\\.|1))@', $ae)) { - return array('deflate', 'deflate'); - } - } - if ($allowCompress && preg_match( - '@(?:^|,)\\s*((?:x-)?compress)\\s*(?:$|,|;\\s*q=(?:0\\.|1))@' - ,$ae - ,$m)) { - return array('compress', $m[1]); - } - return array('', ''); - } - - /** - * Encode (compress) the content - * - * If the encode method is '' (none) or compression level is 0, or the 'zlib' - * extension isn't loaded, we return false. - * - * Then the appropriate gz_* function is called to compress the content. If - * this fails, false is returned. - * - * The header "Vary: Accept-Encoding" is added. If encoding is successful, - * the Content-Length header is updated, and Content-Encoding is also added. - * - * @param int $compressionLevel given to zlib functions. If not given, the - * class default will be used. - * - * @return bool success true if the content was actually compressed - */ - public function encode($compressionLevel = null) - { - if (! self::isBuggyIe()) { - $this->_headers['Vary'] = 'Accept-Encoding'; - } - if (null === $compressionLevel) { - $compressionLevel = self::$compressionLevel; - } - if ('' === $this->_encodeMethod[0] - || ($compressionLevel == 0) - || !extension_loaded('zlib')) - { - return false; - } - if ($this->_encodeMethod[0] === 'deflate') { - $encoded = gzdeflate($this->_content, $compressionLevel); - } elseif ($this->_encodeMethod[0] === 'gzip') { - $encoded = gzencode($this->_content, $compressionLevel); - } else { - $encoded = gzcompress($this->_content, $compressionLevel); - } - if (false === $encoded) { - return false; - } - $this->_headers['Content-Length'] = $this->_useMbStrlen - ? (string)mb_strlen($encoded, '8bit') - : (string)strlen($encoded); - $this->_headers['Content-Encoding'] = $this->_encodeMethod[1]; - $this->_content = $encoded; - return true; - } - - /** - * Encode and send appropriate headers and content - * - * This is a convenience method for common use of the class - * - * @param string $content - * - * @param int $compressionLevel given to zlib functions. If not given, the - * class default will be used. - * - * @return bool success true if the content was actually compressed - */ - public static function output($content, $compressionLevel = null) - { - if (null === $compressionLevel) { - $compressionLevel = self::$compressionLevel; - } - $he = new HTTP_Encoder(array('content' => $content)); - $ret = $he->encode($compressionLevel); - $he->sendAll(); - return $ret; - } - - /** - * Is the browser an IE version earlier than 6 SP2? - * - * @return bool - */ - public static function isBuggyIe() - { - if (empty($_SERVER['HTTP_USER_AGENT'])) { - return false; - } - $ua = $_SERVER['HTTP_USER_AGENT']; - // quick escape for non-IEs - if (0 !== strpos($ua, 'Mozilla/4.0 (compatible; MSIE ') - || false !== strpos($ua, 'Opera')) { - return false; - } - // no regex = faaast - $version = (float)substr($ua, 30); - return self::$encodeToIe6 - ? ($version < 6 || ($version == 6 && false === strpos($ua, 'SV1'))) - : ($version < 7); - } - - protected $_content = ''; - protected $_headers = array(); - protected $_encodeMethod = array('', ''); - protected $_useMbStrlen = false; -} diff --git a/inc/lib/minify/JSMin.php b/inc/lib/minify/JSMin.php deleted file mode 100755 index 9840d8b3..00000000 --- a/inc/lib/minify/JSMin.php +++ /dev/null @@ -1,449 +0,0 @@ - - * $minifiedJs = JSMin::minify($js); - * - * - * This is a modified port of jsmin.c. Improvements: - * - * Does not choke on some regexp literals containing quote characters. E.g. /'/ - * - * Spaces are preserved after some add/sub operators, so they are not mistakenly - * converted to post-inc/dec. E.g. a + ++b -> a+ ++b - * - * Preserves multi-line comments that begin with /*! - * - * PHP 5 or higher is required. - * - * Permission is hereby granted to use this version of the library under the - * same terms as jsmin.c, which has the following license: - * - * -- - * Copyright (c) 2002 Douglas Crockford (www.crockford.com) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * The Software shall be used for Good, not Evil. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * -- - * - * @package JSMin - * @author Ryan Grove (PHP port) - * @author Steve Clay (modifications + cleanup) - * @author Andrea Giammarchi (spaceBeforeRegExp) - * @copyright 2002 Douglas Crockford (jsmin.c) - * @copyright 2008 Ryan Grove (PHP port) - * @license http://opensource.org/licenses/mit-license.php MIT License - * @link http://code.google.com/p/jsmin-php/ - */ - -class JSMin { - const ORD_LF = 10; - const ORD_SPACE = 32; - const ACTION_KEEP_A = 1; - const ACTION_DELETE_A = 2; - const ACTION_DELETE_A_B = 3; - - protected $a = "\n"; - protected $b = ''; - protected $input = ''; - protected $inputIndex = 0; - protected $inputLength = 0; - protected $lookAhead = null; - protected $output = ''; - protected $lastByteOut = ''; - protected $keptComment = ''; - - /** - * Minify Javascript. - * - * @param string $js Javascript to be minified - * - * @return string - */ - public static function minify($js) - { - $jsmin = new JSMin($js); - return $jsmin->min(); - } - - /** - * @param string $input - */ - public function __construct($input) - { - $this->input = $input; - } - - /** - * Perform minification, return result - * - * @return string - */ - public function min() - { - if ($this->output !== '') { // min already run - return $this->output; - } - - $mbIntEnc = null; - if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) { - $mbIntEnc = mb_internal_encoding(); - mb_internal_encoding('8bit'); - } - $this->input = str_replace("\r\n", "\n", $this->input); - $this->inputLength = strlen($this->input); - - $this->action(self::ACTION_DELETE_A_B); - - while ($this->a !== null) { - // determine next command - $command = self::ACTION_KEEP_A; // default - if ($this->a === ' ') { - if (($this->lastByteOut === '+' || $this->lastByteOut === '-') - && ($this->b === $this->lastByteOut)) { - // Don't delete this space. If we do, the addition/subtraction - // could be parsed as a post-increment - } elseif (! $this->isAlphaNum($this->b)) { - $command = self::ACTION_DELETE_A; - } - } elseif ($this->a === "\n") { - if ($this->b === ' ') { - $command = self::ACTION_DELETE_A_B; - - // in case of mbstring.func_overload & 2, must check for null b, - // otherwise mb_strpos will give WARNING - } elseif ($this->b === null - || (false === strpos('{[(+-!~', $this->b) - && ! $this->isAlphaNum($this->b))) { - $command = self::ACTION_DELETE_A; - } - } elseif (! $this->isAlphaNum($this->a)) { - if ($this->b === ' ' - || ($this->b === "\n" - && (false === strpos('}])+-"\'', $this->a)))) { - $command = self::ACTION_DELETE_A_B; - } - } - $this->action($command); - } - $this->output = trim($this->output); - - if ($mbIntEnc !== null) { - mb_internal_encoding($mbIntEnc); - } - return $this->output; - } - - /** - * ACTION_KEEP_A = Output A. Copy B to A. Get the next B. - * ACTION_DELETE_A = Copy B to A. Get the next B. - * ACTION_DELETE_A_B = Get the next B. - * - * @param int $command - * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException - */ - protected function action($command) - { - // make sure we don't compress "a + ++b" to "a+++b", etc. - if ($command === self::ACTION_DELETE_A_B - && $this->b === ' ' - && ($this->a === '+' || $this->a === '-')) { - // Note: we're at an addition/substraction operator; the inputIndex - // will certainly be a valid index - if ($this->input[$this->inputIndex] === $this->a) { - // This is "+ +" or "- -". Don't delete the space. - $command = self::ACTION_KEEP_A; - } - } - - switch ($command) { - case self::ACTION_KEEP_A: // 1 - $this->output .= $this->a; - - if ($this->keptComment) { - $this->output = rtrim($this->output, "\n"); - $this->output .= $this->keptComment; - $this->keptComment = ''; - } - - $this->lastByteOut = $this->a; - - // fallthrough intentional - case self::ACTION_DELETE_A: // 2 - $this->a = $this->b; - if ($this->a === "'" || $this->a === '"') { // string literal - $str = $this->a; // in case needed for exception - for(;;) { - $this->output .= $this->a; - $this->lastByteOut = $this->a; - - $this->a = $this->get(); - if ($this->a === $this->b) { // end quote - break; - } - if ($this->isEOF($this->a)) { - $byte = $this->inputIndex - 1; - throw new JSMin_UnterminatedStringException( - "JSMin: Unterminated String at byte {$byte}: {$str}"); - } - $str .= $this->a; - if ($this->a === '\\') { - $this->output .= $this->a; - $this->lastByteOut = $this->a; - - $this->a = $this->get(); - $str .= $this->a; - } - } - } - - // fallthrough intentional - case self::ACTION_DELETE_A_B: // 3 - $this->b = $this->next(); - if ($this->b === '/' && $this->isRegexpLiteral()) { - $this->output .= $this->a . $this->b; - $pattern = '/'; // keep entire pattern in case we need to report it in the exception - for(;;) { - $this->a = $this->get(); - $pattern .= $this->a; - if ($this->a === '[') { - for(;;) { - $this->output .= $this->a; - $this->a = $this->get(); - $pattern .= $this->a; - if ($this->a === ']') { - break; - } - if ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - $pattern .= $this->a; - } - if ($this->isEOF($this->a)) { - throw new JSMin_UnterminatedRegExpException( - "JSMin: Unterminated set in RegExp at byte " - . $this->inputIndex .": {$pattern}"); - } - } - } - - if ($this->a === '/') { // end pattern - break; // while (true) - } elseif ($this->a === '\\') { - $this->output .= $this->a; - $this->a = $this->get(); - $pattern .= $this->a; - } elseif ($this->isEOF($this->a)) { - $byte = $this->inputIndex - 1; - throw new JSMin_UnterminatedRegExpException( - "JSMin: Unterminated RegExp at byte {$byte}: {$pattern}"); - } - $this->output .= $this->a; - $this->lastByteOut = $this->a; - } - $this->b = $this->next(); - } - // end case ACTION_DELETE_A_B - } - } - - /** - * @return bool - */ - protected function isRegexpLiteral() - { - if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) { - // we obviously aren't dividing - return true; - } - - // we have to check for a preceding keyword, and we don't need to pattern - // match over the whole output. - $recentOutput = substr($this->output, -10); - - // check if return/typeof directly precede a pattern without a space - foreach (array('return', 'typeof') as $keyword) { - if ($this->a !== substr($keyword, -1)) { - // certainly wasn't keyword - continue; - } - if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) { - if ($m[1] === '' || !$this->isAlphaNum($m[1])) { - return true; - } - } - } - - // check all keywords - if ($this->a === ' ' || $this->a === "\n") { - if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) { - if ($m[1] === '' || !$this->isAlphaNum($m[1])) { - return true; - } - } - } - - return false; - } - - /** - * Return the next character from stdin. Watch out for lookahead. If the character is a control character, - * translate it to a space or linefeed. - * - * @return string - */ - protected function get() - { - $c = $this->lookAhead; - $this->lookAhead = null; - if ($c === null) { - // getc(stdin) - if ($this->inputIndex < $this->inputLength) { - $c = $this->input[$this->inputIndex]; - $this->inputIndex += 1; - } else { - $c = null; - } - } - if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) { - return $c; - } - if ($c === "\r") { - return "\n"; - } - return ' '; - } - - /** - * Does $a indicate end of input? - * - * @param string $a - * @return bool - */ - protected function isEOF($a) - { - return ord($a) <= self::ORD_LF; - } - - /** - * Get next char (without getting it). If is ctrl character, translate to a space or newline. - * - * @return string - */ - protected function peek() - { - $this->lookAhead = $this->get(); - return $this->lookAhead; - } - - /** - * Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character. - * - * @param string $c - * - * @return bool - */ - protected function isAlphaNum($c) - { - return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126); - } - - /** - * Consume a single line comment from input (possibly retaining it) - */ - protected function consumeSingleLineComment() - { - $comment = ''; - while (true) { - $get = $this->get(); - $comment .= $get; - if (ord($get) <= self::ORD_LF) { // end of line reached - // if IE conditional comment - if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) { - $this->keptComment .= "/{$comment}"; - } - return; - } - } - } - - /** - * Consume a multiple line comment from input (possibly retaining it) - * - * @throws JSMin_UnterminatedCommentException - */ - protected function consumeMultipleLineComment() - { - $this->get(); - $comment = ''; - for(;;) { - $get = $this->get(); - if ($get === '*') { - if ($this->peek() === '/') { // end of comment reached - $this->get(); - if (0 === strpos($comment, '!')) { - // preserved by YUI Compressor - if (!$this->keptComment) { - // don't prepend a newline if two comments right after one another - $this->keptComment = "\n"; - } - $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n"; - } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { - // IE conditional - $this->keptComment .= "/*{$comment}*/"; - } - return; - } - } elseif ($get === null) { - throw new JSMin_UnterminatedCommentException( - "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}"); - } - $comment .= $get; - } - } - - /** - * Get the next character, skipping over comments. Some comments may be preserved. - * - * @return string - */ - protected function next() - { - $get = $this->get(); - if ($get === '/') { - switch ($this->peek()) { - case '/': - $this->consumeSingleLineComment(); - $get = "\n"; - break; - case '*': - $this->consumeMultipleLineComment(); - $get = ' '; - break; - } - } - return $get; - } -} - -class JSMin_UnterminatedStringException extends Exception {} -class JSMin_UnterminatedCommentException extends Exception {} -class JSMin_UnterminatedRegExpException extends Exception {} diff --git a/inc/lib/minify/JSMinPlus.php b/inc/lib/minify/JSMinPlus.php deleted file mode 100755 index 5a3c5bdf..00000000 --- a/inc/lib/minify/JSMinPlus.php +++ /dev/null @@ -1,2086 +0,0 @@ - - * - * Usage: $minified = JSMinPlus::minify($script [, $filename]) - * - * Versionlog (see also changelog.txt): - * 23-07-2011 - remove dynamic creation of OP_* and KEYWORD_* defines and declare them on top - * reduce memory footprint by minifying by block-scope - * some small byte-saving and performance improvements - * 12-05-2009 - fixed hook:colon precedence, fixed empty body in loop and if-constructs - * 18-04-2009 - fixed crashbug in PHP 5.2.9 and several other bugfixes - * 12-04-2009 - some small bugfixes and performance improvements - * 09-04-2009 - initial open sourced version 1.0 - * - * Latest version of this script: http://files.tweakers.net/jsminplus/jsminplus.zip - * - */ - -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Narcissus JavaScript engine. - * - * The Initial Developer of the Original Code is - * Brendan Eich . - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): Tino Zijdel - * PHP port, modifications and minifier routine are (C) 2009-2011 - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -define('TOKEN_END', 1); -define('TOKEN_NUMBER', 2); -define('TOKEN_IDENTIFIER', 3); -define('TOKEN_STRING', 4); -define('TOKEN_REGEXP', 5); -define('TOKEN_NEWLINE', 6); -define('TOKEN_CONDCOMMENT_START', 7); -define('TOKEN_CONDCOMMENT_END', 8); - -define('JS_SCRIPT', 100); -define('JS_BLOCK', 101); -define('JS_LABEL', 102); -define('JS_FOR_IN', 103); -define('JS_CALL', 104); -define('JS_NEW_WITH_ARGS', 105); -define('JS_INDEX', 106); -define('JS_ARRAY_INIT', 107); -define('JS_OBJECT_INIT', 108); -define('JS_PROPERTY_INIT', 109); -define('JS_GETTER', 110); -define('JS_SETTER', 111); -define('JS_GROUP', 112); -define('JS_LIST', 113); - -define('JS_MINIFIED', 999); - -define('DECLARED_FORM', 0); -define('EXPRESSED_FORM', 1); -define('STATEMENT_FORM', 2); - -/* Operators */ -define('OP_SEMICOLON', ';'); -define('OP_COMMA', ','); -define('OP_HOOK', '?'); -define('OP_COLON', ':'); -define('OP_OR', '||'); -define('OP_AND', '&&'); -define('OP_BITWISE_OR', '|'); -define('OP_BITWISE_XOR', '^'); -define('OP_BITWISE_AND', '&'); -define('OP_STRICT_EQ', '==='); -define('OP_EQ', '=='); -define('OP_ASSIGN', '='); -define('OP_STRICT_NE', '!=='); -define('OP_NE', '!='); -define('OP_LSH', '<<'); -define('OP_LE', '<='); -define('OP_LT', '<'); -define('OP_URSH', '>>>'); -define('OP_RSH', '>>'); -define('OP_GE', '>='); -define('OP_GT', '>'); -define('OP_INCREMENT', '++'); -define('OP_DECREMENT', '--'); -define('OP_PLUS', '+'); -define('OP_MINUS', '-'); -define('OP_MUL', '*'); -define('OP_DIV', '/'); -define('OP_MOD', '%'); -define('OP_NOT', '!'); -define('OP_BITWISE_NOT', '~'); -define('OP_DOT', '.'); -define('OP_LEFT_BRACKET', '['); -define('OP_RIGHT_BRACKET', ']'); -define('OP_LEFT_CURLY', '{'); -define('OP_RIGHT_CURLY', '}'); -define('OP_LEFT_PAREN', '('); -define('OP_RIGHT_PAREN', ')'); -define('OP_CONDCOMMENT_END', '@*/'); - -define('OP_UNARY_PLUS', 'U+'); -define('OP_UNARY_MINUS', 'U-'); - -/* Keywords */ -define('KEYWORD_BREAK', 'break'); -define('KEYWORD_CASE', 'case'); -define('KEYWORD_CATCH', 'catch'); -define('KEYWORD_CONST', 'const'); -define('KEYWORD_CONTINUE', 'continue'); -define('KEYWORD_DEBUGGER', 'debugger'); -define('KEYWORD_DEFAULT', 'default'); -define('KEYWORD_DELETE', 'delete'); -define('KEYWORD_DO', 'do'); -define('KEYWORD_ELSE', 'else'); -define('KEYWORD_ENUM', 'enum'); -define('KEYWORD_FALSE', 'false'); -define('KEYWORD_FINALLY', 'finally'); -define('KEYWORD_FOR', 'for'); -define('KEYWORD_FUNCTION', 'function'); -define('KEYWORD_IF', 'if'); -define('KEYWORD_IN', 'in'); -define('KEYWORD_INSTANCEOF', 'instanceof'); -define('KEYWORD_NEW', 'new'); -define('KEYWORD_NULL', 'null'); -define('KEYWORD_RETURN', 'return'); -define('KEYWORD_SWITCH', 'switch'); -define('KEYWORD_THIS', 'this'); -define('KEYWORD_THROW', 'throw'); -define('KEYWORD_TRUE', 'true'); -define('KEYWORD_TRY', 'try'); -define('KEYWORD_TYPEOF', 'typeof'); -define('KEYWORD_VAR', 'var'); -define('KEYWORD_VOID', 'void'); -define('KEYWORD_WHILE', 'while'); -define('KEYWORD_WITH', 'with'); - - -class JSMinPlus -{ - private $parser; - private $reserved = array( - 'break', 'case', 'catch', 'continue', 'default', 'delete', 'do', - 'else', 'finally', 'for', 'function', 'if', 'in', 'instanceof', - 'new', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'var', - 'void', 'while', 'with', - // Words reserved for future use - 'abstract', 'boolean', 'byte', 'char', 'class', 'const', 'debugger', - 'double', 'enum', 'export', 'extends', 'final', 'float', 'goto', - 'implements', 'import', 'int', 'interface', 'long', 'native', - 'package', 'private', 'protected', 'public', 'short', 'static', - 'super', 'synchronized', 'throws', 'transient', 'volatile', - // These are not reserved, but should be taken into account - // in isValidIdentifier (See jslint source code) - 'arguments', 'eval', 'true', 'false', 'Infinity', 'NaN', 'null', 'undefined' - ); - - private function __construct() - { - $this->parser = new JSParser($this); - } - - public static function minify($js, $filename='') - { - static $instance; - - // this is a singleton - if(!$instance) - $instance = new JSMinPlus(); - - return $instance->min($js, $filename); - } - - private function min($js, $filename) - { - try - { - $n = $this->parser->parse($js, $filename, 1); - return $this->parseTree($n); - } - catch(Exception $e) - { - echo $e->getMessage() . "\n"; - } - - return false; - } - - public function parseTree($n, $noBlockGrouping = false) - { - $s = ''; - - switch ($n->type) - { - case JS_MINIFIED: - $s = $n->value; - break; - - case JS_SCRIPT: - // we do nothing yet with funDecls or varDecls - $noBlockGrouping = true; - // FALL THROUGH - - case JS_BLOCK: - $childs = $n->treeNodes; - $lastType = 0; - for ($c = 0, $i = 0, $j = count($childs); $i < $j; $i++) - { - $type = $childs[$i]->type; - $t = $this->parseTree($childs[$i]); - if (strlen($t)) - { - if ($c) - { - $s = rtrim($s, ';'); - - if ($type == KEYWORD_FUNCTION && $childs[$i]->functionForm == DECLARED_FORM) - { - // put declared functions on a new line - $s .= "\n"; - } - elseif ($type == KEYWORD_VAR && $type == $lastType) - { - // mutiple var-statements can go into one - $t = ',' . substr($t, 4); - } - else - { - // add terminator - $s .= ';'; - } - } - - $s .= $t; - - $c++; - $lastType = $type; - } - } - - if ($c > 1 && !$noBlockGrouping) - { - $s = '{' . $s . '}'; - } - break; - - case KEYWORD_FUNCTION: - $s .= 'function' . ($n->name ? ' ' . $n->name : '') . '('; - $params = $n->params; - for ($i = 0, $j = count($params); $i < $j; $i++) - $s .= ($i ? ',' : '') . $params[$i]; - $s .= '){' . $this->parseTree($n->body, true) . '}'; - break; - - case KEYWORD_IF: - $s = 'if(' . $this->parseTree($n->condition) . ')'; - $thenPart = $this->parseTree($n->thenPart); - $elsePart = $n->elsePart ? $this->parseTree($n->elsePart) : null; - - // empty if-statement - if ($thenPart == '') - $thenPart = ';'; - - if ($elsePart) - { - // be carefull and always make a block out of the thenPart; could be more optimized but is a lot of trouble - if ($thenPart != ';' && $thenPart[0] != '{') - $thenPart = '{' . $thenPart . '}'; - - $s .= $thenPart . 'else'; - - // we could check for more, but that hardly ever applies so go for performance - if ($elsePart[0] != '{') - $s .= ' '; - - $s .= $elsePart; - } - else - { - $s .= $thenPart; - } - break; - - case KEYWORD_SWITCH: - $s = 'switch(' . $this->parseTree($n->discriminant) . '){'; - $cases = $n->cases; - for ($i = 0, $j = count($cases); $i < $j; $i++) - { - $case = $cases[$i]; - if ($case->type == KEYWORD_CASE) - $s .= 'case' . ($case->caseLabel->type != TOKEN_STRING ? ' ' : '') . $this->parseTree($case->caseLabel) . ':'; - else - $s .= 'default:'; - - $statement = $this->parseTree($case->statements, true); - if ($statement) - { - $s .= $statement; - // no terminator for last statement - if ($i + 1 < $j) - $s .= ';'; - } - } - $s .= '}'; - break; - - case KEYWORD_FOR: - $s = 'for(' . ($n->setup ? $this->parseTree($n->setup) : '') - . ';' . ($n->condition ? $this->parseTree($n->condition) : '') - . ';' . ($n->update ? $this->parseTree($n->update) : '') . ')'; - - $body = $this->parseTree($n->body); - if ($body == '') - $body = ';'; - - $s .= $body; - break; - - case KEYWORD_WHILE: - $s = 'while(' . $this->parseTree($n->condition) . ')'; - - $body = $this->parseTree($n->body); - if ($body == '') - $body = ';'; - - $s .= $body; - break; - - case JS_FOR_IN: - $s = 'for(' . ($n->varDecl ? $this->parseTree($n->varDecl) : $this->parseTree($n->iterator)) . ' in ' . $this->parseTree($n->object) . ')'; - - $body = $this->parseTree($n->body); - if ($body == '') - $body = ';'; - - $s .= $body; - break; - - case KEYWORD_DO: - $s = 'do{' . $this->parseTree($n->body, true) . '}while(' . $this->parseTree($n->condition) . ')'; - break; - - case KEYWORD_BREAK: - case KEYWORD_CONTINUE: - $s = $n->value . ($n->label ? ' ' . $n->label : ''); - break; - - case KEYWORD_TRY: - $s = 'try{' . $this->parseTree($n->tryBlock, true) . '}'; - $catchClauses = $n->catchClauses; - for ($i = 0, $j = count($catchClauses); $i < $j; $i++) - { - $t = $catchClauses[$i]; - $s .= 'catch(' . $t->varName . ($t->guard ? ' if ' . $this->parseTree($t->guard) : '') . '){' . $this->parseTree($t->block, true) . '}'; - } - if ($n->finallyBlock) - $s .= 'finally{' . $this->parseTree($n->finallyBlock, true) . '}'; - break; - - case KEYWORD_THROW: - case KEYWORD_RETURN: - $s = $n->type; - if ($n->value) - { - $t = $this->parseTree($n->value); - if (strlen($t)) - { - if ($this->isWordChar($t[0]) || $t[0] == '\\') - $s .= ' '; - - $s .= $t; - } - } - break; - - case KEYWORD_WITH: - $s = 'with(' . $this->parseTree($n->object) . ')' . $this->parseTree($n->body); - break; - - case KEYWORD_VAR: - case KEYWORD_CONST: - $s = $n->value . ' '; - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - { - $t = $childs[$i]; - $s .= ($i ? ',' : '') . $t->name; - $u = $t->initializer; - if ($u) - $s .= '=' . $this->parseTree($u); - } - break; - - case KEYWORD_IN: - case KEYWORD_INSTANCEOF: - $left = $this->parseTree($n->treeNodes[0]); - $right = $this->parseTree($n->treeNodes[1]); - - $s = $left; - - if ($this->isWordChar(substr($left, -1))) - $s .= ' '; - - $s .= $n->type; - - if ($this->isWordChar($right[0]) || $right[0] == '\\') - $s .= ' '; - - $s .= $right; - break; - - case KEYWORD_DELETE: - case KEYWORD_TYPEOF: - $right = $this->parseTree($n->treeNodes[0]); - - $s = $n->type; - - if ($this->isWordChar($right[0]) || $right[0] == '\\') - $s .= ' '; - - $s .= $right; - break; - - case KEYWORD_VOID: - $s = 'void(' . $this->parseTree($n->treeNodes[0]) . ')'; - break; - - case KEYWORD_DEBUGGER: - throw new Exception('NOT IMPLEMENTED: DEBUGGER'); - break; - - case TOKEN_CONDCOMMENT_START: - case TOKEN_CONDCOMMENT_END: - $s = $n->value . ($n->type == TOKEN_CONDCOMMENT_START ? ' ' : ''); - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - $s .= $this->parseTree($childs[$i]); - break; - - case OP_SEMICOLON: - if ($expression = $n->expression) - $s = $this->parseTree($expression); - break; - - case JS_LABEL: - $s = $n->label . ':' . $this->parseTree($n->statement); - break; - - case OP_COMMA: - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); - break; - - case OP_ASSIGN: - $s = $this->parseTree($n->treeNodes[0]) . $n->value . $this->parseTree($n->treeNodes[1]); - break; - - case OP_HOOK: - $s = $this->parseTree($n->treeNodes[0]) . '?' . $this->parseTree($n->treeNodes[1]) . ':' . $this->parseTree($n->treeNodes[2]); - break; - - case OP_OR: case OP_AND: - case OP_BITWISE_OR: case OP_BITWISE_XOR: case OP_BITWISE_AND: - case OP_EQ: case OP_NE: case OP_STRICT_EQ: case OP_STRICT_NE: - case OP_LT: case OP_LE: case OP_GE: case OP_GT: - case OP_LSH: case OP_RSH: case OP_URSH: - case OP_MUL: case OP_DIV: case OP_MOD: - $s = $this->parseTree($n->treeNodes[0]) . $n->type . $this->parseTree($n->treeNodes[1]); - break; - - case OP_PLUS: - case OP_MINUS: - $left = $this->parseTree($n->treeNodes[0]); - $right = $this->parseTree($n->treeNodes[1]); - - switch ($n->treeNodes[1]->type) - { - case OP_PLUS: - case OP_MINUS: - case OP_INCREMENT: - case OP_DECREMENT: - case OP_UNARY_PLUS: - case OP_UNARY_MINUS: - $s = $left . $n->type . ' ' . $right; - break; - - case TOKEN_STRING: - //combine concatted strings with same quotestyle - if ($n->type == OP_PLUS && substr($left, -1) == $right[0]) - { - $s = substr($left, 0, -1) . substr($right, 1); - break; - } - // FALL THROUGH - - default: - $s = $left . $n->type . $right; - } - break; - - case OP_NOT: - case OP_BITWISE_NOT: - case OP_UNARY_PLUS: - case OP_UNARY_MINUS: - $s = $n->value . $this->parseTree($n->treeNodes[0]); - break; - - case OP_INCREMENT: - case OP_DECREMENT: - if ($n->postfix) - $s = $this->parseTree($n->treeNodes[0]) . $n->value; - else - $s = $n->value . $this->parseTree($n->treeNodes[0]); - break; - - case OP_DOT: - $s = $this->parseTree($n->treeNodes[0]) . '.' . $this->parseTree($n->treeNodes[1]); - break; - - case JS_INDEX: - $s = $this->parseTree($n->treeNodes[0]); - // See if we can replace named index with a dot saving 3 bytes - if ( $n->treeNodes[0]->type == TOKEN_IDENTIFIER && - $n->treeNodes[1]->type == TOKEN_STRING && - $this->isValidIdentifier(substr($n->treeNodes[1]->value, 1, -1)) - ) - $s .= '.' . substr($n->treeNodes[1]->value, 1, -1); - else - $s .= '[' . $this->parseTree($n->treeNodes[1]) . ']'; - break; - - case JS_LIST: - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); - break; - - case JS_CALL: - $s = $this->parseTree($n->treeNodes[0]) . '(' . $this->parseTree($n->treeNodes[1]) . ')'; - break; - - case KEYWORD_NEW: - case JS_NEW_WITH_ARGS: - $s = 'new ' . $this->parseTree($n->treeNodes[0]) . '(' . ($n->type == JS_NEW_WITH_ARGS ? $this->parseTree($n->treeNodes[1]) : '') . ')'; - break; - - case JS_ARRAY_INIT: - $s = '['; - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - { - $s .= ($i ? ',' : '') . $this->parseTree($childs[$i]); - } - $s .= ']'; - break; - - case JS_OBJECT_INIT: - $s = '{'; - $childs = $n->treeNodes; - for ($i = 0, $j = count($childs); $i < $j; $i++) - { - $t = $childs[$i]; - if ($i) - $s .= ','; - if ($t->type == JS_PROPERTY_INIT) - { - // Ditch the quotes when the index is a valid identifier - if ( $t->treeNodes[0]->type == TOKEN_STRING && - $this->isValidIdentifier(substr($t->treeNodes[0]->value, 1, -1)) - ) - $s .= substr($t->treeNodes[0]->value, 1, -1); - else - $s .= $t->treeNodes[0]->value; - - $s .= ':' . $this->parseTree($t->treeNodes[1]); - } - else - { - $s .= $t->type == JS_GETTER ? 'get' : 'set'; - $s .= ' ' . $t->name . '('; - $params = $t->params; - for ($i = 0, $j = count($params); $i < $j; $i++) - $s .= ($i ? ',' : '') . $params[$i]; - $s .= '){' . $this->parseTree($t->body, true) . '}'; - } - } - $s .= '}'; - break; - - case TOKEN_NUMBER: - $s = $n->value; - if (preg_match('/^([1-9]+)(0{3,})$/', $s, $m)) - $s = $m[1] . 'e' . strlen($m[2]); - break; - - case KEYWORD_NULL: case KEYWORD_THIS: case KEYWORD_TRUE: case KEYWORD_FALSE: - case TOKEN_IDENTIFIER: case TOKEN_STRING: case TOKEN_REGEXP: - $s = $n->value; - break; - - case JS_GROUP: - if (in_array( - $n->treeNodes[0]->type, - array( - JS_ARRAY_INIT, JS_OBJECT_INIT, JS_GROUP, - TOKEN_NUMBER, TOKEN_STRING, TOKEN_REGEXP, TOKEN_IDENTIFIER, - KEYWORD_NULL, KEYWORD_THIS, KEYWORD_TRUE, KEYWORD_FALSE - ) - )) - { - $s = $this->parseTree($n->treeNodes[0]); - } - else - { - $s = '(' . $this->parseTree($n->treeNodes[0]) . ')'; - } - break; - - default: - throw new Exception('UNKNOWN TOKEN TYPE: ' . $n->type); - } - - return $s; - } - - private function isValidIdentifier($string) - { - return preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $string) && !in_array($string, $this->reserved); - } - - private function isWordChar($char) - { - return $char == '_' || $char == '$' || ctype_alnum($char); - } -} - -class JSParser -{ - private $t; - private $minifier; - - private $opPrecedence = array( - ';' => 0, - ',' => 1, - '=' => 2, '?' => 2, ':' => 2, - // The above all have to have the same precedence, see bug 330975 - '||' => 4, - '&&' => 5, - '|' => 6, - '^' => 7, - '&' => 8, - '==' => 9, '!=' => 9, '===' => 9, '!==' => 9, - '<' => 10, '<=' => 10, '>=' => 10, '>' => 10, 'in' => 10, 'instanceof' => 10, - '<<' => 11, '>>' => 11, '>>>' => 11, - '+' => 12, '-' => 12, - '*' => 13, '/' => 13, '%' => 13, - 'delete' => 14, 'void' => 14, 'typeof' => 14, - '!' => 14, '~' => 14, 'U+' => 14, 'U-' => 14, - '++' => 15, '--' => 15, - 'new' => 16, - '.' => 17, - JS_NEW_WITH_ARGS => 0, JS_INDEX => 0, JS_CALL => 0, - JS_ARRAY_INIT => 0, JS_OBJECT_INIT => 0, JS_GROUP => 0 - ); - - private $opArity = array( - ',' => -2, - '=' => 2, - '?' => 3, - '||' => 2, - '&&' => 2, - '|' => 2, - '^' => 2, - '&' => 2, - '==' => 2, '!=' => 2, '===' => 2, '!==' => 2, - '<' => 2, '<=' => 2, '>=' => 2, '>' => 2, 'in' => 2, 'instanceof' => 2, - '<<' => 2, '>>' => 2, '>>>' => 2, - '+' => 2, '-' => 2, - '*' => 2, '/' => 2, '%' => 2, - 'delete' => 1, 'void' => 1, 'typeof' => 1, - '!' => 1, '~' => 1, 'U+' => 1, 'U-' => 1, - '++' => 1, '--' => 1, - 'new' => 1, - '.' => 2, - JS_NEW_WITH_ARGS => 2, JS_INDEX => 2, JS_CALL => 2, - JS_ARRAY_INIT => 1, JS_OBJECT_INIT => 1, JS_GROUP => 1, - TOKEN_CONDCOMMENT_START => 1, TOKEN_CONDCOMMENT_END => 1 - ); - - public function __construct($minifier=null) - { - $this->minifier = $minifier; - $this->t = new JSTokenizer(); - } - - public function parse($s, $f, $l) - { - // initialize tokenizer - $this->t->init($s, $f, $l); - - $x = new JSCompilerContext(false); - $n = $this->Script($x); - if (!$this->t->isDone()) - throw $this->t->newSyntaxError('Syntax error'); - - return $n; - } - - private function Script($x) - { - $n = $this->Statements($x); - $n->type = JS_SCRIPT; - $n->funDecls = $x->funDecls; - $n->varDecls = $x->varDecls; - - // minify by scope - if ($this->minifier) - { - $n->value = $this->minifier->parseTree($n); - - // clear tree from node to save memory - $n->treeNodes = null; - $n->funDecls = null; - $n->varDecls = null; - - $n->type = JS_MINIFIED; - } - - return $n; - } - - private function Statements($x) - { - $n = new JSNode($this->t, JS_BLOCK); - array_push($x->stmtStack, $n); - - while (!$this->t->isDone() && $this->t->peek() != OP_RIGHT_CURLY) - $n->addNode($this->Statement($x)); - - array_pop($x->stmtStack); - - return $n; - } - - private function Block($x) - { - $this->t->mustMatch(OP_LEFT_CURLY); - $n = $this->Statements($x); - $this->t->mustMatch(OP_RIGHT_CURLY); - - return $n; - } - - private function Statement($x) - { - $tt = $this->t->get(); - $n2 = null; - - // Cases for statements ending in a right curly return early, avoiding the - // common semicolon insertion magic after this switch. - switch ($tt) - { - case KEYWORD_FUNCTION: - return $this->FunctionDefinition( - $x, - true, - count($x->stmtStack) > 1 ? STATEMENT_FORM : DECLARED_FORM - ); - break; - - case OP_LEFT_CURLY: - $n = $this->Statements($x); - $this->t->mustMatch(OP_RIGHT_CURLY); - return $n; - - case KEYWORD_IF: - $n = new JSNode($this->t); - $n->condition = $this->ParenExpression($x); - array_push($x->stmtStack, $n); - $n->thenPart = $this->Statement($x); - $n->elsePart = $this->t->match(KEYWORD_ELSE) ? $this->Statement($x) : null; - array_pop($x->stmtStack); - return $n; - - case KEYWORD_SWITCH: - $n = new JSNode($this->t); - $this->t->mustMatch(OP_LEFT_PAREN); - $n->discriminant = $this->Expression($x); - $this->t->mustMatch(OP_RIGHT_PAREN); - $n->cases = array(); - $n->defaultIndex = -1; - - array_push($x->stmtStack, $n); - - $this->t->mustMatch(OP_LEFT_CURLY); - - while (($tt = $this->t->get()) != OP_RIGHT_CURLY) - { - switch ($tt) - { - case KEYWORD_DEFAULT: - if ($n->defaultIndex >= 0) - throw $this->t->newSyntaxError('More than one switch default'); - // FALL THROUGH - case KEYWORD_CASE: - $n2 = new JSNode($this->t); - if ($tt == KEYWORD_DEFAULT) - $n->defaultIndex = count($n->cases); - else - $n2->caseLabel = $this->Expression($x, OP_COLON); - break; - default: - throw $this->t->newSyntaxError('Invalid switch case'); - } - - $this->t->mustMatch(OP_COLON); - $n2->statements = new JSNode($this->t, JS_BLOCK); - while (($tt = $this->t->peek()) != KEYWORD_CASE && $tt != KEYWORD_DEFAULT && $tt != OP_RIGHT_CURLY) - $n2->statements->addNode($this->Statement($x)); - - array_push($n->cases, $n2); - } - - array_pop($x->stmtStack); - return $n; - - case KEYWORD_FOR: - $n = new JSNode($this->t); - $n->isLoop = true; - $this->t->mustMatch(OP_LEFT_PAREN); - - if (($tt = $this->t->peek()) != OP_SEMICOLON) - { - $x->inForLoopInit = true; - if ($tt == KEYWORD_VAR || $tt == KEYWORD_CONST) - { - $this->t->get(); - $n2 = $this->Variables($x); - } - else - { - $n2 = $this->Expression($x); - } - $x->inForLoopInit = false; - } - - if ($n2 && $this->t->match(KEYWORD_IN)) - { - $n->type = JS_FOR_IN; - if ($n2->type == KEYWORD_VAR) - { - if (count($n2->treeNodes) != 1) - { - throw $this->t->SyntaxError( - 'Invalid for..in left-hand side', - $this->t->filename, - $n2->lineno - ); - } - - // NB: n2[0].type == IDENTIFIER and n2[0].value == n2[0].name. - $n->iterator = $n2->treeNodes[0]; - $n->varDecl = $n2; - } - else - { - $n->iterator = $n2; - $n->varDecl = null; - } - - $n->object = $this->Expression($x); - } - else - { - $n->setup = $n2 ? $n2 : null; - $this->t->mustMatch(OP_SEMICOLON); - $n->condition = $this->t->peek() == OP_SEMICOLON ? null : $this->Expression($x); - $this->t->mustMatch(OP_SEMICOLON); - $n->update = $this->t->peek() == OP_RIGHT_PAREN ? null : $this->Expression($x); - } - - $this->t->mustMatch(OP_RIGHT_PAREN); - $n->body = $this->nest($x, $n); - return $n; - - case KEYWORD_WHILE: - $n = new JSNode($this->t); - $n->isLoop = true; - $n->condition = $this->ParenExpression($x); - $n->body = $this->nest($x, $n); - return $n; - - case KEYWORD_DO: - $n = new JSNode($this->t); - $n->isLoop = true; - $n->body = $this->nest($x, $n, KEYWORD_WHILE); - $n->condition = $this->ParenExpression($x); - if (!$x->ecmaStrictMode) - { - // "; - * $link = ""; - * - * // in min.php - * Minify::serve('Groups', array( - * 'groups' => $groupSources - * ,'setExpires' => (time() + 86400 * 365) - * )); - * - * - * @package Minify - * @author Stephen Clay - */ -class Minify_Build { - - /** - * Last modification time of all files in the build - * - * @var int - */ - public $lastModified = 0; - - /** - * String to use as ampersand in uri(). Set this to '&' if - * you are not HTML-escaping URIs. - * - * @var string - */ - public static $ampersand = '&'; - - /** - * Get a time-stamped URI - * - * - * echo $b->uri('/site.js'); - * // outputs "/site.js?1678242" - * - * echo $b->uri('/scriptaculous.js?load=effects'); - * // outputs "/scriptaculous.js?load=effects&1678242" - * - * - * @param string $uri - * @param boolean $forceAmpersand (default = false) Force the use of ampersand to - * append the timestamp to the URI. - * @return string - */ - public function uri($uri, $forceAmpersand = false) { - $sep = ($forceAmpersand || strpos($uri, '?') !== false) - ? self::$ampersand - : '?'; - return "{$uri}{$sep}{$this->lastModified}"; - } - - /** - * Create a build object - * - * @param array $sources array of Minify_Source objects and/or file paths - * - * @return null - */ - public function __construct($sources) - { - $max = 0; - foreach ((array)$sources as $source) { - if ($source instanceof Minify_Source) { - $max = max($max, $source->lastModified); - } elseif (is_string($source)) { - if (0 === strpos($source, '//')) { - $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); - } - if (is_file($source)) { - $max = max($max, filemtime($source)); - } - } - } - $this->lastModified = $max; - } -} diff --git a/inc/lib/minify/Minify/CSS/UriRewriter.php b/inc/lib/minify/Minify/CSS/UriRewriter.php deleted file mode 100755 index 43cc2548..00000000 --- a/inc/lib/minify/Minify/CSS/UriRewriter.php +++ /dev/null @@ -1,307 +0,0 @@ - - */ -class Minify_CSS_UriRewriter { - - /** - * rewrite() and rewriteRelative() append debugging information here - * - * @var string - */ - public static $debugText = ''; - - /** - * In CSS content, rewrite file relative URIs as root relative - * - * @param string $css - * - * @param string $currentDir The directory of the current CSS file. - * - * @param string $docRoot The document root of the web site in which - * the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']). - * - * @param array $symlinks (default = array()) If the CSS file is stored in - * a symlink-ed directory, provide an array of link paths to - * target paths, where the link paths are within the document root. Because - * paths need to be normalized for this to work, use "//" to substitute - * the doc root in the link paths (the array keys). E.g.: - * - * array('//symlink' => '/real/target/path') // unix - * array('//static' => 'D:\\staticStorage') // Windows - * - * - * @return string - */ - public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array()) - { - self::$_docRoot = self::_realpath( - $docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT'] - ); - self::$_currentDir = self::_realpath($currentDir); - self::$_symlinks = array(); - - // normalize symlinks - foreach ($symlinks as $link => $target) { - $link = ($link === '//') - ? self::$_docRoot - : str_replace('//', self::$_docRoot . '/', $link); - $link = strtr($link, '/', DIRECTORY_SEPARATOR); - self::$_symlinks[$link] = self::_realpath($target); - } - - self::$debugText .= "docRoot : " . self::$_docRoot . "\n" - . "currentDir : " . self::$_currentDir . "\n"; - if (self::$_symlinks) { - self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n"; - } - self::$debugText .= "\n"; - - $css = self::_trimUrls($css); - - // rewrite - $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' - ,array(self::$className, '_processUriCB'), $css); - $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' - ,array(self::$className, '_processUriCB'), $css); - - return $css; - } - - /** - * In CSS content, prepend a path to relative URIs - * - * @param string $css - * - * @param string $path The path to prepend. - * - * @return string - */ - public static function prepend($css, $path) - { - self::$_prependPath = $path; - - $css = self::_trimUrls($css); - - // append - $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/' - ,array(self::$className, '_processUriCB'), $css); - $css = preg_replace_callback('/url\\(\\s*([\'"](.*?)[\'"]|[^\\)\\s]+)\\s*\\)/' - ,array(self::$className, '_processUriCB'), $css); - - self::$_prependPath = null; - return $css; - } - - /** - * Get a root relative URI from a file relative URI - * - * - * Minify_CSS_UriRewriter::rewriteRelative( - * '../img/hello.gif' - * , '/home/user/www/css' // path of CSS file - * , '/home/user/www' // doc root - * ); - * // returns '/img/hello.gif' - * - * // example where static files are stored in a symlinked directory - * Minify_CSS_UriRewriter::rewriteRelative( - * 'hello.gif' - * , '/var/staticFiles/theme' - * , '/home/user/www' - * , array('/home/user/www/static' => '/var/staticFiles') - * ); - * // returns '/static/theme/hello.gif' - * - * - * @param string $uri file relative URI - * - * @param string $realCurrentDir realpath of the current file's directory. - * - * @param string $realDocRoot realpath of the site document root. - * - * @param array $symlinks (default = array()) If the file is stored in - * a symlink-ed directory, provide an array of link paths to - * real target paths, where the link paths "appear" to be within the document - * root. E.g.: - * - * array('/home/foo/www/not/real/path' => '/real/target/path') // unix - * array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows - * - * - * @return string - */ - public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array()) - { - // prepend path with current dir separator (OS-independent) - $path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR) - . DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR); - - self::$debugText .= "file-relative URI : {$uri}\n" - . "path prepended : {$path}\n"; - - // "unresolve" a symlink back to doc root - foreach ($symlinks as $link => $target) { - if (0 === strpos($path, $target)) { - // replace $target with $link - $path = $link . substr($path, strlen($target)); - - self::$debugText .= "symlink unresolved : {$path}\n"; - - break; - } - } - // strip doc root - $path = substr($path, strlen($realDocRoot)); - - self::$debugText .= "docroot stripped : {$path}\n"; - - // fix to root-relative URI - $uri = strtr($path, '/\\', '//'); - $uri = self::removeDots($uri); - - self::$debugText .= "traversals removed : {$uri}\n\n"; - - return $uri; - } - - /** - * Remove instances of "./" and "../" where possible from a root-relative URI - * - * @param string $uri - * - * @return string - */ - public static function removeDots($uri) - { - $uri = str_replace('/./', '/', $uri); - // inspired by patch from Oleg Cherniy - do { - $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed); - } while ($changed); - return $uri; - } - - /** - * Defines which class to call as part of callbacks, change this - * if you extend Minify_CSS_UriRewriter - * - * @var string - */ - protected static $className = 'Minify_CSS_UriRewriter'; - - /** - * Get realpath with any trailing slash removed. If realpath() fails, - * just remove the trailing slash. - * - * @param string $path - * - * @return mixed path with no trailing slash - */ - protected static function _realpath($path) - { - $realPath = realpath($path); - if ($realPath !== false) { - $path = $realPath; - } - return rtrim($path, '/\\'); - } - - /** - * Directory of this stylesheet - * - * @var string - */ - private static $_currentDir = ''; - - /** - * DOC_ROOT - * - * @var string - */ - private static $_docRoot = ''; - - /** - * directory replacements to map symlink targets back to their - * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath' - * - * @var array - */ - private static $_symlinks = array(); - - /** - * Path to prepend - * - * @var string - */ - private static $_prependPath = null; - - /** - * @param string $css - * - * @return string - */ - private static function _trimUrls($css) - { - return preg_replace('/ - url\\( # url( - \\s* - ([^\\)]+?) # 1 = URI (assuming does not contain ")") - \\s* - \\) # ) - /x', 'url($1)', $css); - } - - /** - * @param array $m - * - * @return string - */ - private static function _processUriCB($m) - { - // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/' - $isImport = ($m[0][0] === '@'); - // determine URI and the quote character (if any) - if ($isImport) { - $quoteChar = $m[1]; - $uri = $m[2]; - } else { - // $m[1] is either quoted or not - $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"') - ? $m[1][0] - : ''; - $uri = ($quoteChar === '') - ? $m[1] - : substr($m[1], 1, strlen($m[1]) - 2); - } - // if not root/scheme relative and not starts with scheme - if (!preg_match('~^(/|[a-z]+\:)~', $uri)) { - // URI is file-relative: rewrite depending on options - if (self::$_prependPath === null) { - $uri = self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks); - } else { - $uri = self::$_prependPath . $uri; - if ($uri[0] === '/') { - $root = ''; - $rootRelative = $uri; - $uri = $root . self::removeDots($rootRelative); - } elseif (preg_match('@^((https?\:)?//([^/]+))/@', $uri, $m) && (false !== strpos($m[3], '.'))) { - $root = $m[1]; - $rootRelative = substr($uri, strlen($root)); - $uri = $root . self::removeDots($rootRelative); - } - } - } - return $isImport - ? "@import {$quoteChar}{$uri}{$quoteChar}" - : "url({$quoteChar}{$uri}{$quoteChar})"; - } -} diff --git a/inc/lib/minify/Minify/Cache/APC.php b/inc/lib/minify/Minify/Cache/APC.php deleted file mode 100755 index 24ab0462..00000000 --- a/inc/lib/minify/Minify/Cache/APC.php +++ /dev/null @@ -1,133 +0,0 @@ - - * Minify::setCache(new Minify_Cache_APC()); - * - * - * @package Minify - * @author Chris Edwards - **/ -class Minify_Cache_APC { - - /** - * Create a Minify_Cache_APC object, to be passed to - * Minify::setCache(). - * - * - * @param int $expire seconds until expiration (default = 0 - * meaning the item will not get an expiration date) - * - * @return null - */ - public function __construct($expire = 0) - { - $this->_exp = $expire; - } - - /** - * Write data to cache. - * - * @param string $id cache id - * - * @param string $data - * - * @return bool success - */ - public function store($id, $data) - { - return apc_store($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp); - } - - /** - * Get the size of a cache entry - * - * @param string $id cache id - * - * @return int size in bytes - */ - public function getSize($id) - { - if (! $this->_fetch($id)) { - return false; - } - return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) - ? mb_strlen($this->_data, '8bit') - : strlen($this->_data); - } - - /** - * Does a valid cache entry exist? - * - * @param string $id cache id - * - * @param int $srcMtime mtime of the original source file(s) - * - * @return bool exists - */ - public function isValid($id, $srcMtime) - { - return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); - } - - /** - * Send the cached content to output - * - * @param string $id cache id - */ - public function display($id) - { - echo $this->_fetch($id) - ? $this->_data - : ''; - } - - /** - * Fetch the cached content - * - * @param string $id cache id - * - * @return string - */ - public function fetch($id) - { - return $this->_fetch($id) - ? $this->_data - : ''; - } - - private $_exp = null; - - // cache of most recently fetched id - private $_lm = null; - private $_data = null; - private $_id = null; - - /** - * Fetch data and timestamp from apc, store in instance - * - * @param string $id - * - * @return bool success - */ - private function _fetch($id) - { - if ($this->_id === $id) { - return true; - } - $ret = apc_fetch($id); - if (false === $ret) { - $this->_id = null; - return false; - } - list($this->_lm, $this->_data) = explode('|', $ret, 2); - $this->_id = $id; - return true; - } -} diff --git a/inc/lib/minify/Minify/Cache/File.php b/inc/lib/minify/Minify/Cache/File.php deleted file mode 100755 index c228eb2b..00000000 --- a/inc/lib/minify/Minify/Cache/File.php +++ /dev/null @@ -1,197 +0,0 @@ -_locking = $fileLocking; - $this->_path = $path; - } - - /** - * Write data to cache. - * - * @param string $id cache id (e.g. a filename) - * - * @param string $data - * - * @return bool success - */ - public function store($id, $data) - { - $flag = $this->_locking - ? LOCK_EX - : null; - $file = $this->_path . '/' . $id; - if (! @file_put_contents($file, $data, $flag)) { - $this->_log("Minify_Cache_File: Write failed to '$file'"); - } - // write control - if ($data !== $this->fetch($id)) { - @unlink($file); - $this->_log("Minify_Cache_File: Post-write read failed for '$file'"); - return false; - } - return true; - } - - /** - * Get the size of a cache entry - * - * @param string $id cache id (e.g. a filename) - * - * @return int size in bytes - */ - public function getSize($id) - { - return filesize($this->_path . '/' . $id); - } - - /** - * Does a valid cache entry exist? - * - * @param string $id cache id (e.g. a filename) - * - * @param int $srcMtime mtime of the original source file(s) - * - * @return bool exists - */ - public function isValid($id, $srcMtime) - { - $file = $this->_path . '/' . $id; - return (is_file($file) && (filemtime($file) >= $srcMtime)); - } - - /** - * Send the cached content to output - * - * @param string $id cache id (e.g. a filename) - */ - public function display($id) - { - if ($this->_locking) { - $fp = fopen($this->_path . '/' . $id, 'rb'); - flock($fp, LOCK_SH); - fpassthru($fp); - flock($fp, LOCK_UN); - fclose($fp); - } else { - readfile($this->_path . '/' . $id); - } - } - - /** - * Fetch the cached content - * - * @param string $id cache id (e.g. a filename) - * - * @return string - */ - public function fetch($id) - { - if ($this->_locking) { - $fp = fopen($this->_path . '/' . $id, 'rb'); - if (!$fp) { - return false; - } - flock($fp, LOCK_SH); - $ret = stream_get_contents($fp); - flock($fp, LOCK_UN); - fclose($fp); - return $ret; - } else { - return file_get_contents($this->_path . '/' . $id); - } - } - - /** - * Fetch the cache path used - * - * @return string - */ - public function getPath() - { - return $this->_path; - } - - /** - * Get a usable temp directory - * - * Adapted from Solar/Dir.php - * @author Paul M. Jones - * @license http://opensource.org/licenses/bsd-license.php BSD - * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php - * - * @return string - */ - public static function tmp() - { - static $tmp = null; - if (! $tmp) { - $tmp = function_exists('sys_get_temp_dir') - ? sys_get_temp_dir() - : self::_tmp(); - $tmp = rtrim($tmp, DIRECTORY_SEPARATOR); - } - return $tmp; - } - - /** - * Returns the OS-specific directory for temporary files - * - * @author Paul M. Jones - * @license http://opensource.org/licenses/bsd-license.php BSD - * @link http://solarphp.com/trac/core/browser/trunk/Solar/Dir.php - * - * @return string - */ - protected static function _tmp() - { - // non-Windows system? - if (strtolower(substr(PHP_OS, 0, 3)) != 'win') { - $tmp = empty($_ENV['TMPDIR']) ? getenv('TMPDIR') : $_ENV['TMPDIR']; - if ($tmp) { - return $tmp; - } else { - return '/tmp'; - } - } - // Windows 'TEMP' - $tmp = empty($_ENV['TEMP']) ? getenv('TEMP') : $_ENV['TEMP']; - if ($tmp) { - return $tmp; - } - // Windows 'TMP' - $tmp = empty($_ENV['TMP']) ? getenv('TMP') : $_ENV['TMP']; - if ($tmp) { - return $tmp; - } - // Windows 'windir' - $tmp = empty($_ENV['windir']) ? getenv('windir') : $_ENV['windir']; - if ($tmp) { - return $tmp; - } - // final fallback for Windows - return getenv('SystemRoot') . '\\temp'; - } - - /** - * Send message to the Minify logger - * @param string $msg - * @return null - */ - protected function _log($msg) - { - Minify_Logger::log($msg); - } - - private $_path = null; - private $_locking = null; -} diff --git a/inc/lib/minify/Minify/Cache/Memcache.php b/inc/lib/minify/Minify/Cache/Memcache.php deleted file mode 100755 index 72bf454b..00000000 --- a/inc/lib/minify/Minify/Cache/Memcache.php +++ /dev/null @@ -1,140 +0,0 @@ - - * // fall back to disk caching if memcache can't connect - * $memcache = new Memcache; - * if ($memcache->connect('localhost', 11211)) { - * Minify::setCache(new Minify_Cache_Memcache($memcache)); - * } else { - * Minify::setCache(); - * } - * - **/ -class Minify_Cache_Memcache { - - /** - * Create a Minify_Cache_Memcache object, to be passed to - * Minify::setCache(). - * - * @param Memcache $memcache already-connected instance - * - * @param int $expire seconds until expiration (default = 0 - * meaning the item will not get an expiration date) - * - * @return null - */ - public function __construct($memcache, $expire = 0) - { - $this->_mc = $memcache; - $this->_exp = $expire; - } - - /** - * Write data to cache. - * - * @param string $id cache id - * - * @param string $data - * - * @return bool success - */ - public function store($id, $data) - { - return $this->_mc->set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", 0, $this->_exp); - } - - - /** - * Get the size of a cache entry - * - * @param string $id cache id - * - * @return int size in bytes - */ - public function getSize($id) - { - if (! $this->_fetch($id)) { - return false; - } - return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) - ? mb_strlen($this->_data, '8bit') - : strlen($this->_data); - } - - /** - * Does a valid cache entry exist? - * - * @param string $id cache id - * - * @param int $srcMtime mtime of the original source file(s) - * - * @return bool exists - */ - public function isValid($id, $srcMtime) - { - return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); - } - - /** - * Send the cached content to output - * - * @param string $id cache id - */ - public function display($id) - { - echo $this->_fetch($id) - ? $this->_data - : ''; - } - - /** - * Fetch the cached content - * - * @param string $id cache id - * - * @return string - */ - public function fetch($id) - { - return $this->_fetch($id) - ? $this->_data - : ''; - } - - private $_mc = null; - private $_exp = null; - - // cache of most recently fetched id - private $_lm = null; - private $_data = null; - private $_id = null; - - /** - * Fetch data and timestamp from memcache, store in instance - * - * @param string $id - * - * @return bool success - */ - private function _fetch($id) - { - if ($this->_id === $id) { - return true; - } - $ret = $this->_mc->get($id); - if (false === $ret) { - $this->_id = null; - return false; - } - list($this->_lm, $this->_data) = explode('|', $ret, 2); - $this->_id = $id; - return true; - } -} diff --git a/inc/lib/minify/Minify/Cache/ZendPlatform.php b/inc/lib/minify/Minify/Cache/ZendPlatform.php deleted file mode 100755 index 3130d69a..00000000 --- a/inc/lib/minify/Minify/Cache/ZendPlatform.php +++ /dev/null @@ -1,142 +0,0 @@ - - * Minify::setCache(new Minify_Cache_ZendPlatform()); - * - * - * @package Minify - * @author Patrick van Dissel - */ -class Minify_Cache_ZendPlatform { - - - /** - * Create a Minify_Cache_ZendPlatform object, to be passed to - * Minify::setCache(). - * - * @param int $expire seconds until expiration (default = 0 - * meaning the item will not get an expiration date) - * - * @return null - */ - public function __construct($expire = 0) - { - $this->_exp = $expire; - } - - - /** - * Write data to cache. - * - * @param string $id cache id - * - * @param string $data - * - * @return bool success - */ - public function store($id, $data) - { - return output_cache_put($id, "{$_SERVER['REQUEST_TIME']}|{$data}"); - } - - - /** - * Get the size of a cache entry - * - * @param string $id cache id - * - * @return int size in bytes - */ - public function getSize($id) - { - return $this->_fetch($id) - ? strlen($this->_data) - : false; - } - - - /** - * Does a valid cache entry exist? - * - * @param string $id cache id - * - * @param int $srcMtime mtime of the original source file(s) - * - * @return bool exists - */ - public function isValid($id, $srcMtime) - { - $ret = ($this->_fetch($id) && ($this->_lm >= $srcMtime)); - return $ret; - } - - - /** - * Send the cached content to output - * - * @param string $id cache id - */ - public function display($id) - { - echo $this->_fetch($id) - ? $this->_data - : ''; - } - - - /** - * Fetch the cached content - * - * @param string $id cache id - * - * @return string - */ - public function fetch($id) - { - return $this->_fetch($id) - ? $this->_data - : ''; - } - - - private $_exp = null; - - - // cache of most recently fetched id - private $_lm = null; - private $_data = null; - private $_id = null; - - - /** - * Fetch data and timestamp from ZendPlatform, store in instance - * - * @param string $id - * - * @return bool success - */ - private function _fetch($id) - { - if ($this->_id === $id) { - return true; - } - $ret = output_cache_get($id, $this->_exp); - if (false === $ret) { - $this->_id = null; - return false; - } - list($this->_lm, $this->_data) = explode('|', $ret, 2); - $this->_id = $id; - return true; - } -} diff --git a/inc/lib/minify/Minify/CommentPreserver.php b/inc/lib/minify/Minify/CommentPreserver.php deleted file mode 100755 index 7a359bf9..00000000 --- a/inc/lib/minify/Minify/CommentPreserver.php +++ /dev/null @@ -1,89 +0,0 @@ - - */ -class Minify_CommentPreserver { - - /** - * String to be prepended to each preserved comment - * - * @var string - */ - public static $prepend = "\n"; - - /** - * String to be appended to each preserved comment - * - * @var string - */ - public static $append = "\n"; - - /** - * Process a string outside of C-style comments that begin with "/*!" - * - * On each non-empty string outside these comments, the given processor - * function will be called. The comments will be surrounded by - * Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append. - * - * @param string $content - * @param callback $processor function - * @param array $args array of extra arguments to pass to the processor - * function (default = array()) - * @return string - */ - public static function process($content, $processor, $args = array()) - { - $ret = ''; - while (true) { - list($beforeComment, $comment, $afterComment) = self::_nextComment($content); - if ('' !== $beforeComment) { - $callArgs = $args; - array_unshift($callArgs, $beforeComment); - $ret .= call_user_func_array($processor, $callArgs); - } - if (false === $comment) { - break; - } - $ret .= $comment; - $content = $afterComment; - } - return $ret; - } - - /** - * Extract comments that YUI Compressor preserves. - * - * @param string $in input - * - * @return array 3 elements are returned. If a YUI comment is found, the - * 2nd element is the comment and the 1st and 3rd are the surrounding - * strings. If no comment is found, the entire string is returned as the - * 1st element and the other two are false. - */ - private static function _nextComment($in) - { - if ( - false === ($start = strpos($in, '/*!')) - || false === ($end = strpos($in, '*/', $start + 3)) - ) { - return array($in, false, false); - } - $ret = array( - substr($in, 0, $start) - ,self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append - ); - $endChars = (strlen($in) - $end - 2); - $ret[] = (0 === $endChars) - ? '' - : substr($in, -$endChars); - return $ret; - } -} diff --git a/inc/lib/minify/Minify/Controller/Base.php b/inc/lib/minify/Minify/Controller/Base.php deleted file mode 100755 index 5a863290..00000000 --- a/inc/lib/minify/Minify/Controller/Base.php +++ /dev/null @@ -1,222 +0,0 @@ - - */ -abstract class Minify_Controller_Base { - - /** - * Setup controller sources and set an needed options for Minify::source - * - * You must override this method in your subclass controller to set - * $this->sources. If the request is NOT valid, make sure $this->sources - * is left an empty array. Then strip any controller-specific options from - * $options and return it. To serve files, $this->sources must be an array of - * Minify_Source objects. - * - * @param array $options controller and Minify options - * - * @return array $options Minify::serve options - */ - abstract public function setupSources($options); - - /** - * Get default Minify options for this controller. - * - * Override in subclass to change defaults - * - * @return array options for Minify - */ - public function getDefaultMinifyOptions() { - return array( - 'isPublic' => true - ,'encodeOutput' => function_exists('gzdeflate') - ,'encodeMethod' => null // determine later - ,'encodeLevel' => 9 - ,'minifierOptions' => array() // no minifier options - ,'contentTypeCharset' => 'utf-8' - ,'maxAge' => 1800 // 30 minutes - ,'rewriteCssUris' => true - ,'bubbleCssImports' => false - ,'quiet' => false // serve() will send headers and output - ,'debug' => false - - // if you override these, the response codes MUST be directly after - // the first space. - ,'badRequestHeader' => 'HTTP/1.0 400 Bad Request' - ,'errorHeader' => 'HTTP/1.0 500 Internal Server Error' - - // callback function to see/modify content of all sources - ,'postprocessor' => null - // file to require to load preprocessor - ,'postprocessorRequire' => null - ); - } - - /** - * Get default minifiers for this controller. - * - * Override in subclass to change defaults - * - * @return array minifier callbacks for common types - */ - public function getDefaultMinifers() { - $ret[Minify::TYPE_JS] = array('JSMin', 'minify'); - $ret[Minify::TYPE_CSS] = array('Minify_CSS', 'minify'); - $ret[Minify::TYPE_HTML] = array('Minify_HTML', 'minify'); - return $ret; - } - - /** - * Is a user-given file within an allowable directory, existing, - * and having an extension js/css/html/txt ? - * - * This is a convenience function for controllers that have to accept - * user-given paths - * - * @param string $file full file path (already processed by realpath()) - * - * @param array $safeDirs directories where files are safe to serve. Files can also - * be in subdirectories of these directories. - * - * @return bool file is safe - * - * @deprecated use checkAllowDirs, checkNotHidden instead - */ - public static function _fileIsSafe($file, $safeDirs) - { - $pathOk = false; - foreach ((array)$safeDirs as $safeDir) { - if (strpos($file, $safeDir) === 0) { - $pathOk = true; - break; - } - } - $base = basename($file); - if (! $pathOk || ! is_file($file) || $base[0] === '.') { - return false; - } - list($revExt) = explode('.', strrev($base)); - return in_array(strrev($revExt), array('js', 'css', 'html', 'txt')); - } - - /** - * @param string $file - * @param array $allowDirs - * @param string $uri - * @return bool - * @throws Exception - */ - public static function checkAllowDirs($file, $allowDirs, $uri) - { - foreach ((array)$allowDirs as $allowDir) { - if (strpos($file, $allowDir) === 0) { - return true; - } - } - throw new Exception("File '$file' is outside \$allowDirs. If the path is" - . " resolved via an alias/symlink, look into the \$min_symlinks option." - . " E.g. \$min_symlinks['/" . dirname($uri) . "'] = '" . dirname($file) . "';"); - } - - /** - * @param string $file - * @throws Exception - */ - public static function checkNotHidden($file) - { - $b = basename($file); - if (0 === strpos($b, '.')) { - throw new Exception("Filename '$b' starts with period (may be hidden)"); - } - } - - /** - * instances of Minify_Source, which provide content and any individual minification needs. - * - * @var array - * - * @see Minify_Source - */ - public $sources = array(); - - /** - * Short name to place inside cache id - * - * The setupSources() method may choose to set this, making it easier to - * recognize a particular set of sources/settings in the cache folder. It - * will be filtered and truncated to make the final cache id <= 250 bytes. - * - * @var string - */ - public $selectionId = ''; - - /** - * Mix in default controller options with user-given options - * - * @param array $options user options - * - * @return array mixed options - */ - public final function mixInDefaultOptions($options) - { - $ret = array_merge( - $this->getDefaultMinifyOptions(), $options - ); - if (! isset($options['minifiers'])) { - $options['minifiers'] = array(); - } - $ret['minifiers'] = array_merge( - $this->getDefaultMinifers(), $options['minifiers'] - ); - return $ret; - } - - /** - * Analyze sources (if there are any) and set $options 'contentType' - * and 'lastModifiedTime' if they already aren't. - * - * @param array $options options for Minify - * - * @return array options for Minify - */ - public final function analyzeSources($options = array()) - { - if ($this->sources) { - if (! isset($options['contentType'])) { - $options['contentType'] = Minify_Source::getContentType($this->sources); - } - // last modified is needed for caching, even if setExpires is set - if (! isset($options['lastModifiedTime'])) { - $max = 0; - foreach ($this->sources as $source) { - $max = max($source->lastModified, $max); - } - $options['lastModifiedTime'] = $max; - } - } - return $options; - } - - /** - * Send message to the Minify logger - * - * @param string $msg - * - * @return null - */ - public function log($msg) { - Minify_Logger::log($msg); - } -} diff --git a/inc/lib/minify/Minify/Controller/Files.php b/inc/lib/minify/Minify/Controller/Files.php deleted file mode 100755 index f084cd07..00000000 --- a/inc/lib/minify/Minify/Controller/Files.php +++ /dev/null @@ -1,76 +0,0 @@ - - * Minify::serve('Files', array( - * 'files' => array( - * '//js/jquery.js' - * ,'//js/plugins.js' - * ,'/home/username/file.js' - * ) - * )); - * - * - * As a shortcut, the controller will replace "//" at the beginning - * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. - * - * @package Minify - * @author Stephen Clay - */ -class Minify_Controller_Files extends Minify_Controller_Base { - - /** - * Set up file sources - * - * @param array $options controller and Minify options - * @return array Minify options - * - * Controller options: - * - * 'files': (required) array of complete file paths, or a single path - */ - public function setupSources($options) { - // strip controller options - - $files = $options['files']; - // if $files is a single object, casting will break it - if (is_object($files)) { - $files = array($files); - } elseif (! is_array($files)) { - $files = (array)$files; - } - unset($options['files']); - - $sources = array(); - foreach ($files as $file) { - if ($file instanceof Minify_Source) { - $sources[] = $file; - continue; - } - if (0 === strpos($file, '//')) { - $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); - } - $realPath = realpath($file); - if (is_file($realPath)) { - $sources[] = new Minify_Source(array( - 'filepath' => $realPath - )); - } else { - $this->log("The path \"{$file}\" could not be found (or was not a file)"); - return $options; - } - } - if ($sources) { - $this->sources = $sources; - } - return $options; - } -} - diff --git a/inc/lib/minify/Minify/Controller/Groups.php b/inc/lib/minify/Minify/Controller/Groups.php deleted file mode 100755 index c4c25db1..00000000 --- a/inc/lib/minify/Minify/Controller/Groups.php +++ /dev/null @@ -1,91 +0,0 @@ - - * Minify::serve('Groups', array( - * 'groups' => array( - * 'css' => array('//css/type.css', '//css/layout.css') - * ,'js' => array('//js/jquery.js', '//js/site.js') - * ) - * )); - * - * - * If the above code were placed in /serve.php, it would enable the URLs - * /serve.php/js and /serve.php/css - * - * As a shortcut, the controller will replace "//" at the beginning - * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. - * - * @package Minify - * @author Stephen Clay - */ -class Minify_Controller_Groups extends Minify_Controller_Base { - - /** - * Set up groups of files as sources - * - * @param array $options controller and Minify options - * - * 'groups': (required) array mapping PATH_INFO strings to arrays - * of complete file paths. @see Minify_Controller_Groups - * - * @return array Minify options - */ - public function setupSources($options) { - // strip controller options - $groups = $options['groups']; - unset($options['groups']); - - // mod_fcgid places PATH_INFO in ORIG_PATH_INFO - $pi = isset($_SERVER['ORIG_PATH_INFO']) - ? substr($_SERVER['ORIG_PATH_INFO'], 1) - : (isset($_SERVER['PATH_INFO']) - ? substr($_SERVER['PATH_INFO'], 1) - : false - ); - if (false === $pi || ! isset($groups[$pi])) { - // no PATH_INFO or not a valid group - $this->log("Missing PATH_INFO or no group set for \"$pi\""); - return $options; - } - $sources = array(); - - $files = $groups[$pi]; - // if $files is a single object, casting will break it - if (is_object($files)) { - $files = array($files); - } elseif (! is_array($files)) { - $files = (array)$files; - } - foreach ($files as $file) { - if ($file instanceof Minify_Source) { - $sources[] = $file; - continue; - } - if (0 === strpos($file, '//')) { - $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); - } - $realPath = realpath($file); - if (is_file($realPath)) { - $sources[] = new Minify_Source(array( - 'filepath' => $realPath - )); - } else { - $this->log("The path \"{$file}\" could not be found (or was not a file)"); - return $options; - } - } - if ($sources) { - $this->sources = $sources; - } - return $options; - } -} - diff --git a/inc/lib/minify/Minify/Controller/MinApp.php b/inc/lib/minify/Minify/Controller/MinApp.php deleted file mode 100755 index 6943ee6b..00000000 --- a/inc/lib/minify/Minify/Controller/MinApp.php +++ /dev/null @@ -1,238 +0,0 @@ - - */ -class Minify_Controller_MinApp extends Minify_Controller_Base { - - /** - * Set up groups of files as sources - * - * @param array $options controller and Minify options - * - * @return array Minify options - */ - public function setupSources($options) { - // PHP insecure by default: realpath() and other FS functions can't handle null bytes. - foreach (array('g', 'b', 'f') as $key) { - if (isset($_GET[$key])) { - $_GET[$key] = str_replace("\x00", '', (string)$_GET[$key]); - } - } - - // filter controller options - $cOptions = array_merge( - array( - 'allowDirs' => '//' - ,'groupsOnly' => false - ,'groups' => array() - ,'noMinPattern' => '@[-\\.]min\\.(?:js|css)$@i' // matched against basename - ) - ,(isset($options['minApp']) ? $options['minApp'] : array()) - ); - unset($options['minApp']); - $sources = array(); - $this->selectionId = ''; - $firstMissingResource = null; - if (isset($_GET['g'])) { - // add group(s) - $this->selectionId .= 'g=' . $_GET['g']; - $keys = explode(',', $_GET['g']); - if ($keys != array_unique($keys)) { - $this->log("Duplicate group key found."); - return $options; - } - $keys = explode(',', $_GET['g']); - foreach ($keys as $key) { - if (! isset($cOptions['groups'][$key])) { - $this->log("A group configuration for \"{$key}\" was not found"); - return $options; - } - $files = $cOptions['groups'][$key]; - // if $files is a single object, casting will break it - if (is_object($files)) { - $files = array($files); - } elseif (! is_array($files)) { - $files = (array)$files; - } - foreach ($files as $file) { - if ($file instanceof Minify_Source) { - $sources[] = $file; - continue; - } - if (0 === strpos($file, '//')) { - $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); - } - $realpath = realpath($file); - if ($realpath && is_file($realpath)) { - $sources[] = $this->_getFileSource($realpath, $cOptions); - } else { - $this->log("The path \"{$file}\" (realpath \"{$realpath}\") could not be found (or was not a file)"); - if (null === $firstMissingResource) { - $firstMissingResource = basename($file); - continue; - } else { - $secondMissingResource = basename($file); - $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource'"); - return $options; - } - } - } - if ($sources) { - try { - $this->checkType($sources[0]); - } catch (Exception $e) { - $this->log($e->getMessage()); - return $options; - } - } - } - } - if (! $cOptions['groupsOnly'] && isset($_GET['f'])) { - // try user files - // The following restrictions are to limit the URLs that minify will - // respond to. - if (// verify at least one file, files are single comma separated, - // and are all same extension - ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'], $m) - // no "//" - || strpos($_GET['f'], '//') !== false - // no "\" - || strpos($_GET['f'], '\\') !== false - ) { - $this->log("GET param 'f' was invalid"); - return $options; - } - $ext = ".{$m[1]}"; - try { - $this->checkType($m[1]); - } catch (Exception $e) { - $this->log($e->getMessage()); - return $options; - } - $files = explode(',', $_GET['f']); - if ($files != array_unique($files)) { - $this->log("Duplicate files were specified"); - return $options; - } - if (isset($_GET['b'])) { - // check for validity - if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b']) - && false === strpos($_GET['b'], '..') - && $_GET['b'] !== '.') { - // valid base - $base = "/{$_GET['b']}/"; - } else { - $this->log("GET param 'b' was invalid"); - return $options; - } - } else { - $base = '/'; - } - $allowDirs = array(); - foreach ((array)$cOptions['allowDirs'] as $allowDir) { - $allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir)); - } - $basenames = array(); // just for cache id - foreach ($files as $file) { - $uri = $base . $file; - $path = $_SERVER['DOCUMENT_ROOT'] . $uri; - $realpath = realpath($path); - if (false === $realpath || ! is_file($realpath)) { - $this->log("The path \"{$path}\" (realpath \"{$realpath}\") could not be found (or was not a file)"); - if (null === $firstMissingResource) { - $firstMissingResource = $uri; - continue; - } else { - $secondMissingResource = $uri; - $this->log("More than one file was missing: '$firstMissingResource', '$secondMissingResource`'"); - return $options; - } - } - try { - parent::checkNotHidden($realpath); - parent::checkAllowDirs($realpath, $allowDirs, $uri); - } catch (Exception $e) { - $this->log($e->getMessage()); - return $options; - } - $sources[] = $this->_getFileSource($realpath, $cOptions); - $basenames[] = basename($realpath, $ext); - } - if ($this->selectionId) { - $this->selectionId .= '_f='; - } - $this->selectionId .= implode(',', $basenames) . $ext; - } - if ($sources) { - if (null !== $firstMissingResource) { - array_unshift($sources, new Minify_Source(array( - 'id' => 'missingFile' - // should not cause cache invalidation - ,'lastModified' => 0 - // due to caching, filename is unreliable. - ,'content' => "/* Minify: at least one missing file. See " . Minify::URL_DEBUG . " */\n" - ,'minifier' => '' - ))); - } - $this->sources = $sources; - } else { - $this->log("No sources to serve"); - } - return $options; - } - - /** - * @param string $file - * - * @param array $cOptions - * - * @return Minify_Source - */ - protected function _getFileSource($file, $cOptions) - { - $spec['filepath'] = $file; - if ($cOptions['noMinPattern'] && preg_match($cOptions['noMinPattern'], basename($file))) { - if (preg_match('~\.css$~i', $file)) { - $spec['minifyOptions']['compress'] = false; - } else { - $spec['minifier'] = ''; - } - } - return new Minify_Source($spec); - } - - protected $_type = null; - - /** - * Make sure that only source files of a single type are registered - * - * @param string $sourceOrExt - * - * @throws Exception - */ - public function checkType($sourceOrExt) - { - if ($sourceOrExt === 'js') { - $type = Minify::TYPE_JS; - } elseif ($sourceOrExt === 'css') { - $type = Minify::TYPE_CSS; - } elseif ($sourceOrExt->contentType !== null) { - $type = $sourceOrExt->contentType; - } else { - return; - } - if ($this->_type === null) { - $this->_type = $type; - } elseif ($this->_type !== $type) { - throw new Exception('Content-Type mismatch'); - } - } -} diff --git a/inc/lib/minify/Minify/Controller/Page.php b/inc/lib/minify/Minify/Controller/Page.php deleted file mode 100755 index 1095fb46..00000000 --- a/inc/lib/minify/Minify/Controller/Page.php +++ /dev/null @@ -1,68 +0,0 @@ - - */ -class Minify_Controller_Page extends Minify_Controller_Base { - - /** - * Set up source of HTML content - * - * @param array $options controller and Minify options - * @return array Minify options - * - * Controller options: - * - * 'content': (required) HTML markup - * - * 'id': (required) id of page (string for use in server-side caching) - * - * 'lastModifiedTime': timestamp of when this content changed. This - * is recommended to allow both server and client-side caching. - * - * 'minifyAll': should all CSS and Javascript blocks be individually - * minified? (default false) - * - * @todo Add 'file' option to read HTML file. - */ - public function setupSources($options) { - if (isset($options['file'])) { - $sourceSpec = array( - 'filepath' => $options['file'] - ); - $f = $options['file']; - } else { - // strip controller options - $sourceSpec = array( - 'content' => $options['content'] - ,'id' => $options['id'] - ); - $f = $options['id']; - unset($options['content'], $options['id']); - } - // something like "builder,index.php" or "directory,file.html" - $this->selectionId = strtr(substr($f, 1 + strlen(dirname(dirname($f)))), '/\\', ',,'); - - if (isset($options['minifyAll'])) { - // this will be the 2nd argument passed to Minify_HTML::minify() - $sourceSpec['minifyOptions'] = array( - 'cssMinifier' => array('Minify_CSS', 'minify') - ,'jsMinifier' => array('JSMin', 'minify') - ); - unset($options['minifyAll']); - } - $this->sources[] = new Minify_Source($sourceSpec); - - $options['contentType'] = Minify::TYPE_HTML; - return $options; - } -} - diff --git a/inc/lib/minify/Minify/Controller/Version1.php b/inc/lib/minify/Minify/Controller/Version1.php deleted file mode 100755 index 91fcf614..00000000 --- a/inc/lib/minify/Minify/Controller/Version1.php +++ /dev/null @@ -1,119 +0,0 @@ - - * Minify::serve('Version1'); - * - * - * @package Minify - * @author Stephen Clay - */ -class Minify_Controller_Version1 extends Minify_Controller_Base { - - /** - * Set up groups of files as sources - * - * @param array $options controller and Minify options - * @return array Minify options - * - */ - public function setupSources($options) { - // PHP insecure by default: realpath() and other FS functions can't handle null bytes. - if (isset($_GET['files'])) { - $_GET['files'] = str_replace("\x00", '', (string)$_GET['files']); - } - - self::_setupDefines(); - if (MINIFY_USE_CACHE) { - $cacheDir = defined('MINIFY_CACHE_DIR') - ? MINIFY_CACHE_DIR - : ''; - Minify::setCache($cacheDir); - } - $options['badRequestHeader'] = 'HTTP/1.0 404 Not Found'; - $options['contentTypeCharset'] = MINIFY_ENCODING; - - // The following restrictions are to limit the URLs that minify will - // respond to. Ideally there should be only one way to reference a file. - if (! isset($_GET['files']) - // verify at least one file, files are single comma separated, - // and are all same extension - || ! preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m) - // no "//" (makes URL rewriting easier) - || strpos($_GET['files'], '//') !== false - // no "\" - || strpos($_GET['files'], '\\') !== false - // no "./" - || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files']) - ) { - return $options; - } - - $files = explode(',', $_GET['files']); - if (count($files) > MINIFY_MAX_FILES) { - return $options; - } - - // strings for prepending to relative/absolute paths - $prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME']) - . DIRECTORY_SEPARATOR; - $prependAbsPaths = $_SERVER['DOCUMENT_ROOT']; - - $goodFiles = array(); - $hasBadSource = false; - - $allowDirs = isset($options['allowDirs']) - ? $options['allowDirs'] - : MINIFY_BASE_DIR; - - foreach ($files as $file) { - // prepend appropriate string for abs/rel paths - $file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file; - // make sure a real file! - $file = realpath($file); - // don't allow unsafe or duplicate files - if (parent::_fileIsSafe($file, $allowDirs) - && !in_array($file, $goodFiles)) - { - $goodFiles[] = $file; - $srcOptions = array( - 'filepath' => $file - ); - $this->sources[] = new Minify_Source($srcOptions); - } else { - $hasBadSource = true; - break; - } - } - if ($hasBadSource) { - $this->sources = array(); - } - if (! MINIFY_REWRITE_CSS_URLS) { - $options['rewriteCssUris'] = false; - } - return $options; - } - - private static function _setupDefines() - { - $defaults = array( - 'MINIFY_BASE_DIR' => realpath($_SERVER['DOCUMENT_ROOT']) - ,'MINIFY_ENCODING' => 'utf-8' - ,'MINIFY_MAX_FILES' => 16 - ,'MINIFY_REWRITE_CSS_URLS' => true - ,'MINIFY_USE_CACHE' => true - ); - foreach ($defaults as $const => $val) { - if (! defined($const)) { - define($const, $val); - } - } - } -} - diff --git a/inc/lib/minify/Minify/HTML/Helper.php b/inc/lib/minify/Minify/HTML/Helper.php deleted file mode 100755 index f92ab854..00000000 --- a/inc/lib/minify/Minify/HTML/Helper.php +++ /dev/null @@ -1,225 +0,0 @@ - - */ -class Minify_HTML_Helper { - public $rewriteWorks = true; - public $minAppUri = '/min'; - public $groupsConfigFile = ''; - - /** - * Get an HTML-escaped Minify URI for a group or set of files - * - * @param string|array $keyOrFiles a group key or array of filepaths/URIs - * @param array $opts options: - * 'farExpires' : (default true) append a modified timestamp for cache revving - * 'debug' : (default false) append debug flag - * 'charset' : (default 'UTF-8') for htmlspecialchars - * 'minAppUri' : (default '/min') URI of min directory - * 'rewriteWorks' : (default true) does mod_rewrite work in min app? - * 'groupsConfigFile' : specify if different - * @return string - */ - public static function getUri($keyOrFiles, $opts = array()) - { - $opts = array_merge(array( // default options - 'farExpires' => true - ,'debug' => false - ,'charset' => 'UTF-8' - ,'minAppUri' => '/min' - ,'rewriteWorks' => true - ,'groupsConfigFile' => '' - ), $opts); - $h = new self; - $h->minAppUri = $opts['minAppUri']; - $h->rewriteWorks = $opts['rewriteWorks']; - $h->groupsConfigFile = $opts['groupsConfigFile']; - if (is_array($keyOrFiles)) { - $h->setFiles($keyOrFiles, $opts['farExpires']); - } else { - $h->setGroup($keyOrFiles, $opts['farExpires']); - } - $uri = $h->getRawUri($opts['farExpires'], $opts['debug']); - return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']); - } - - /** - * Get non-HTML-escaped URI to minify the specified files - * - * @param bool $farExpires - * @param bool $debug - * @return string - */ - public function getRawUri($farExpires = true, $debug = false) - { - $path = rtrim($this->minAppUri, '/') . '/'; - if (! $this->rewriteWorks) { - $path .= '?'; - } - if (null === $this->_groupKey) { - // @todo: implement shortest uri - $path = self::_getShortestUri($this->_filePaths, $path); - } else { - $path .= "g=" . $this->_groupKey; - } - if ($debug) { - $path .= "&debug"; - } elseif ($farExpires && $this->_lastModified) { - $path .= "&" . $this->_lastModified; - } - return $path; - } - - /** - * Set the files that will comprise the URI we're building - * - * @param array $files - * @param bool $checkLastModified - */ - public function setFiles($files, $checkLastModified = true) - { - $this->_groupKey = null; - if ($checkLastModified) { - $this->_lastModified = self::getLastModified($files); - } - // normalize paths like in /min/f= - foreach ($files as $k => $file) { - if (0 === strpos($file, '//')) { - $file = substr($file, 2); - } elseif (0 === strpos($file, '/') - || 1 === strpos($file, ':\\')) { - $file = substr($file, strlen($_SERVER['DOCUMENT_ROOT']) + 1); - } - $file = strtr($file, '\\', '/'); - $files[$k] = $file; - } - $this->_filePaths = $files; - } - - /** - * Set the group of files that will comprise the URI we're building - * - * @param string $key - * @param bool $checkLastModified - */ - public function setGroup($key, $checkLastModified = true) - { - $this->_groupKey = $key; - if ($checkLastModified) { - if (! $this->groupsConfigFile) { - $this->groupsConfigFile = dirname(dirname(dirname(dirname(__FILE__)))) . '/groupsConfig.php'; - } - if (is_file($this->groupsConfigFile)) { - $gc = (require $this->groupsConfigFile); - $keys = explode(',', $key); - foreach ($keys as $key) { - if (isset($gc[$key])) { - $this->_lastModified = self::getLastModified($gc[$key], $this->_lastModified); - } - } - } - } - } - - /** - * Get the max(lastModified) of all files - * - * @param array|string $sources - * @param int $lastModified - * @return int - */ - public static function getLastModified($sources, $lastModified = 0) - { - $max = $lastModified; - foreach ((array)$sources as $source) { - if (is_object($source) && isset($source->lastModified)) { - $max = max($max, $source->lastModified); - } elseif (is_string($source)) { - if (0 === strpos($source, '//')) { - $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); - } - if (is_file($source)) { - $max = max($max, filemtime($source)); - } - } - } - return $max; - } - - protected $_groupKey = null; // if present, URI will be like g=... - protected $_filePaths = array(); - protected $_lastModified = null; - - - /** - * In a given array of strings, find the character they all have at - * a particular index - * - * @param array $arr array of strings - * @param int $pos index to check - * @return mixed a common char or '' if any do not match - */ - protected static function _getCommonCharAtPos($arr, $pos) { - if (!isset($arr[0][$pos])) { - return ''; - } - $c = $arr[0][$pos]; - $l = count($arr); - if ($l === 1) { - return $c; - } - for ($i = 1; $i < $l; ++$i) { - if ($arr[$i][$pos] !== $c) { - return ''; - } - } - return $c; - } - - /** - * Get the shortest URI to minify the set of source files - * - * @param array $paths root-relative URIs of files - * @param string $minRoot root-relative URI of the "min" application - * @return string - */ - protected static function _getShortestUri($paths, $minRoot = '/min/') { - $pos = 0; - $base = ''; - while (true) { - $c = self::_getCommonCharAtPos($paths, $pos); - if ($c === '') { - break; - } else { - $base .= $c; - } - ++$pos; - } - $base = preg_replace('@[^/]+$@', '', $base); - $uri = $minRoot . 'f=' . implode(',', $paths); - - if (substr($base, -1) === '/') { - // we have a base dir! - $basedPaths = $paths; - $l = count($paths); - for ($i = 0; $i < $l; ++$i) { - $basedPaths[$i] = substr($paths[$i], strlen($base)); - } - $base = substr($base, 0, strlen($base) - 1); - $bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths); - - $uri = strlen($uri) < strlen($bUri) - ? $uri - : $bUri; - } - return $uri; - } -} diff --git a/inc/lib/minify/Minify/JS/ClosureCompiler.php b/inc/lib/minify/Minify/JS/ClosureCompiler.php deleted file mode 100755 index e067d7c8..00000000 --- a/inc/lib/minify/Minify/JS/ClosureCompiler.php +++ /dev/null @@ -1,230 +0,0 @@ - - * - * @todo can use a stream wrapper to unit test this? - */ -class Minify_JS_ClosureCompiler { - - /** - * @var string The option key for the maximum POST byte size - */ - const OPTION_MAX_BYTES = 'maxBytes'; - - /** - * @var string The option key for additional params. @see __construct - */ - const OPTION_ADDITIONAL_OPTIONS = 'additionalParams'; - - /** - * @var string The option key for the fallback Minifier - */ - const OPTION_FALLBACK_FUNCTION = 'fallbackFunc'; - - /** - * @var string The option key for the service URL - */ - const OPTION_COMPILER_URL = 'compilerUrl'; - - /** - * @var int The default maximum POST byte size according to https://developers.google.com/closure/compiler/docs/api-ref - */ - const DEFAULT_MAX_BYTES = 200000; - - /** - * @var string[] $DEFAULT_OPTIONS The default options to pass to the compiler service - * - * @note This would be a constant if PHP allowed it - */ - private static $DEFAULT_OPTIONS = array( - 'output_format' => 'text', - 'compilation_level' => 'SIMPLE_OPTIMIZATIONS' - ); - - /** - * @var string $url URL of compiler server. defaults to Google's - */ - protected $serviceUrl = 'http://closure-compiler.appspot.com/compile'; - - /** - * @var int $maxBytes The maximum JS size that can be sent to the compiler server in bytes - */ - protected $maxBytes = self::DEFAULT_MAX_BYTES; - - /** - * @var string[] $additionalOptions Additional options to pass to the compiler service - */ - protected $additionalOptions = array(); - - /** - * @var callable Function to minify JS if service fails. Default is JSMin - */ - protected $fallbackMinifier = array('JSMin', 'minify'); - - /** - * Minify JavaScript code via HTTP request to a Closure Compiler API - * - * @param string $js input code - * @param array $options Options passed to __construct(). @see __construct - * - * @return string - */ - public static function minify($js, array $options = array()) - { - $obj = new self($options); - return $obj->min($js); - } - - /** - * @param array $options Options with keys available below: - * - * fallbackFunc : (callable) function to minify if service unavailable. Default is JSMin. - * - * compilerUrl : (string) URL to closure compiler server - * - * maxBytes : (int) The maximum amount of bytes to be sent as js_code in the POST request. - * Defaults to 200000. - * - * additionalParams : (string[]) Additional parameters to pass to the compiler server. Can be anything named - * in https://developers.google.com/closure/compiler/docs/api-ref except for js_code and - * output_info - */ - public function __construct(array $options = array()) - { - if (isset($options[self::OPTION_FALLBACK_FUNCTION])) { - $this->fallbackMinifier = $options[self::OPTION_FALLBACK_FUNCTION]; - } - if (isset($options[self::OPTION_COMPILER_URL])) { - $this->serviceUrl = $options[self::OPTION_COMPILER_URL]; - } - if (isset($options[self::OPTION_ADDITIONAL_OPTIONS]) && is_array($options[self::OPTION_ADDITIONAL_OPTIONS])) { - $this->additionalOptions = $options[self::OPTION_ADDITIONAL_OPTIONS]; - } - if (isset($options[self::OPTION_MAX_BYTES])) { - $this->maxBytes = (int) $options[self::OPTION_MAX_BYTES]; - } - } - - /** - * Call the service to perform the minification - * - * @param string $js JavaScript code - * @return string - * @throws Minify_JS_ClosureCompiler_Exception - */ - public function min($js) - { - $postBody = $this->buildPostBody($js); - - if ($this->maxBytes > 0) { - $bytes = (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) - ? mb_strlen($postBody, '8bit') - : strlen($postBody); - if ($bytes > $this->maxBytes) { - throw new Minify_JS_ClosureCompiler_Exception( - 'POST content larger than ' . $this->maxBytes . ' bytes' - ); - } - } - - $response = $this->getResponse($postBody); - - if (preg_match('/^Error\(\d\d?\):/', $response)) { - if (is_callable($this->fallbackMinifier)) { - // use fallback - $response = "/* Received errors from Closure Compiler API:\n$response" - . "\n(Using fallback minifier)\n*/\n"; - $response .= call_user_func($this->fallbackMinifier, $js); - } else { - throw new Minify_JS_ClosureCompiler_Exception($response); - } - } - - if ($response === '') { - $errors = $this->getResponse($this->buildPostBody($js, true)); - throw new Minify_JS_ClosureCompiler_Exception($errors); - } - - return $response; - } - - /** - * Get the response for a given POST body - * - * @param string $postBody - * @return string - * @throws Minify_JS_ClosureCompiler_Exception - */ - protected function getResponse($postBody) - { - $allowUrlFopen = preg_match('/1|yes|on|true/i', ini_get('allow_url_fopen')); - - if ($allowUrlFopen) { - $contents = file_get_contents($this->serviceUrl, false, stream_context_create(array( - 'http' => array( - 'method' => 'POST', - 'header' => "Content-type: application/x-www-form-urlencoded\r\nConnection: close\r\n", - 'content' => $postBody, - 'max_redirects' => 0, - 'timeout' => 15, - ) - ))); - } elseif (defined('CURLOPT_POST')) { - $ch = curl_init($this->serviceUrl); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/x-www-form-urlencoded')); - curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15); - $contents = curl_exec($ch); - curl_close($ch); - } else { - throw new Minify_JS_ClosureCompiler_Exception( - "Could not make HTTP request: allow_url_open is false and cURL not available" - ); - } - - if (false === $contents) { - throw new Minify_JS_ClosureCompiler_Exception( - "No HTTP response from server" - ); - } - - return trim($contents); - } - - /** - * Build a POST request body - * - * @param string $js JavaScript code - * @param bool $returnErrors - * @return string - */ - protected function buildPostBody($js, $returnErrors = false) - { - return http_build_query( - array_merge( - self::$DEFAULT_OPTIONS, - $this->additionalOptions, - array( - 'js_code' => $js, - 'output_info' => ($returnErrors ? 'errors' : 'compiled_code') - ) - ), - null, - '&' - ); - } -} - -class Minify_JS_ClosureCompiler_Exception extends Exception {} diff --git a/inc/lib/minify/Minify/Lines.php b/inc/lib/minify/Minify/Lines.php deleted file mode 100755 index e999a6c2..00000000 --- a/inc/lib/minify/Minify/Lines.php +++ /dev/null @@ -1,143 +0,0 @@ - - * @author Adam Pedersen (Issue 55 fix) - */ -class Minify_Lines { - - /** - * Add line numbers in C-style comments - * - * This uses a very basic parser easily fooled by comment tokens inside - * strings or regexes, but, otherwise, generally clean code will not be - * mangled. URI rewriting can also be performed. - * - * @param string $content - * - * @param array $options available options: - * - * 'id': (optional) string to identify file. E.g. file name/path - * - * 'currentDir': (default null) if given, this is assumed to be the - * directory of the current CSS file. Using this, minify will rewrite - * all relative URIs in import/url declarations to correctly point to - * the desired files, and prepend a comment with debugging information about - * this process. - * - * @return string - */ - public static function minify($content, $options = array()) - { - $id = (isset($options['id']) && $options['id']) - ? $options['id'] - : ''; - $content = str_replace("\r\n", "\n", $content); - - // Hackily rewrite strings with XPath expressions that are - // likely to throw off our dumb parser (for Prototype 1.6.1). - $content = str_replace('"/*"', '"/"+"*"', $content); - $content = preg_replace('@([\'"])(\\.?//?)\\*@', '$1$2$1+$1*', $content); - - $lines = explode("\n", $content); - $numLines = count($lines); - // determine left padding - $padTo = strlen((string) $numLines); // e.g. 103 lines = 3 digits - $inComment = false; - $i = 0; - $newLines = array(); - while (null !== ($line = array_shift($lines))) { - if (('' !== $id) && (0 == $i % 50)) { - if ($inComment) { - array_push($newLines, '', "/* {$id} *|", ''); - } else { - array_push($newLines, '', "/* {$id} */", ''); - } - } - ++$i; - $newLines[] = self::_addNote($line, $i, $inComment, $padTo); - $inComment = self::_eolInComment($line, $inComment); - } - $content = implode("\n", $newLines) . "\n"; - - // check for desired URI rewriting - if (isset($options['currentDir'])) { - Minify_CSS_UriRewriter::$debugText = ''; - $content = Minify_CSS_UriRewriter::rewrite( - $content - ,$options['currentDir'] - ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'] - ,isset($options['symlinks']) ? $options['symlinks'] : array() - ); - $content = "/* Minify_CSS_UriRewriter::\$debugText\n\n" - . Minify_CSS_UriRewriter::$debugText . "*/\n" - . $content; - } - - return $content; - } - - /** - * Is the parser within a C-style comment at the end of this line? - * - * @param string $line current line of code - * - * @param bool $inComment was the parser in a comment at the - * beginning of the line? - * - * @return bool - */ - private static function _eolInComment($line, $inComment) - { - // crude way to avoid things like // */ - $line = preg_replace('~//.*?(\\*/|/\\*).*~', '', $line); - - while (strlen($line)) { - $search = $inComment - ? '*/' - : '/*'; - $pos = strpos($line, $search); - if (false === $pos) { - return $inComment; - } else { - if ($pos == 0 - || ($inComment - ? substr($line, $pos, 3) - : substr($line, $pos-1, 3)) != '*/*') - { - $inComment = ! $inComment; - } - $line = substr($line, $pos + 2); - } - } - return $inComment; - } - - /** - * Prepend a comment (or note) to the given line - * - * @param string $line current line of code - * - * @param string $note content of note/comment - * - * @param bool $inComment was the parser in a comment at the - * beginning of the line? - * - * @param int $padTo minimum width of comment - * - * @return string - */ - private static function _addNote($line, $note, $inComment, $padTo) - { - return $inComment - ? '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line - : '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line; - } -} diff --git a/inc/lib/minify/Minify/Logger.php b/inc/lib/minify/Minify/Logger.php deleted file mode 100755 index 8eb72f45..00000000 --- a/inc/lib/minify/Minify/Logger.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * @todo lose this singleton! pass log object in Minify::serve and distribute to others - */ -class Minify_Logger { - - /** - * Set logger object. - * - * The object should have a method "log" that accepts a value as 1st argument and - * an optional string label as the 2nd. - * - * @param mixed $obj or a "falsey" value to disable - * @return null - */ - public static function setLogger($obj = null) { - self::$_logger = $obj - ? $obj - : null; - } - - /** - * Pass a message to the logger (if set) - * - * @param string $msg message to log - * @return null - */ - public static function log($msg, $label = 'Minify') { - if (! self::$_logger) return; - self::$_logger->log($msg, $label); - } - - /** - * @var mixed logger object (like FirePHP) or null (i.e. no logger available) - */ - private static $_logger = null; -} diff --git a/inc/lib/minify/Minify/Packer.php b/inc/lib/minify/Minify/Packer.php deleted file mode 100755 index 949c3eef..00000000 --- a/inc/lib/minify/Minify/Packer.php +++ /dev/null @@ -1,37 +0,0 @@ -pack()); - } -} diff --git a/inc/lib/minify/Minify/Source.php b/inc/lib/minify/Minify/Source.php deleted file mode 100755 index 5a85d10d..00000000 --- a/inc/lib/minify/Minify/Source.php +++ /dev/null @@ -1,187 +0,0 @@ - - */ -class Minify_Source { - - /** - * @var int time of last modification - */ - public $lastModified = null; - - /** - * @var callback minifier function specifically for this source. - */ - public $minifier = null; - - /** - * @var array minification options specific to this source. - */ - public $minifyOptions = null; - - /** - * @var string full path of file - */ - public $filepath = null; - - /** - * @var string HTTP Content Type (Minify requires one of the constants Minify::TYPE_*) - */ - public $contentType = null; - - /** - * Create a Minify_Source - * - * In the $spec array(), you can either provide a 'filepath' to an existing - * file (existence will not be checked!) or give 'id' (unique string for - * the content), 'content' (the string content) and 'lastModified' - * (unixtime of last update). - * - * As a shortcut, the controller will replace "//" at the beginning - * of a filepath with $_SERVER['DOCUMENT_ROOT'] . '/'. - * - * @param array $spec options - */ - public function __construct($spec) - { - if (isset($spec['filepath'])) { - if (0 === strpos($spec['filepath'], '//')) { - $spec['filepath'] = $_SERVER['DOCUMENT_ROOT'] . substr($spec['filepath'], 1); - } - $segments = explode('.', $spec['filepath']); - $ext = strtolower(array_pop($segments)); - switch ($ext) { - case 'js' : $this->contentType = 'application/x-javascript'; - break; - case 'css' : $this->contentType = 'text/css'; - break; - case 'htm' : // fallthrough - case 'html' : $this->contentType = 'text/html'; - break; - } - $this->filepath = $spec['filepath']; - $this->_id = $spec['filepath']; - $this->lastModified = filemtime($spec['filepath']) - // offset for Windows uploaders with out of sync clocks - + round(Minify::$uploaderHoursBehind * 3600); - } elseif (isset($spec['id'])) { - $this->_id = 'id::' . $spec['id']; - if (isset($spec['content'])) { - $this->_content = $spec['content']; - } else { - $this->_getContentFunc = $spec['getContentFunc']; - } - $this->lastModified = isset($spec['lastModified']) - ? $spec['lastModified'] - : time(); - } - if (isset($spec['contentType'])) { - $this->contentType = $spec['contentType']; - } - if (isset($spec['minifier'])) { - $this->minifier = $spec['minifier']; - } - if (isset($spec['minifyOptions'])) { - $this->minifyOptions = $spec['minifyOptions']; - } - } - - /** - * Get content - * - * @return string - */ - public function getContent() - { - $content = (null !== $this->filepath) - ? file_get_contents($this->filepath) - : ((null !== $this->_content) - ? $this->_content - : call_user_func($this->_getContentFunc, $this->_id) - ); - // remove UTF-8 BOM if present - return (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) - ? substr($content, 3) - : $content; - } - - /** - * Get id - * - * @return string - */ - public function getId() - { - return $this->_id; - } - - /** - * Verifies a single minification call can handle all sources - * - * @param array $sources Minify_Source instances - * - * @return bool true iff there no sources with specific minifier preferences. - */ - public static function haveNoMinifyPrefs($sources) - { - foreach ($sources as $source) { - if (null !== $source->minifier - || null !== $source->minifyOptions) { - return false; - } - } - return true; - } - - /** - * Get unique string for a set of sources - * - * @param array $sources Minify_Source instances - * - * @return string - */ - public static function getDigest($sources) - { - foreach ($sources as $source) { - $info[] = array( - $source->_id, $source->minifier, $source->minifyOptions - ); - } - return md5(serialize($info)); - } - - /** - * Get content type from a group of sources - * - * This is called if the user doesn't pass in a 'contentType' options - * - * @param array $sources Minify_Source instances - * - * @return string content type. e.g. 'text/css' - */ - public static function getContentType($sources) - { - foreach ($sources as $source) { - if ($source->contentType !== null) { - return $source->contentType; - } - } - return 'text/plain'; - } - - protected $_content = null; - protected $_getContentFunc = null; - protected $_id = null; -} - diff --git a/inc/lib/minify/Minify/YUI/CssCompressor.java b/inc/lib/minify/Minify/YUI/CssCompressor.java deleted file mode 100755 index 3fb497a9..00000000 --- a/inc/lib/minify/Minify/YUI/CssCompressor.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * YUI Compressor - * http://developer.yahoo.com/yui/compressor/ - * Author: Julien Lecomte - http://www.julienlecomte.net/ - * Author: Isaac Schlueter - http://foohack.com/ - * Author: Stoyan Stefanov - http://phpied.com/ - * Copyright (c) 2011 Yahoo! Inc. All rights reserved. - * The copyrights embodied in the content of this file are licensed - * by Yahoo! Inc. under the BSD (revised) open source license. - */ -package com.yahoo.platform.yui.compressor; - -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import java.util.ArrayList; - -public class CssCompressor { - - private StringBuffer srcsb = new StringBuffer(); - - public CssCompressor(Reader in) throws IOException { - // Read the stream... - int c; - while ((c = in.read()) != -1) { - srcsb.append((char) c); - } - } - - // Leave data urls alone to increase parse performance. - protected String extractDataUrls(String css, ArrayList preservedTokens) { - - int maxIndex = css.length() - 1; - int appendIndex = 0; - - StringBuffer sb = new StringBuffer(); - - Pattern p = Pattern.compile("url\\(\\s*([\"']?)data\\:"); - Matcher m = p.matcher(css); - - /* - * Since we need to account for non-base64 data urls, we need to handle - * ' and ) being part of the data string. Hence switching to indexOf, - * to determine whether or not we have matching string terminators and - * handling sb appends directly, instead of using matcher.append* methods. - */ - - while (m.find()) { - - int startIndex = m.start() + 4; // "url(".length() - String terminator = m.group(1); // ', " or empty (not quoted) - - if (terminator.length() == 0) { - terminator = ")"; - } - - boolean foundTerminator = false; - - int endIndex = m.end() - 1; - while(foundTerminator == false && endIndex+1 <= maxIndex) { - endIndex = css.indexOf(terminator, endIndex+1); - - if ((endIndex > 0) && (css.charAt(endIndex-1) != '\\')) { - foundTerminator = true; - if (!")".equals(terminator)) { - endIndex = css.indexOf(")", endIndex); - } - } - } - - // Enough searching, start moving stuff over to the buffer - sb.append(css.substring(appendIndex, m.start())); - - if (foundTerminator) { - String token = css.substring(startIndex, endIndex); - token = token.replaceAll("\\s+", ""); - preservedTokens.add(token); - - String preserver = "url(___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___)"; - sb.append(preserver); - - appendIndex = endIndex + 1; - } else { - // No end terminator found, re-add the whole match. Should we throw/warn here? - sb.append(css.substring(m.start(), m.end())); - appendIndex = m.end(); - } - } - - sb.append(css.substring(appendIndex)); - - return sb.toString(); - } - - public void compress(Writer out, int linebreakpos) - throws IOException { - - Pattern p; - Matcher m; - String css = srcsb.toString(); - - int startIndex = 0; - int endIndex = 0; - int i = 0; - int max = 0; - ArrayList preservedTokens = new ArrayList(0); - ArrayList comments = new ArrayList(0); - String token; - int totallen = css.length(); - String placeholder; - - css = this.extractDataUrls(css, preservedTokens); - - StringBuffer sb = new StringBuffer(css); - - // collect all comment blocks... - while ((startIndex = sb.indexOf("/*", startIndex)) >= 0) { - endIndex = sb.indexOf("*/", startIndex + 2); - if (endIndex < 0) { - endIndex = totallen; - } - - token = sb.substring(startIndex + 2, endIndex); - comments.add(token); - sb.replace(startIndex + 2, endIndex, "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + (comments.size() - 1) + "___"); - startIndex += 2; - } - css = sb.toString(); - - // preserve strings so their content doesn't get accidentally minified - sb = new StringBuffer(); - p = Pattern.compile("(\"([^\\\\\"]|\\\\.|\\\\)*\")|(\'([^\\\\\']|\\\\.|\\\\)*\')"); - m = p.matcher(css); - while (m.find()) { - token = m.group(); - char quote = token.charAt(0); - token = token.substring(1, token.length() - 1); - - // maybe the string contains a comment-like substring? - // one, maybe more? put'em back then - if (token.indexOf("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_") >= 0) { - for (i = 0, max = comments.size(); i < max; i += 1) { - token = token.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", comments.get(i).toString()); - } - } - - // minify alpha opacity in filter strings - token = token.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity="); - - preservedTokens.add(token); - String preserver = quote + "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___" + quote; - m.appendReplacement(sb, preserver); - } - m.appendTail(sb); - css = sb.toString(); - - - // strings are safe, now wrestle the comments - for (i = 0, max = comments.size(); i < max; i += 1) { - - token = comments.get(i).toString(); - placeholder = "___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___"; - - // ! in the first position of the comment means preserve - // so push to the preserved tokens while stripping the ! - if (token.startsWith("!")) { - preservedTokens.add(token); - css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); - continue; - } - - // \ in the last position looks like hack for Mac/IE5 - // shorten that to /*\*/ and the next one to /**/ - if (token.endsWith("\\")) { - preservedTokens.add("\\"); - css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); - i = i + 1; // attn: advancing the loop - preservedTokens.add(""); - css = css.replace("___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_" + i + "___", "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); - continue; - } - - // keep empty comments after child selectors (IE7 hack) - // e.g. html >/**/ body - if (token.length() == 0) { - startIndex = css.indexOf(placeholder); - if (startIndex > 2) { - if (css.charAt(startIndex - 3) == '>') { - preservedTokens.add(""); - css = css.replace(placeholder, "___YUICSSMIN_PRESERVED_TOKEN_" + (preservedTokens.size() - 1) + "___"); - } - } - } - - // in all other cases kill the comment - css = css.replace("/*" + placeholder + "*/", ""); - } - - - // Normalize all whitespace strings to single spaces. Easier to work with that way. - css = css.replaceAll("\\s+", " "); - - // Remove the spaces before the things that should not have spaces before them. - // But, be careful not to turn "p :link {...}" into "p:link{...}" - // Swap out any pseudo-class colons with the token, and then swap back. - sb = new StringBuffer(); - p = Pattern.compile("(^|\\})(([^\\{:])+:)+([^\\{]*\\{)"); - m = p.matcher(css); - while (m.find()) { - String s = m.group(); - s = s.replaceAll(":", "___YUICSSMIN_PSEUDOCLASSCOLON___"); - s = s.replaceAll( "\\\\", "\\\\\\\\" ).replaceAll( "\\$", "\\\\\\$" ); - m.appendReplacement(sb, s); - } - m.appendTail(sb); - css = sb.toString(); - // Remove spaces before the things that should not have spaces before them. - css = css.replaceAll("\\s+([!{};:>+\\(\\)\\],])", "$1"); - // bring back the colon - css = css.replaceAll("___YUICSSMIN_PSEUDOCLASSCOLON___", ":"); - - // retain space for special IE6 cases - css = css.replaceAll(":first\\-(line|letter)(\\{|,)", ":first-$1 $2"); - - // no space after the end of a preserved comment - css = css.replaceAll("\\*/ ", "*/"); - - // If there is a @charset, then only allow one, and push to the top of the file. - css = css.replaceAll("^(.*)(@charset \"[^\"]*\";)", "$2$1"); - css = css.replaceAll("^(\\s*@charset [^;]+;\\s*)+", "$1"); - - // Put the space back in some cases, to support stuff like - // @media screen and (-webkit-min-device-pixel-ratio:0){ - css = css.replaceAll("\\band\\(", "and ("); - - // Remove the spaces after the things that should not have spaces after them. - css = css.replaceAll("([!{}:;>+\\(\\[,])\\s+", "$1"); - - // remove unnecessary semicolons - css = css.replaceAll(";+}", "}"); - - // Replace 0(px,em,%) with 0. - css = css.replaceAll("([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)", "$1$2"); - - // Replace 0 0 0 0; with 0. - css = css.replaceAll(":0 0 0 0(;|})", ":0$1"); - css = css.replaceAll(":0 0 0(;|})", ":0$1"); - css = css.replaceAll(":0 0(;|})", ":0$1"); - - - // Replace background-position:0; with background-position:0 0; - // same for transform-origin - sb = new StringBuffer(); - p = Pattern.compile("(?i)(background-position|transform-origin|webkit-transform-origin|moz-transform-origin|o-transform-origin|ms-transform-origin):0(;|})"); - m = p.matcher(css); - while (m.find()) { - m.appendReplacement(sb, m.group(1).toLowerCase() + ":0 0" + m.group(2)); - } - m.appendTail(sb); - css = sb.toString(); - - // Replace 0.6 to .6, but only when preceded by : or a white-space - css = css.replaceAll("(:|\\s)0+\\.(\\d+)", "$1.$2"); - - // Shorten colors from rgb(51,102,153) to #336699 - // This makes it more likely that it'll get further compressed in the next step. - p = Pattern.compile("rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)"); - m = p.matcher(css); - sb = new StringBuffer(); - while (m.find()) { - String[] rgbcolors = m.group(1).split(","); - StringBuffer hexcolor = new StringBuffer("#"); - for (i = 0; i < rgbcolors.length; i++) { - int val = Integer.parseInt(rgbcolors[i]); - if (val < 16) { - hexcolor.append("0"); - } - hexcolor.append(Integer.toHexString(val)); - } - m.appendReplacement(sb, hexcolor.toString()); - } - m.appendTail(sb); - css = sb.toString(); - - // Shorten colors from #AABBCC to #ABC. Note that we want to make sure - // the color is not preceded by either ", " or =. Indeed, the property - // filter: chroma(color="#FFFFFF"); - // would become - // filter: chroma(color="#FFF"); - // which makes the filter break in IE. - // We also want to make sure we're only compressing #AABBCC patterns inside { }, not id selectors ( #FAABAC {} ) - // We also want to avoid compressing invalid values (e.g. #AABBCCD to #ABCD) - p = Pattern.compile("(\\=\\s*?[\"']?)?" + "#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])" + "(:?\\}|[^0-9a-fA-F{][^{]*?\\})"); - - m = p.matcher(css); - sb = new StringBuffer(); - int index = 0; - - while (m.find(index)) { - - sb.append(css.substring(index, m.start())); - - boolean isFilter = (m.group(1) != null && !"".equals(m.group(1))); - - if (isFilter) { - // Restore, as is. Compression will break filters - sb.append(m.group(1) + "#" + m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)); - } else { - if( m.group(2).equalsIgnoreCase(m.group(3)) && - m.group(4).equalsIgnoreCase(m.group(5)) && - m.group(6).equalsIgnoreCase(m.group(7))) { - - // #AABBCC pattern - sb.append("#" + (m.group(3) + m.group(5) + m.group(7)).toLowerCase()); - - } else { - - // Non-compressible color, restore, but lower case. - sb.append("#" + (m.group(2) + m.group(3) + m.group(4) + m.group(5) + m.group(6) + m.group(7)).toLowerCase()); - } - } - - index = m.end(7); - } - - sb.append(css.substring(index)); - css = sb.toString(); - - // border: none -> border:0 - sb = new StringBuffer(); - p = Pattern.compile("(?i)(border|border-top|border-right|border-bottom|border-right|outline|background):none(;|})"); - m = p.matcher(css); - while (m.find()) { - m.appendReplacement(sb, m.group(1).toLowerCase() + ":0" + m.group(2)); - } - m.appendTail(sb); - css = sb.toString(); - - // shorter opacity IE filter - css = css.replaceAll("(?i)progid:DXImageTransform.Microsoft.Alpha\\(Opacity=", "alpha(opacity="); - - // Remove empty rules. - css = css.replaceAll("[^\\}\\{/;]+\\{\\}", ""); - - // TODO: Should this be after we re-insert tokens. These could alter the break points. However then - // we'd need to make sure we don't break in the middle of a string etc. - if (linebreakpos >= 0) { - // Some source control tools don't like it when files containing lines longer - // than, say 8000 characters, are checked in. The linebreak option is used in - // that case to split long lines after a specific column. - i = 0; - int linestartpos = 0; - sb = new StringBuffer(css); - while (i < sb.length()) { - char c = sb.charAt(i++); - if (c == '}' && i - linestartpos > linebreakpos) { - sb.insert(i, '\n'); - linestartpos = i; - } - } - - css = sb.toString(); - } - - // Replace multiple semi-colons in a row by a single one - // See SF bug #1980989 - css = css.replaceAll(";;+", ";"); - - // restore preserved comments and strings - for(i = 0, max = preservedTokens.size(); i < max; i++) { - css = css.replace("___YUICSSMIN_PRESERVED_TOKEN_" + i + "___", preservedTokens.get(i).toString()); - } - - // Trim the final string (for any leading or trailing white spaces) - css = css.trim(); - - // Write the output... - out.write(css); - } -} diff --git a/inc/lib/minify/Minify/YUI/CssCompressor.php b/inc/lib/minify/Minify/YUI/CssCompressor.php deleted file mode 100755 index ae3443d4..00000000 --- a/inc/lib/minify/Minify/YUI/CssCompressor.php +++ /dev/null @@ -1,171 +0,0 @@ -+\\(\\)\\],])@", "$1", $css); - $css = str_replace("___PSEUDOCLASSCOLON___", ":", $css); - - // Remove the spaces after the things that should not have spaces after them. - $css = preg_replace("@([!{}:;>+\\(\\[,])\\s+@", "$1", $css); - - // Add the semicolon where it's missing. - $css = preg_replace("@([^;\\}])}@", "$1;}", $css); - - // Replace 0(px,em,%) with 0. - $css = preg_replace("@([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)@", "$1$2", $css); - - // Replace 0 0 0 0; with 0. - $css = str_replace(":0 0 0 0;", ":0;", $css); - $css = str_replace(":0 0 0;", ":0;", $css); - $css = str_replace(":0 0;", ":0;", $css); - - // Replace background-position:0; with background-position:0 0; - $css = str_replace("background-position:0;", "background-position:0 0;", $css); - - // Replace 0.6 to .6, but only when preceded by : or a white-space - $css = preg_replace("@(:|\\s)0+\\.(\\d+)@", "$1.$2", $css); - - // Shorten colors from rgb(51,102,153) to #336699 - // This makes it more likely that it'll get further compressed in the next step. - $css = preg_replace_callback("@rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)@", array($this, '_shortenRgbCB'), $css); - - // Shorten colors from #AABBCC to #ABC. Note that we want to make sure - // the color is not preceded by either ", " or =. Indeed, the property - // filter: chroma(color="#FFFFFF"); - // would become - // filter: chroma(color="#FFF"); - // which makes the filter break in IE. - $css = preg_replace_callback("@([^\"'=\\s])(\\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])@", array($this, '_shortenHexCB'), $css); - - // Remove empty rules. - $css = preg_replace("@[^\\}]+\\{;\\}@", "", $css); - - $linebreakpos = isset($this->_options['linebreakpos']) - ? $this->_options['linebreakpos'] - : 0; - - if ($linebreakpos > 0) { - // Some source control tools don't like it when files containing lines longer - // than, say 8000 characters, are checked in. The linebreak option is used in - // that case to split long lines after a specific column. - $i = 0; - $linestartpos = 0; - $sb = $css; - - // make sure strlen returns byte count - $mbIntEnc = null; - if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) { - $mbIntEnc = mb_internal_encoding(); - mb_internal_encoding('8bit'); - } - $sbLength = strlen($css); - while ($i < $sbLength) { - $c = $sb[$i++]; - if ($c === '}' && $i - $linestartpos > $linebreakpos) { - $sb = substr_replace($sb, "\n", $i, 0); - $sbLength++; - $linestartpos = $i; - } - } - $css = $sb; - - // undo potential mb_encoding change - if ($mbIntEnc !== null) { - mb_internal_encoding($mbIntEnc); - } - } - - // Replace the pseudo class for the Box Model Hack - $css = str_replace("___PSEUDOCLASSBMH___", "\"\\\\\"}\\\\\"\"", $css); - - // Replace multiple semi-colons in a row by a single one - // See SF bug #1980989 - $css = preg_replace("@;;+@", ";", $css); - - // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/ - $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css); - - // Trim the final string (for any leading or trailing white spaces) - $css = trim($css); - - return $css; - } - - protected function _removeSpacesCB($m) - { - return str_replace(':', '___PSEUDOCLASSCOLON___', $m[0]); - } - - protected function _shortenRgbCB($m) - { - $rgbcolors = explode(',', $m[1]); - $hexcolor = '#'; - for ($i = 0; $i < count($rgbcolors); $i++) { - $val = round($rgbcolors[$i]); - if ($val < 16) { - $hexcolor .= '0'; - } - $hexcolor .= dechex($val); - } - return $hexcolor; - } - - protected function _shortenHexCB($m) - { - // Test for AABBCC pattern - if ((strtolower($m[3])===strtolower($m[4])) && - (strtolower($m[5])===strtolower($m[6])) && - (strtolower($m[7])===strtolower($m[8]))) { - return $m[1] . $m[2] . "#" . $m[3] . $m[5] . $m[7]; - } else { - return $m[0]; - } - } -} \ No newline at end of file diff --git a/inc/lib/minify/Minify/YUICompressor.php b/inc/lib/minify/Minify/YUICompressor.php deleted file mode 100755 index 5762e890..00000000 --- a/inc/lib/minify/Minify/YUICompressor.php +++ /dev/null @@ -1,156 +0,0 @@ - - * Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.4.6.jar'; - * Minify_YUICompressor::$tempDir = '/tmp'; - * $code = Minify_YUICompressor::minifyJs( - * $code - * ,array('nomunge' => true, 'line-break' => 1000) - * ); - * - * - * Note: In case you run out stack (default is 512k), you may increase stack size in $options: - * array('stack-size' => '2048k') - * - * @todo unit tests, $options docs - * - * @package Minify - * @author Stephen Clay - */ -class Minify_YUICompressor { - - /** - * Filepath of the YUI Compressor jar file. This must be set before - * calling minifyJs() or minifyCss(). - * - * @var string - */ - public static $jarFile = null; - - /** - * Writable temp directory. This must be set before calling minifyJs() - * or minifyCss(). - * - * @var string - */ - public static $tempDir = null; - - /** - * Filepath of "java" executable (may be needed if not in shell's PATH) - * - * @var string - */ - public static $javaExecutable = 'java'; - - /** - * Minify a Javascript string - * - * @param string $js - * - * @param array $options (verbose is ignored) - * - * @see http://www.julienlecomte.net/yuicompressor/README - * - * @return string - */ - public static function minifyJs($js, $options = array()) - { - return self::_minify('js', $js, $options); - } - - /** - * Minify a CSS string - * - * @param string $css - * - * @param array $options (verbose is ignored) - * - * @see http://www.julienlecomte.net/yuicompressor/README - * - * @return string - */ - public static function minifyCss($css, $options = array()) - { - return self::_minify('css', $css, $options); - } - - private static function _minify($type, $content, $options) - { - self::_prepare(); - if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) { - throw new Exception('Minify_YUICompressor : could not create temp file in "'.self::$tempDir.'".'); - } - file_put_contents($tmpFile, $content); - exec(self::_getCmd($options, $type, $tmpFile), $output, $result_code); - unlink($tmpFile); - if ($result_code != 0) { - throw new Exception('Minify_YUICompressor : YUI compressor execution failed.'); - } - return implode("\n", $output); - } - - private static function _getCmd($userOptions, $type, $tmpFile) - { - $o = array_merge( - array( - 'charset' => '' - ,'line-break' => 5000 - ,'type' => $type - ,'nomunge' => false - ,'preserve-semi' => false - ,'disable-optimizations' => false - ,'stack-size' => '' - ) - ,$userOptions - ); - $cmd = self::$javaExecutable - . (!empty($o['stack-size']) - ? ' -Xss' . $o['stack-size'] - : '') - . ' -jar ' . escapeshellarg(self::$jarFile) - . " --type {$type}" - . (preg_match('/^[\\da-zA-Z0-9\\-]+$/', $o['charset']) - ? " --charset {$o['charset']}" - : '') - . (is_numeric($o['line-break']) && $o['line-break'] >= 0 - ? ' --line-break ' . (int)$o['line-break'] - : ''); - if ($type === 'js') { - foreach (array('nomunge', 'preserve-semi', 'disable-optimizations') as $opt) { - $cmd .= $o[$opt] - ? " --{$opt}" - : ''; - } - } - return $cmd . ' ' . escapeshellarg($tmpFile); - } - - private static function _prepare() - { - if (! is_file(self::$jarFile)) { - throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.'); - } - if (! is_readable(self::$jarFile)) { - throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not readable.'); - } - if (! is_dir(self::$tempDir)) { - throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.'); - } - if (! is_writable(self::$tempDir)) { - throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.'); - } - } -} - diff --git a/inc/lib/minify/MrClay/Cli.php b/inc/lib/minify/MrClay/Cli.php deleted file mode 100755 index 9aa8e06f..00000000 --- a/inc/lib/minify/MrClay/Cli.php +++ /dev/null @@ -1,384 +0,0 @@ -values. - * - * You may also specify that some arguments be used to provide input/output. By communicating - * solely through the file pointers provided by openInput()/openOutput(), you can make your - * app more flexible to end users. - * - * @author Steve Clay - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -class Cli { - - /** - * @var array validation errors - */ - public $errors = array(); - - /** - * @var array option values available after validation. - * - * E.g. array( - * 'a' => false // option was missing - * ,'b' => true // option was present - * ,'c' => "Hello" // option had value - * ,'f' => "/home/user/file" // file path from root - * ,'f.raw' => "~/file" // file path as given to option - * ) - */ - public $values = array(); - - /** - * @var array - */ - public $moreArgs = array(); - - /** - * @var array - */ - public $debug = array(); - - /** - * @var bool The user wants help info - */ - public $isHelpRequest = false; - - /** - * @var Arg[] - */ - protected $_args = array(); - - /** - * @var resource - */ - protected $_stdin = null; - - /** - * @var resource - */ - protected $_stdout = null; - - /** - * @param bool $exitIfNoStdin (default true) Exit() if STDIN is not defined - */ - public function __construct($exitIfNoStdin = true) - { - if ($exitIfNoStdin && ! defined('STDIN')) { - exit('This script is for command-line use only.'); - } - if (isset($GLOBALS['argv'][1]) - && ($GLOBALS['argv'][1] === '-?' || $GLOBALS['argv'][1] === '--help')) { - $this->isHelpRequest = true; - } - } - - /** - * @param Arg|string $letter - * @return Arg - */ - public function addOptionalArg($letter) - { - return $this->addArgument($letter, false); - } - - /** - * @param Arg|string $letter - * @return Arg - */ - public function addRequiredArg($letter) - { - return $this->addArgument($letter, true); - } - - /** - * @param string $letter - * @param bool $required - * @param Arg|null $arg - * @return Arg - * @throws InvalidArgumentException - */ - public function addArgument($letter, $required, Arg $arg = null) - { - if (! preg_match('/^[a-zA-Z]$/', $letter)) { - throw new InvalidArgumentException('$letter must be in [a-zA-Z]'); - } - if (! $arg) { - $arg = new Arg($required); - } - $this->_args[$letter] = $arg; - return $arg; - } - - /** - * @param string $letter - * @return Arg|null - */ - public function getArgument($letter) - { - return isset($this->_args[$letter]) ? $this->_args[$letter] : null; - } - - /* - * Read and validate options - * - * @return bool true if all options are valid - */ - public function validate() - { - $options = ''; - $this->errors = array(); - $this->values = array(); - $this->_stdin = null; - - if ($this->isHelpRequest) { - return false; - } - - $lettersUsed = ''; - foreach ($this->_args as $letter => $arg) { - /* @var Arg $arg */ - $options .= $letter; - $lettersUsed .= $letter; - - if ($arg->mayHaveValue || $arg->mustHaveValue) { - $options .= ($arg->mustHaveValue ? ':' : '::'); - } - } - - $this->debug['argv'] = $GLOBALS['argv']; - $argvCopy = array_slice($GLOBALS['argv'], 1); - $o = getopt($options); - $this->debug['getopt_options'] = $options; - $this->debug['getopt_return'] = $o; - - foreach ($this->_args as $letter => $arg) { - /* @var Arg $arg */ - $this->values[$letter] = false; - if (isset($o[$letter])) { - if (is_bool($o[$letter])) { - - // remove from argv copy - $k = array_search("-$letter", $argvCopy); - if ($k !== false) { - array_splice($argvCopy, $k, 1); - } - - if ($arg->mustHaveValue) { - $this->addError($letter, "Missing value"); - } else { - $this->values[$letter] = true; - } - } else { - // string - $this->values[$letter] = $o[$letter]; - $v =& $this->values[$letter]; - - // remove from argv copy - // first look for -ovalue or -o=value - $pattern = "/^-{$letter}=?" . preg_quote($v, '/') . "$/"; - $foundInArgv = false; - foreach ($argvCopy as $k => $argV) { - if (preg_match($pattern, $argV)) { - array_splice($argvCopy, $k, 1); - $foundInArgv = true; - break; - } - } - if (! $foundInArgv) { - // space separated - $k = array_search("-$letter", $argvCopy); - if ($k !== false) { - array_splice($argvCopy, $k, 2); - } - } - - // check that value isn't really another option - if (strlen($lettersUsed) > 1) { - $pattern = "/^-[" . str_replace($letter, '', $lettersUsed) . "]/i"; - if (preg_match($pattern, $v)) { - $this->addError($letter, "Value was read as another option: %s", $v); - return false; - } - } - if ($arg->assertFile || $arg->assertDir) { - if ($v[0] !== '/' && $v[0] !== '~') { - $this->values["$letter.raw"] = $v; - $v = getcwd() . "/$v"; - } - } - if ($arg->assertFile) { - if ($arg->useAsInfile) { - $this->_stdin = $v; - } elseif ($arg->useAsOutfile) { - $this->_stdout = $v; - } - if ($arg->assertReadable && ! is_readable($v)) { - $this->addError($letter, "File not readable: %s", $v); - continue; - } - if ($arg->assertWritable) { - if (is_file($v)) { - if (! is_writable($v)) { - $this->addError($letter, "File not writable: %s", $v); - } - } else { - if (! is_writable(dirname($v))) { - $this->addError($letter, "Directory not writable: %s", dirname($v)); - } - } - } - } elseif ($arg->assertDir && $arg->assertWritable && ! is_writable($v)) { - $this->addError($letter, "Directory not readable: %s", $v); - } - } - } else { - if ($arg->isRequired()) { - $this->addError($letter, "Missing"); - } - } - } - $this->moreArgs = $argvCopy; - reset($this->moreArgs); - return empty($this->errors); - } - - /** - * Get the full paths of file(s) passed in as unspecified arguments - * - * @return array - */ - public function getPathArgs() - { - $r = $this->moreArgs; - foreach ($r as $k => $v) { - if ($v[0] !== '/' && $v[0] !== '~') { - $v = getcwd() . "/$v"; - $v = str_replace('/./', '/', $v); - do { - $v = preg_replace('@/[^/]+/\\.\\./@', '/', $v, 1, $changed); - } while ($changed); - $r[$k] = $v; - } - } - return $r; - } - - /** - * Get a short list of errors with options - * - * @return string - */ - public function getErrorReport() - { - if (empty($this->errors)) { - return ''; - } - $r = "Some arguments did not pass validation:\n"; - foreach ($this->errors as $letter => $arr) { - $r .= " $letter : " . implode(', ', $arr) . "\n"; - } - $r .= "\n"; - return $r; - } - - /** - * @return string - */ - public function getArgumentsListing() - { - $r = "\n"; - foreach ($this->_args as $letter => $arg) { - /* @var Arg $arg */ - $desc = $arg->getDescription(); - $flag = " -$letter "; - if ($arg->mayHaveValue) { - $flag .= "[VAL]"; - } elseif ($arg->mustHaveValue) { - $flag .= "VAL"; - } - if ($arg->assertFile) { - $flag = str_replace('VAL', 'FILE', $flag); - } elseif ($arg->assertDir) { - $flag = str_replace('VAL', 'DIR', $flag); - } - if ($arg->isRequired()) { - $desc = "(required) $desc"; - } - $flag = str_pad($flag, 12, " ", STR_PAD_RIGHT); - $desc = wordwrap($desc, 70); - $r .= $flag . str_replace("\n", "\n ", $desc) . "\n\n"; - } - return $r; - } - - /** - * Get resource of open input stream. May be STDIN or a file pointer - * to the file specified by an option with 'STDIN'. - * - * @return resource - */ - public function openInput() - { - if (null === $this->_stdin) { - return STDIN; - } else { - $this->_stdin = fopen($this->_stdin, 'rb'); - return $this->_stdin; - } - } - - public function closeInput() - { - if (null !== $this->_stdin) { - fclose($this->_stdin); - } - } - - /** - * Get resource of open output stream. May be STDOUT or a file pointer - * to the file specified by an option with 'STDOUT'. The file will be - * truncated to 0 bytes on opening. - * - * @return resource - */ - public function openOutput() - { - if (null === $this->_stdout) { - return STDOUT; - } else { - $this->_stdout = fopen($this->_stdout, 'wb'); - return $this->_stdout; - } - } - - public function closeOutput() - { - if (null !== $this->_stdout) { - fclose($this->_stdout); - } - } - - /** - * @param string $letter - * @param string $msg - * @param string $value - */ - protected function addError($letter, $msg, $value = null) - { - if ($value !== null) { - $value = var_export($value, 1); - } - $this->errors[$letter][] = sprintf($msg, $value); - } -} - diff --git a/inc/lib/minify/MrClay/Cli/Arg.php b/inc/lib/minify/MrClay/Cli/Arg.php deleted file mode 100755 index 5fa59327..00000000 --- a/inc/lib/minify/MrClay/Cli/Arg.php +++ /dev/null @@ -1,183 +0,0 @@ -values['f.raw'] - * - * Use assertReadable()/assertWritable() to cause the validator to test the file/dir for - * read/write permissions respectively. - * - * @method \MrClay\Cli\Arg mayHaveValue() Assert that the argument, if present, may receive a string value - * @method \MrClay\Cli\Arg mustHaveValue() Assert that the argument, if present, must receive a string value - * @method \MrClay\Cli\Arg assertFile() Assert that the argument's value must specify a file - * @method \MrClay\Cli\Arg assertDir() Assert that the argument's value must specify a directory - * @method \MrClay\Cli\Arg assertReadable() Assert that the specified file/dir must be readable - * @method \MrClay\Cli\Arg assertWritable() Assert that the specified file/dir must be writable - * - * @property-read bool mayHaveValue - * @property-read bool mustHaveValue - * @property-read bool assertFile - * @property-read bool assertDir - * @property-read bool assertReadable - * @property-read bool assertWritable - * @property-read bool useAsInfile - * @property-read bool useAsOutfile - * - * @author Steve Clay - * @license http://www.opensource.org/licenses/mit-license.php MIT License - */ -class Arg { - /** - * @return array - */ - public function getDefaultSpec() - { - return array( - 'mayHaveValue' => false, - 'mustHaveValue' => false, - 'assertFile' => false, - 'assertDir' => false, - 'assertReadable' => false, - 'assertWritable' => false, - 'useAsInfile' => false, - 'useAsOutfile' => false, - ); - } - - /** - * @var array - */ - protected $spec = array(); - - /** - * @var bool - */ - protected $required = false; - - /** - * @var string - */ - protected $description = ''; - - /** - * @param bool $isRequired - */ - public function __construct($isRequired = false) - { - $this->spec = $this->getDefaultSpec(); - $this->required = (bool) $isRequired; - if ($isRequired) { - $this->spec['mustHaveValue'] = true; - } - } - - /** - * Assert that the argument's value points to a writable file. When - * Cli::openOutput() is called, a write pointer to this file will - * be provided. - * @return Arg - */ - public function useAsOutfile() - { - $this->spec['useAsOutfile'] = true; - return $this->assertFile()->assertWritable(); - } - - /** - * Assert that the argument's value points to a readable file. When - * Cli::openInput() is called, a read pointer to this file will - * be provided. - * @return Arg - */ - public function useAsInfile() - { - $this->spec['useAsInfile'] = true; - return $this->assertFile()->assertReadable(); - } - - /** - * @return array - */ - public function getSpec() - { - return $this->spec; - } - - /** - * @param string $desc - * @return Arg - */ - public function setDescription($desc) - { - $this->description = $desc; - return $this; - } - - /** - * @return string - */ - public function getDescription() - { - return $this->description; - } - - /** - * @return bool - */ - public function isRequired() - { - return $this->required; - } - - /** - * Note: magic methods declared in class PHPDOC - * - * @param string $name - * @param array $args - * @return Arg - * @throws BadMethodCallException - */ - public function __call($name, array $args = array()) - { - if (array_key_exists($name, $this->spec)) { - $this->spec[$name] = true; - if ($name === 'assertFile' || $name === 'assertDir') { - $this->spec['mustHaveValue'] = true; - } - } else { - throw new BadMethodCallException('Method does not exist'); - } - return $this; - } - - /** - * Note: magic properties declared in class PHPDOC - * - * @param string $name - * @return bool|null - */ - public function __get($name) - { - if (array_key_exists($name, $this->spec)) { - return $this->spec[$name]; - } - return null; - } -} diff --git a/inc/lib/Twig/Extensions/Extension/I18n.php b/inc/lib/twig/extensions/Extension/I18n.php similarity index 99% rename from inc/lib/Twig/Extensions/Extension/I18n.php rename to inc/lib/twig/extensions/Extension/I18n.php index bc6a05bd..d6865d01 100644 --- a/inc/lib/Twig/Extensions/Extension/I18n.php +++ b/inc/lib/twig/extensions/Extension/I18n.php @@ -42,4 +42,3 @@ class Twig_Extensions_Extension_I18n extends Twig_Extension return 'i18n'; } } - diff --git a/inc/lib/Twig/Extensions/Extension/Tinyboard.php b/inc/lib/twig/extensions/Extension/Tinyboard.php similarity index 100% rename from inc/lib/Twig/Extensions/Extension/Tinyboard.php rename to inc/lib/twig/extensions/Extension/Tinyboard.php diff --git a/inc/lib/Twig/Extensions/Node/Trans.php b/inc/lib/twig/extensions/Node/Trans.php similarity index 99% rename from inc/lib/Twig/Extensions/Node/Trans.php rename to inc/lib/twig/extensions/Node/Trans.php index e7dc1ca8..d12564a7 100644 --- a/inc/lib/Twig/Extensions/Node/Trans.php +++ b/inc/lib/twig/extensions/Node/Trans.php @@ -130,4 +130,4 @@ class Twig_Extensions_Node_Trans extends Twig_Node return array(new Twig_Node(array(new Twig_Node_Expression_Constant(trim($msg), $body->getLine()))), $vars); } -} \ No newline at end of file +} diff --git a/inc/lib/Twig/Extensions/TokenParser/Trans.php b/inc/lib/twig/extensions/TokenParser/Trans.php similarity index 99% rename from inc/lib/Twig/Extensions/TokenParser/Trans.php rename to inc/lib/twig/extensions/TokenParser/Trans.php index 4a0fad41..5e2dc464 100644 --- a/inc/lib/Twig/Extensions/TokenParser/Trans.php +++ b/inc/lib/twig/extensions/TokenParser/Trans.php @@ -77,4 +77,4 @@ class Twig_Extensions_TokenParser_Trans extends Twig_TokenParser throw new Twig_Error_Syntax(sprintf('The text to be translated with "trans" can only contain references to simple variables'), $lineno); } } -} \ No newline at end of file +} diff --git a/inc/template.php b/inc/template.php index 48b2b1bb..648adae8 100644 --- a/inc/template.php +++ b/inc/template.php @@ -4,21 +4,15 @@ * Copyright (c) 2010-2013 Tinyboard Development Group */ +require_once 'inc/bootstrap.php'; defined('TINYBOARD') or exit; + + $twig = false; function load_twig() { global $twig, $config; - - require 'lib/Twig/Autoloader.php'; - Twig_Autoloader::register(); - - Twig_Autoloader::autoload('Twig_Extensions_Node_Trans'); - Twig_Autoloader::autoload('Twig_Extensions_TokenParser_Trans'); - Twig_Autoloader::autoload('Twig_Extensions_Extension_I18n'); - Twig_Autoloader::autoload('Twig_Extensions_Extension_Tinyboard'); - $loader = new Twig_Loader_Filesystem($config['dir']['template']); $loader->setPaths($config['dir']['template']); $twig = new Twig_Environment($loader, array( diff --git a/install.php b/install.php index a35a3360..3eda423b 100644 --- a/install.php +++ b/install.php @@ -8,8 +8,7 @@ if (fopen('inc/instance-config.php' , 'a') === false) { exit(); } -require 'inc/functions.php'; -require_once 'inc/anti-bot.php'; // DELETE ME THIS IS FOR print_err function only! +require 'inc/bootstrap.php'; loadConfig(); diff --git a/log.php b/log.php index 1a660c4c..5637a558 100644 --- a/log.php +++ b/log.php @@ -1,6 +1,5 @@ $handler) { ); $debug['time']['parse_mod_req'] = '~' . round((microtime(true) - $parse_start_time) * 1000, 2) . 'ms'; } - + + if (is_array($matches)) { + // we don't want to call named parameters (PHP 8) + $matches = array_values($matches); + } + if (is_string($handler)) { if ($handler[0] == ':') { header('Location: ' . substr($handler, 1), true, $config['redirect_http']); diff --git a/post.php b/post.php index 41e93165..b16edb0f 100644 --- a/post.php +++ b/post.php @@ -3,20 +3,7 @@ * Copyright (c) 2010-2014 Tinyboard Development Group */ -require_once 'inc/functions.php'; -require_once 'inc/anti-bot.php'; -require_once 'inc/bans.php'; - -// Fix for magic quotes -if (get_magic_quotes_gpc()) { - function strip_array($var) { - return is_array($var) ? array_map('strip_array', $var) : stripslashes($var); - } - - $_GET = strip_array($_GET); - $_POST = strip_array($_POST); -} - +require_once 'inc/bootstrap.php'; $dropped_post = false; @@ -867,8 +854,7 @@ function handle_post(){ if (!$dropped_post) if (($config['country_flags'] && !$config['allow_no_country']) || ($config['country_flags'] && $config['allow_no_country'] && !isset($_POST['no_country']))) { - require 'inc/lib/geoip/geoip.inc'; - $gi=geoip\geoip_open('inc/lib/geoip/GeoIPv6.dat', GEOIP_STANDARD); + $gi=geoip_open('inc/lib/geoip/GeoIPv6.dat', GEOIP_STANDARD); function ipv4to6($ip) { if (strpos($ip, ':') !== false) { @@ -882,10 +868,10 @@ function handle_post(){ return '::ffff:'.$part7.':'.$part8; } - if ($country_code = geoip\geoip_country_code_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR']))) { + if ($country_code = geoip_country_code_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR']))) { if (!in_array(strtolower($country_code), array('eu', 'ap', 'o1', 'a1', 'a2'))) $post['body'] .= "\n".strtolower($country_code)."". - "\n".geoip\geoip_country_name_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR'])).""; + "\n".geoip_country_name_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR'])).""; } } diff --git a/report.php b/report.php index e09b1075..2a268fad 100644 --- a/report.php +++ b/report.php @@ -1,5 +1,5 @@ Date: Mon, 17 Jan 2022 03:01:56 -0100 Subject: [PATCH 47/74] Fix redis deprecation of delete --- inc/cache.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/inc/cache.php b/inc/cache.php index 852aefa2..e8148cbf 100644 --- a/inc/cache.php +++ b/inc/cache.php @@ -118,11 +118,15 @@ class Cache { switch ($config['cache']['enabled']) { case 'memcached': - case 'redis': if (!self::$cache) self::init(); self::$cache->delete($key); break; + case 'redis': + if (!self::$cache) + self::init(); + self::$cache->del($key); + break; case 'apc': apc_delete($key); break; From e906ac74514a415c73593edfad5b540df9d67ac5 Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 17 Jan 2022 07:12:13 -0100 Subject: [PATCH 48/74] Refactor rebuilding after posts, finish reply requests before rebuilding index This provides massive improvements to perceived post times as it doesn't wait for the entire board to rebuild index before confirming to the user that the post was made --- post.php | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/post.php b/post.php index 41e93165..7ad7a7e1 100644 --- a/post.php +++ b/post.php @@ -1449,24 +1449,33 @@ function handle_post(){ )); } - if ($config['try_smarter'] && $post['op']) - $build_pages = range(1, $config['max_pages']); - - if ($post['op']) + if ($post['op']) { clean($id); + + if ($config['try_smarter']) + $build_pages = range(1, $config['max_pages']); - event('post-after', $post); - - buildIndex(); - - // We are already done, let's continue our heavy-lifting work in the background (if we run off FastCGI) - if (function_exists('fastcgi_finish_request')) { - @fastcgi_finish_request(); - } + event('post-after', $post); + + buildIndex(); + + // We are already done and post is visible to others, let's continue our heavy-lifting work in the background (if we run off FastCGI) + if (function_exists('fastcgi_finish_request')) { + @fastcgi_finish_request(); + } - if ($post['op']) { rebuildThemes('post-thread', $board['uri']); + } else { + event('post-after', $post); + + // We are already done and post is visible to others, let's continue our heavy-lifting work in the background (if we run off FastCGI) + if (function_exists('fastcgi_finish_request')) { + @fastcgi_finish_request(); + } + + buildIndex(); + rebuildThemes('post', $board['uri']); } } From ad772c90b74c72678ac81be26e4d6164afbcc714 Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 17 Jan 2022 11:02:35 -0100 Subject: [PATCH 49/74] Update author info --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 556202f8..4db89088 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "towards-a-new-leftypol/leftypol_lainchan", + "name": "leftypol/leftypol", "description": "leftypol imageboard", "type": "project", "require": { @@ -42,7 +42,7 @@ }, { "name": "leftypol contributors", - "homepage": "https://github.com/towards-a-new-leftypol/leftypol_lainchan/" + "homepage": "https://git.leftypol.org/leftypol/leftypol/" } ] } From 7c2b091e32f76f844a6a5f7085afc47ada3035d3 Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 17 Jan 2022 11:05:32 -0100 Subject: [PATCH 50/74] Fix missing function log.php from PHP8 changes I assume this is a better solution than adding the file to the composer.json autoload files as it's only needed for this single file. --- log.php | 1 + 1 file changed, 1 insertion(+) diff --git a/log.php b/log.php index 5637a558..c48bae89 100644 --- a/log.php +++ b/log.php @@ -1,5 +1,6 @@ Date: Mon, 17 Jan 2022 11:14:04 -0100 Subject: [PATCH 51/74] Consider nonoko in building after posting, improve comments --- post.php | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/post.php b/post.php index 0eb1b2e4..3b6ba440 100644 --- a/post.php +++ b/post.php @@ -1440,28 +1440,25 @@ function handle_post(){ if ($config['try_smarter']) $build_pages = range(1, $config['max_pages']); + } - event('post-after', $post); - + event('post-after', $post); + + // If this is a new thread or the poster is returning to the index, let's build it before they redirect + if ($post['op'] || !$noko) + buildIndex(); + + // We are already done, let's continue our heavy-lifting work in the background (if we run off FastCGI) + if (function_exists('fastcgi_finish_request')) { + @fastcgi_finish_request(); + } + + if (!$post['op'] && $noko) buildIndex(); - - // We are already done and post is visible to others, let's continue our heavy-lifting work in the background (if we run off FastCGI) - if (function_exists('fastcgi_finish_request')) { - @fastcgi_finish_request(); - } + if ($post['op']) { rebuildThemes('post-thread', $board['uri']); - } else { - event('post-after', $post); - - // We are already done and post is visible to others, let's continue our heavy-lifting work in the background (if we run off FastCGI) - if (function_exists('fastcgi_finish_request')) { - @fastcgi_finish_request(); - } - - buildIndex(); - rebuildThemes('post', $board['uri']); } } From 32cb9db6b7f4e4d7bc87a4de6e8ae513c5693ea9 Mon Sep 17 00:00:00 2001 From: Sardach Date: Fri, 30 Oct 2020 19:56:49 -0600 Subject: [PATCH 52/74] insignificant fix PHP7 shows a warning when executing tools/rebuild2.php: "Declaration of case-insensitive constants is deprecated" $group_name and $group_value really not need be case-insensitive, so i simply removed that "true". --- inc/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/functions.php b/inc/functions.php index 5f101db2..53fb9600 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -345,7 +345,7 @@ function define_groups() { foreach ($config['mod']['groups'] as $group_value => $group_name) { $group_name = strtoupper($group_name); if(!defined($group_name)) { - define($group_name, $group_value, true); + define($group_name, $group_value); } } From b0b30ad7555bb97f6e70cf39b4988cc647ebf383 Mon Sep 17 00:00:00 2001 From: Daniel Saunders Date: Sun, 19 Jan 2020 01:06:01 -0500 Subject: [PATCH 53/74] $board can be NULL here, prevent indexing it Simplest 7.4 fix ever? Possibly. --- inc/functions.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 53fb9600..7ad23de7 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -212,15 +212,17 @@ function loadConfig() { if (!isset($config['image_deleted'])) $config['image_deleted'] = $config['dir']['static'] . 'deleted.png'; - if (!isset($config['uri_thumb'])) - $config['uri_thumb'] = $config['root'] . $board['dir'] . $config['dir']['thumb']; - elseif (isset($board['dir'])) - $config['uri_thumb'] = sprintf($config['uri_thumb'], $board['dir']); - - if (!isset($config['uri_img'])) - $config['uri_img'] = $config['root'] . $board['dir'] . $config['dir']['img']; - elseif (isset($board['dir'])) - $config['uri_img'] = sprintf($config['uri_img'], $board['dir']); + if (isset($board)) { + if (!isset($config['uri_thumb'])) + $config['uri_thumb'] = $config['root'] . $board['dir'] . $config['dir']['thumb']; + elseif (isset($board['dir'])) + $config['uri_thumb'] = sprintf($config['uri_thumb'], $board['dir']); + + if (!isset($config['uri_img'])) + $config['uri_img'] = $config['root'] . $board['dir'] . $config['dir']['img']; + elseif (isset($board['dir'])) + $config['uri_img'] = sprintf($config['uri_img'], $board['dir']); + } if (!isset($config['uri_stylesheets'])) $config['uri_stylesheets'] = $config['root'] . 'stylesheets/'; From ed73ee76cc816d994bf098eaa9be8d3554e3f09a Mon Sep 17 00:00:00 2001 From: discomrade Date: Mon, 17 Jan 2022 13:08:57 -0100 Subject: [PATCH 54/74] Remove useless debug messages lainchan was a mistake --- inc/anti-bot.php | 13 ------------- inc/filters.php | 6 ------ inc/functions.php | 3 --- inc/mod/pages.php | 5 ----- install.php | 13 ------------- 5 files changed, 40 deletions(-) diff --git a/inc/anti-bot.php b/inc/anti-bot.php index 54c6d87b..daf12c5d 100644 --- a/inc/anti-bot.php +++ b/inc/anti-bot.php @@ -8,19 +8,6 @@ defined('TINYBOARD') or exit; $hidden_inputs_twig = array(); -$logfile = "/tmp/lainchan_err.out"; - -function print_err($s) { - // global $logfile; - // file_put_contents($logfile, $s . "\n", FILE_APPEND); -} - -function print_err2($s) { - print_err($s); -} - -print_err("\n\nSTART\n\n"); - class AntiBot { public $salt, $inputs = array(), $index = 0; diff --git a/inc/filters.php b/inc/filters.php index 1c7b39f1..2a66cd2a 100644 --- a/inc/filters.php +++ b/inc/filters.php @@ -6,8 +6,6 @@ defined('TINYBOARD') or exit; -require_once 'inc/anti-bot.php'; - class Filter { public $flood_check; private $condition; @@ -19,7 +17,6 @@ class Filter { } public function match($condition, $match) { - print_err("Filter condition: " . $condition); $condition = strtolower($condition); $post = &$this->post; @@ -220,8 +217,6 @@ function purge_flood_table() { function do_filters(array $post) { global $config; - print_err("do_filters begin"); - if (!isset($config['filters']) || empty($config['filters'])) return; @@ -239,7 +234,6 @@ function do_filters(array $post) { } foreach ($config['filters'] as $filter_array) { - print_err("creating new filter, running check"); $filter = new Filter($filter_array); $filter->flood_check = $flood_check; if ($filter->check($post)) { diff --git a/inc/functions.php b/inc/functions.php index 7ad23de7..3a7a8e99 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -357,7 +357,6 @@ function define_groups() { function create_antibot($board, $thread = null) { require_once dirname(__FILE__) . '/anti-bot.php'; - print_err("Create Antibot."); return _create_antibot($board, $thread); } @@ -1624,7 +1623,6 @@ function checkSpam(array $extra_salt = array()) { // Iterate through each input foreach ($inputs as $name => $value) { - print_err("-> " . $name . ' : ' . $value); $_hash .= $name . '=' . $value; } @@ -1635,7 +1633,6 @@ function checkSpam(array $extra_salt = array()) { $_hash = sha1($_hash . $extra_salt); if ($hash != $_hash) { - print_err("Hash mismatch"); return true; } diff --git a/inc/mod/pages.php b/inc/mod/pages.php index a15ed1a2..1b68fb2c 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -6,8 +6,6 @@ defined('TINYBOARD') or exit; -require_once 'inc/anti-bot.php'; // DELETE ME THIS IS FOR print_err function only! - function mod_page($title, $template, $args, $subtitle = false) { global $config, $mod; @@ -2688,7 +2686,6 @@ function mod_new_pm($username) { function mod_rebuild() { global $config, $twig; - print_err("mod_rebuild"); if (!hasPermission($config['mod']['rebuild'])) error($config['error']['noaccess']); @@ -2713,9 +2710,7 @@ function mod_rebuild() { if (isset($_POST['rebuild_themes'])) { $log[] = 'Regenerating theme files'; - print_err("mod_rebuild calling rebuildThemes"); rebuildThemes('all'); - print_err("mod_rebuild calling rebuildThemes ok"); } if (isset($_POST['rebuild_javascript'])) { diff --git a/install.php b/install.php index 3eda423b..72994bfa 100644 --- a/install.php +++ b/install.php @@ -24,27 +24,17 @@ $page = array( $config['minify_html'] = false; function checkMd5Exec(bool $can_exec) { - print_err2("checkMd5Exec"); - print_err2($can_exec); $shell_out = shell_exec("pwd"); - print_err2("shell out: " . $shell_out); $shell_out = shell_exec('echo "vichan" | md5sum'); - print_err2("shell out: " . $shell_out); $shell_ok = $shell_out == "141225c362da02b5c359c45b665168de -\n"; - print_err2("shell ok: " . strval($shell_ok)); $result = $can_exec && $shell_ok; - print_err2($result); return $result; } function checkGifsicle() { - print_err2("checkGifsicle"); $shell_out = shell_exec('echo $PATH'); - print_err2("shell out: " . $shell_out); $shell_out = shell_exec('gifsicle --help'); - print_err2("shell out: " . $shell_out); $shell_out = shell_exec('which gifsicle'); - print_err2("shell out (which gifsicle): " . $shell_out); return $shell_out; } @@ -672,7 +662,6 @@ if ($step == 0) { echo Element('page.html', $page); } elseif ($step == 1) { - print_err2("Hello World install.php"); $page['title'] = 'Pre-installation test'; $can_exec = true; @@ -689,8 +678,6 @@ if ($step == 0) { $version = explode('.', PHP_VERSION); define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); } - - print_err2("Can exec: " . strval($can_exec)); // Required extensions $extensions = array( From 2fe1d617a59109854333d36f30ee357463c67121 Mon Sep 17 00:00:00 2001 From: discomrade Date: Wed, 19 Jan 2022 03:55:00 -0100 Subject: [PATCH 55/74] Fix deprecated size() in quick-post-controls.js --- js/quick-post-controls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/quick-post-controls.js b/js/quick-post-controls.js index 3751b4cf..3fc33a19 100644 --- a/js/quick-post-controls.js +++ b/js/quick-post-controls.js @@ -39,7 +39,7 @@ $(document).ready(function(){ ' ' + '
' + ''); - if($('form[name="post"]:first').size()){ + if($('form[name="post"]:first').length){ var board=$(this).parent().parent().parent().attr("data-board"); post_form .attr('action', $('form[name="post"]:first').attr('action')) From b7019fb8b5fd0a04ace0c405ba3032f3881334aa Mon Sep 17 00:00:00 2001 From: discomrade Date: Sat, 22 Jan 2022 02:00:52 -0100 Subject: [PATCH 56/74] Fix multiple issues with anti_bump_flood - bumplocked thread with one reply, delete the reply and no post matches the query - saged posts aren't ignored when finding last bump - bumplocked threads should be ignored --- inc/functions.php | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 3a7a8e99..035d1fcc 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1238,18 +1238,27 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true) { $query = prepare("DELETE FROM ``cites`` WHERE (`target_board` = :board AND (`target` = " . implode(' OR `target` = ', $ids) . ")) OR (`board` = :board AND (`post` = " . implode(' OR `post` = ', $ids) . "))"); $query->bindValue(':board', $board['uri']); $query->execute() or error(db_error($query)); - - if ($config['anti_bump_flood']) { - $query = prepare(sprintf("SELECT `time` FROM ``posts_%s`` WHERE (`thread` = :thread OR `id` = :thread) AND `sage` = 0 ORDER BY `time` DESC LIMIT 1", $board['uri'])); - $query->bindValue(':thread', $thread_id); - $query->execute() or error(db_error($query)); - $bump = $query->fetchColumn(); - $query = prepare(sprintf("UPDATE ``posts_%s`` SET `bump` = :bump WHERE `id` = :thread", $board['uri'])); - $query->bindValue(':bump', $bump); - $query->bindValue(':thread', $thread_id); - $query->execute() or error(db_error($query)); - } - + + // No need to run on OPs + if ($config['anti_bump_flood'] && isset($thread_id)) { + $query = prepare(sprintf("SELECT `sage` FROM ``posts_%s`` WHERE `id` = :thread", $board['uri'])); + $query->bindValue(':thread', $thread_id); + $query->execute() or error(db_error($query)); + $bumplocked = (bool)$query->fetchColumn(); + + if (!$bumplocked) { + $query = prepare(sprintf("SELECT `time` FROM ``posts_%s`` WHERE (`thread` = :thread AND NOT email <=> 'sage') OR `id` = :thread ORDER BY `time` DESC LIMIT 1", $board['uri'])); + $query->bindValue(':thread', $thread_id); + $query->execute() or error(db_error($query)); + $bump = $query->fetchColumn(); + + $query = prepare(sprintf("UPDATE ``posts_%s`` SET `bump` = :bump WHERE `id` = :thread", $board['uri'])); + $query->bindValue(':bump', $bump); + $query->bindValue(':thread', $thread_id); + $query->execute() or error(db_error($query)); + } + } + if (isset($rebuild) && $rebuild_after) { buildThread($rebuild); buildIndex(); From 7f72c0c6f45f3bbfaf83eed1ea64d02ca14803b2 Mon Sep 17 00:00:00 2001 From: discomrade Date: Sun, 23 Jan 2022 22:01:25 -0100 Subject: [PATCH 57/74] Update jQuery libraries Mainly for security purposes. --- js/jquery-ui.custom.min.js | 8 ++++---- js/jquery.min.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/jquery-ui.custom.min.js b/js/jquery-ui.custom.min.js index 165e559d..b91919e4 100755 --- a/js/jquery-ui.custom.min.js +++ b/js/jquery-ui.custom.min.js @@ -1,6 +1,6 @@ -/*! jQuery UI - v1.10.4 - 2014-02-11 +/*! jQuery UI - v1.13.1 - 2022-01-23 * http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js -* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ +* Includes: widget.js, data.js, disable-selection.js, jquery-patch.js, scroll-parent.js, widgets/draggable.js, widgets/droppable.js, widgets/resizable.js, widgets/selectable.js, widgets/sortable.js, widgets/mouse.js +* Copyright jQuery Foundation and other contributors; Licensed MIT */ -(function(e,t){function i(t,i){var s,a,o,r=t.nodeName.toLowerCase();return"area"===r?(s=t.parentNode,a=s.name,t.href&&a&&"map"===s.nodeName.toLowerCase()?(o=e("img[usemap=#"+a+"]")[0],!!o&&n(o)):!1):(/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||i:i)&&n(t)}function n(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var s=0,a=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,n){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),n&&n.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var n,s,a=e(this[0]);a.length&&a[0]!==document;){if(n=a.css("position"),("absolute"===n||"relative"===n||"fixed"===n)&&(s=parseInt(a.css("zIndex"),10),!isNaN(s)&&0!==s))return s;a=a.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++s)})},removeUniqueId:function(){return this.each(function(){a.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,n){return!!e.data(t,n[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var n=e.attr(t,"tabindex"),s=isNaN(n);return(s||n>=0)&&i(t,!s)}}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(i,n){function s(t,i,n,s){return e.each(a,function(){i-=parseFloat(e.css(t,"padding"+this))||0,n&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var a="Width"===n?["Left","Right"]:["Top","Bottom"],o=n.toLowerCase(),r={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+n]=function(i){return i===t?r["inner"+n].call(this):this.each(function(){e(this).css(o,s(this,i)+"px")})},e.fn["outer"+n]=function(t,i){return"number"!=typeof t?r["outer"+n].call(this,t):this.each(function(){e(this).css(o,s(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,n){var s,a=e.ui[t].prototype;for(s in n)a.plugins[s]=a.plugins[s]||[],a.plugins[s].push([i,n[s]])},call:function(e,t,i){var n,s=e.plugins[t];if(s&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(n=0;s.length>n;n++)e.options[s[n][0]]&&s[n][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var n=i&&"left"===i?"scrollLeft":"scrollTop",s=!1;return t[n]>0?!0:(t[n]=1,s=t[n]>0,t[n]=0,s)}})})(jQuery);(function(t,e){var i=0,s=Array.prototype.slice,n=t.cleanData;t.cleanData=function(e){for(var i,s=0;null!=(i=e[s]);s++)try{t(i).triggerHandler("remove")}catch(o){}n(e)},t.widget=function(i,s,n){var o,a,r,h,l={},c=i.split(".")[0];i=i.split(".")[1],o=c+"-"+i,n||(n=s,s=t.Widget),t.expr[":"][o.toLowerCase()]=function(e){return!!t.data(e,o)},t[c]=t[c]||{},a=t[c][i],r=t[c][i]=function(t,i){return this._createWidget?(arguments.length&&this._createWidget(t,i),e):new r(t,i)},t.extend(r,a,{version:n.version,_proto:t.extend({},n),_childConstructors:[]}),h=new s,h.options=t.widget.extend({},h.options),t.each(n,function(i,n){return t.isFunction(n)?(l[i]=function(){var t=function(){return s.prototype[i].apply(this,arguments)},e=function(t){return s.prototype[i].apply(this,t)};return function(){var i,s=this._super,o=this._superApply;return this._super=t,this._superApply=e,i=n.apply(this,arguments),this._super=s,this._superApply=o,i}}(),e):(l[i]=n,e)}),r.prototype=t.widget.extend(h,{widgetEventPrefix:a?h.widgetEventPrefix||i:i},l,{constructor:r,namespace:c,widgetName:i,widgetFullName:o}),a?(t.each(a._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,r,i._proto)}),delete a._childConstructors):s._childConstructors.push(r),t.widget.bridge(i,r)},t.widget.extend=function(i){for(var n,o,a=s.call(arguments,1),r=0,h=a.length;h>r;r++)for(n in a[r])o=a[r][n],a[r].hasOwnProperty(n)&&o!==e&&(i[n]=t.isPlainObject(o)?t.isPlainObject(i[n])?t.widget.extend({},i[n],o):t.widget.extend({},o):o);return i},t.widget.bridge=function(i,n){var o=n.prototype.widgetFullName||i;t.fn[i]=function(a){var r="string"==typeof a,h=s.call(arguments,1),l=this;return a=!r&&h.length?t.widget.extend.apply(null,[a].concat(h)):a,r?this.each(function(){var s,n=t.data(this,o);return n?t.isFunction(n[a])&&"_"!==a.charAt(0)?(s=n[a].apply(n,h),s!==n&&s!==e?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):e):t.error("no such method '"+a+"' for "+i+" widget instance"):t.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+a+"'")}):this.each(function(){var e=t.data(this,o);e?e.option(a||{})._init():t.data(this,o,new n(a,this))}),l}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this.bindings=t(),this.hoverable=t(),this.focusable=t(),s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(i,s){var n,o,a,r=i;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof i)if(r={},n=i.split("."),i=n.shift(),n.length){for(o=r[i]=t.widget.extend({},this.options[i]),a=0;n.length-1>a;a++)o[n[a]]=o[n[a]]||{},o=o[n[a]];if(i=n.pop(),1===arguments.length)return o[i]===e?null:o[i];o[i]=s}else{if(1===arguments.length)return this.options[i]===e?null:this.options[i];r[i]=s}return this._setOptions(r),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!e).attr("aria-disabled",e),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var o,a=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=o=t(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,o=this.widget()),t.each(n,function(n,r){function h(){return i||a.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof r?a[r]:r).apply(a,arguments):e}"string"!=typeof r&&(h.guid=r.guid=r.guid||h.guid||t.guid++);var l=n.match(/^(\w+)\s*(.*)$/),c=l[1]+a.eventNamespace,u=l[2];u?o.delegate(u,c,h):s.bind(c,h)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.unbind(e).undelegate(e)},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}})})(jQuery);(function(t){var e=!1;t(document).mouseup(function(){e=!1}),t.widget("ui.mouse",{version:"1.10.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.bind("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).bind("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!e){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?t(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===t.data(i.target,this.widgetName+".preventClickEvent")&&t.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return s._mouseMove(t)},this._mouseUpDelegate=function(t){return s._mouseUp(t)},t(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),e=!0,!0)):!0}},_mouseMove:function(e){return t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button?this._mouseUp(e):this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){return t(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),!1},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(t){t.widget("ui.draggable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(t(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){t("
").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(t(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offsetParent=this.helper.offsetParent(),this.offsetParentCssPosition=this.offsetParent.css("position"),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.offset.scroll=!1,t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_mouseDrag:function(e,i){if("fixed"===this.offsetParentCssPosition&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"original"!==this.options.helper||t.contains(this.element[0].ownerDocument,this.element[0])?("invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1):!1},_mouseUp:function(e){return t("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.element.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;return n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):"document"===n.containment?(this.containment=[0,0,t(document).width()-this.helperProportions.width-this.margins.left,(t(document).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):n.containment.constructor===Array?(this.containment=n.containment,undefined):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e="hidden"!==i.css("overflow"),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i),undefined):(this.containment=null,undefined)},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent;return this.offset.scroll||(this.offset.scroll={top:n.scrollTop(),left:n.scrollLeft()}),{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top)*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)*s}},_generatePosition:function(e){var i,s,n,a,o=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,l=e.pageX,h=e.pageY;return this.offset.scroll||(this.offset.scroll={top:r.scrollTop(),left:r.scrollLeft()}),this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,e.pageX-this.offset.click.lefti[2]&&(l=i[2]+this.offset.click.left),e.pageY-this.offset.click.top>i[3]&&(h=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((h-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,h=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((l-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,l=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a)),{top:h-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top),left:l-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s]),"drag"===e&&(this.positionAbs=this._convertPositionTo("absolute")),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i){var s=t(this).data("ui-draggable"),n=s.options,a=t.extend({},i,{item:s.element});s.sortables=[],t(n.connectToSortable).each(function(){var i=t.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",e,a))})},stop:function(e,i){var s=t(this).data("ui-draggable"),n=t.extend({},i,{item:s.element});t.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(e),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",e,n))})},drag:function(e,i){var s=t(this).data("ui-draggable"),n=this;t.each(s.sortables,function(){var a=!1,o=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(a=!0,t.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&t.contains(o.instance.element[0],this.instance.element[0])&&(a=!1),a})),a?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=t(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},e.target=this.instance.currentItem[0],this.instance._mouseCapture(e,!0),this.instance._mouseStart(e,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",e),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(e)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",e,this.instance._uiHash(this.instance)),this.instance._mouseStop(e,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",e),s.dropped=!1)})}}),t.ui.plugin.add("draggable","cursor",{start:function(){var e=t("body"),i=t(this).data("ui-draggable").options;e.css("cursor")&&(i._cursor=e.css("cursor")),e.css("cursor",i.cursor)},stop:function(){var e=t(this).data("ui-draggable").options;e._cursor&&t("body").css("cursor",e._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._opacity&&t(i.helper).css("opacity",s._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(){var e=t(this).data("ui-draggable");e.scrollParent[0]!==document&&"HTML"!==e.scrollParent[0].tagName&&(e.overflowOffset=e.scrollParent.offset())},drag:function(e){var i=t(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-e.pageY=0;u--)r=p.snapElements[u].left,l=r+p.snapElements[u].width,h=p.snapElements[u].top,c=h+p.snapElements[u].height,r-f>_||m>l+f||h-f>b||v>c+f||!t.contains(p.snapElements[u].item.ownerDocument,p.snapElements[u].item)?(p.snapElements[u].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=!1):("inner"!==g.snapMode&&(s=f>=Math.abs(h-b),n=f>=Math.abs(c-v),a=f>=Math.abs(r-_),o=f>=Math.abs(l-m),s&&(i.position.top=p._convertPositionTo("relative",{top:h-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:l}).left-p.margins.left)),d=s||n||a||o,"outer"!==g.snapMode&&(s=f>=Math.abs(h-v),n=f>=Math.abs(c-b),a=f>=Math.abs(r-m),o=f>=Math.abs(l-_),s&&(i.position.top=p._convertPositionTo("relative",{top:h,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:c-p.helperProportions.height,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:l-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[u].snapping&&(s||n||a||o||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,e,t.extend(p._uiHash(),{snapItem:p.snapElements[u].item})),p.snapElements[u].snapping=s||n||a||o||d)}}),t.ui.plugin.add("draggable","stack",{start:function(){var e,i=this.data("ui-draggable").options,s=t.makeArray(t(i.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});s.length&&(e=parseInt(t(s[0]).css("zIndex"),10)||0,t(s).each(function(i){t(this).css("zIndex",e+i)}),this.css("zIndex",e+s.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i){var s=t(i.helper),n=t(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(e,i){var s=t(this).data("ui-draggable").options;s._zIndex&&t(i.helper).css("zIndex",s._zIndex)}})})(jQuery);(function(t){function e(t,e,i){return t>e&&e+i>t}t.widget("ui.droppable",{version:"1.10.4",widgetEventPrefix:"drop",options:{accept:"*",activeClass:!1,addClasses:!0,greedy:!1,hoverClass:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],undefined):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},t.ui.ddmanager.droppables[i.scope]=t.ui.ddmanager.droppables[i.scope]||[],t.ui.ddmanager.droppables[i.scope].push(this),i.addClasses&&this.element.addClass("ui-droppable")},_destroy:function(){for(var e=0,i=t.ui.ddmanager.droppables[this.options.scope];i.length>e;e++)i[e]===this&&i.splice(e,1);this.element.removeClass("ui-droppable ui-droppable-disabled")},_setOption:function(e,i){"accept"===e&&(this.accept=t.isFunction(i)?i:function(t){return t.is(i)}),t.Widget.prototype._setOption.apply(this,arguments)},_activate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.addClass(this.options.activeClass),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.addClass(this.options.hoverClass),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var e=t.data(this,"ui-droppable");return e.options.greedy&&!e.options.disabled&&e.options.scope===s.options.scope&&e.accept.call(e.element[0],s.currentItem||s.element)&&t.ui.intersect(s,t.extend(e,{offset:e.element.offset()}),e.options.tolerance)?(n=!0,!1):undefined}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this.options.activeClass&&this.element.removeClass(this.options.activeClass),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}}}),t.ui.intersect=function(t,i,s){if(!i.offset)return!1;var n,a,o=(t.positionAbs||t.position.absolute).left,r=(t.positionAbs||t.position.absolute).top,l=o+t.helperProportions.width,h=r+t.helperProportions.height,c=i.offset.left,u=i.offset.top,d=c+i.proportions().width,p=u+i.proportions().height;switch(s){case"fit":return o>=c&&d>=l&&r>=u&&p>=h;case"intersect":return o+t.helperProportions.width/2>c&&d>l-t.helperProportions.width/2&&r+t.helperProportions.height/2>u&&p>h-t.helperProportions.height/2;case"pointer":return n=(t.positionAbs||t.position.absolute).left+(t.clickOffset||t.offset.click).left,a=(t.positionAbs||t.position.absolute).top+(t.clickOffset||t.offset.click).top,e(a,u,i.proportions().height)&&e(n,c,i.proportions().width);case"touch":return(r>=u&&p>=r||h>=u&&p>=h||u>r&&h>p)&&(o>=c&&d>=o||l>=c&&d>=l||c>o&&l>d);default:return!1}},t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,a=t.ui.ddmanager.droppables[e.options.scope]||[],o=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;a.length>s;s++)if(!(a[s].options.disabled||e&&!a[s].accept.call(a[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===a[s].element[0]){a[s].proportions().height=0;continue t}a[s].visible="none"!==a[s].element.css("display"),a[s].visible&&("mousedown"===o&&a[s]._activate.call(a[s],i),a[s].offset=a[s].element.offset(),a[s].proportions({width:a[s].element[0].offsetWidth,height:a[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&t.ui.intersect(e,this,this.options.tolerance)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").bind("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,a,o=t.ui.intersect(e,this,this.options.tolerance),r=!o&&this.isover?"isout":o&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,a=this.element.parents(":data(ui-droppable)").filter(function(){return t.data(this,"ui-droppable").options.scope===n}),a.length&&(s=t.data(a[0],"ui-droppable"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").unbind("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}}})(jQuery);(function(t){function e(t){return parseInt(t,10)||0}function i(t){return!isNaN(parseInt(t,10))}t.widget("ui.resizable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var e,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(t("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),e=this.handles.split(","),this.handles={},i=0;e.length>i;i++)s=t.trim(e[i]),a="ui-resizable-"+s,n=t("
"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(e){var i,s,n,a;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=t(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=t(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,a),this._proportionallyResize()),t(this.handles[i]).length},this._renderAxis(this.element),this._handles=t(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),t(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(t(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(t(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,a,o=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=e(this.helper.css("left")),n=e(this.helper.css("top")),o.containment&&(s+=t(o.containment).scrollLeft()||0,n+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,a=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===a?this.axis+"-resize":a),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(e){var i,s=this.helper,n={},a=this.originalMousePosition,o=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,c=this.size.height,u=e.pageX-a.left||0,d=e.pageY-a.top||0,p=this._change[o];return p?(i=p.apply(this,[e,u,d]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==c&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(n)||this._trigger("resize",e,this.ui()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&t.ui.hasScroll(i[0],"left")?0:c.sizeDiff.height,a=s?0:c.sizeDiff.width,o={width:c.helper.width()-a,height:c.helper.height()-n},r=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null,h=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(o,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(t){var e,s,n,a,o,r=this.options;o={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,n=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,a=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),n>o.minHeight&&(o.minHeight=n),o.maxWidth>s&&(o.maxWidth=s),o.maxHeight>a&&(o.maxHeight=a)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),i(t.left)&&(this.position.left=t.left),i(t.top)&&(this.position.top=t.top),i(t.height)&&(this.size.height=t.height),i(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,s=this.size,n=this.axis;return i(t.height)?t.width=t.height*this.aspectRatio:i(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===n&&(t.left=e.left+(s.width-t.width),t.top=null),"nw"===n&&(t.top=e.top+(s.height-t.height),t.left=e.left+(s.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,s=this.axis,n=i(t.width)&&e.maxWidth&&e.maxWidtht.width,r=i(t.height)&&e.minHeight&&e.minHeight>t.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,c=/sw|nw|w/.test(s),u=/nw|ne|n/.test(s);return o&&(t.width=e.minWidth),r&&(t.height=e.minHeight),n&&(t.width=e.maxWidth),a&&(t.height=e.maxHeight),o&&c&&(t.left=h-e.minWidth),n&&c&&(t.left=h-e.maxWidth),r&&u&&(t.top=l-e.minHeight),a&&u&&(t.top=l-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var t,e,i,s,n,a=this.helper||this.element;for(t=0;this._proportionallyResizeElements.length>t;t++){if(n=this._proportionallyResizeElements[t],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],e=0;i.length>e;e++)this.borderDif[e]=(parseInt(i[e],10)||0)+(parseInt(s[e],10)||0);n.css({height:a.height()-this.borderDif[0]-this.borderDif[2]||0,width:a.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&t.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,c=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,a,o,r,h,l=t(this).data("ui-resizable"),c=l.options,u=l.element,d=c.containment,p=d instanceof t?d.get(0):/parent/.test(d)?u.parent().get(0):d;p&&(l.containerElement=t(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(i=t(p),s=[],t(["Top","Right","Left","Bottom"]).each(function(t,n){s[t]=e(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,a=l.containerSize.height,o=l.containerSize.width,r=t.ui.hasScroll(p,"left")?p.scrollWidth:o,h=t.ui.hasScroll(p)?p.scrollHeight:a,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(e){var i,s,n,a,o=t(this).data("ui-resizable"),r=o.options,h=o.containerOffset,l=o.position,c=o._aspectRatio||e.shiftKey,u={top:0,left:0},d=o.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-u.left),c&&(o.size.height=o.size.width/o.aspectRatio),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),c&&(o.size.width=o.size.height*o.aspectRatio),o.position.top=o._helper?h.top:0),o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top,i=Math.abs((o._helper?o.offset.left-u.left:o.offset.left-u.left)+o.sizeDiff.width),s=Math.abs((o._helper?o.offset.top-u.top:o.offset.top-h.top)+o.sizeDiff.height),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a&&(i-=Math.abs(o.parentData.left)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,c&&(o.size.height=o.size.width/o.aspectRatio)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,c&&(o.size.width=o.size.height*o.aspectRatio))},stop:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.containerOffset,n=e.containerPosition,a=e.containerElement,o=t(e.helper),r=o.offset(),h=o.outerWidth()-e.sizeDiff.width,l=o.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(a.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(a.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=function(e){t(e).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseInt(e.width(),10),height:parseInt(e.height(),10),left:parseInt(e.css("left"),10),top:parseInt(e.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):t.each(i.alsoResize,function(t){s(t)})},resize:function(e,i){var s=t(this).data("ui-resizable"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(e,s){t(e).each(function(){var e=t(this),n=t(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(n[e]||0)+(r[e]||0);i&&i>=0&&(a[e]=i||null)}),e.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):t.each(n.alsoResize,function(t,e){h(t,e)})},stop:function(){t(this).removeData("resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).data("ui-resizable");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).data("ui-resizable");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e=t(this).data("ui-resizable"),i=e.options,s=e.size,n=e.originalSize,a=e.originalPosition,o=e.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,c=Math.round((s.width-n.width)/h)*h,u=Math.round((s.height-n.height)/l)*l,d=n.width+c,p=n.height+u,f=i.maxWidth&&d>i.maxWidth,g=i.maxHeight&&p>i.maxHeight,m=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,m&&(d+=h),v&&(p+=l),f&&(d-=h),g&&(p-=l),/^(se|s|e)$/.test(o)?(e.size.width=d,e.size.height=p):/^(ne)$/.test(o)?(e.size.width=d,e.size.height=p,e.position.top=a.top-u):/^(sw)$/.test(o)?(e.size.width=d,e.size.height=p,e.position.left=a.left-c):(p-l>0?(e.size.height=p,e.position.top=a.top-u):(e.size.height=l,e.position.top=a.top+n.height-l),d-h>0?(e.size.width=d,e.position.left=a.left-c):(e.size.width=h,e.position.left=a.left+n.width-h))}})})(jQuery);(function(t){t.widget("ui.selectable",t.ui.mouse,{version:"1.10.4",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e,i=this;this.element.addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e=t(i.options.filter,i.element[0]),e.addClass("ui-selectee"),e.each(function(){var e=t(this),i=e.offset();t.data(this,"selectable-item",{element:this,$element:e,left:i.left,top:i.top,right:i.left+e.outerWidth(),bottom:i.top+e.outerHeight(),startselected:!1,selected:e.hasClass("ui-selected"),selecting:e.hasClass("ui-selecting"),unselecting:e.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=e.addClass("ui-selectee"),this._mouseInit(),this.helper=t("
")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(s.$element.removeClass("ui-selected"),s.selected=!1,s.$element.addClass("ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),n.$element.removeClass(s?"ui-unselecting":"ui-selected").addClass(s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):undefined}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,a=this.opos[0],o=this.opos[1],r=e.pageX,l=e.pageY;return a>r&&(i=r,r=a,a=i),o>l&&(i=l,l=o,o=i),this.helper.css({left:a,top:o,width:r-a,height:l-o}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),h=!1;i&&i.element!==s.element[0]&&("touch"===n.tolerance?h=!(i.left>r||a>i.right||i.top>l||o>i.bottom):"fit"===n.tolerance&&(h=i.left>a&&r>i.right&&i.top>o&&l>i.bottom),h?(i.selected&&(i.$element.removeClass("ui-selected"),i.selected=!1),i.unselecting&&(i.$element.removeClass("ui-unselecting"),i.unselecting=!1),i.selecting||(i.$element.addClass("ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.$element.addClass("ui-selected"),i.selected=!0):(i.$element.removeClass("ui-selecting"),i.selecting=!1,i.startselected&&(i.$element.addClass("ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(i.$element.removeClass("ui-selected"),i.selected=!1,i.$element.addClass("ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");s.$element.removeClass("ui-selecting").addClass("ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}})})(jQuery);(function(t){function e(t,e,i){return t>e&&e+i>t}function i(t){return/left|right/.test(t.css("float"))||/inline|table-cell/.test(t.css("display"))}t.widget("ui.sortable",t.ui.mouse,{version:"1.10.4",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var t=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?"x"===t.axis||i(this.items[0].item):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var t=this.items.length-1;t>=0;t--)this.items[t].item.removeData(this.widgetName+"-item");return this},_setOption:function(e,i){"disabled"===e?(this.options[e]=i,this.widget().toggleClass("ui-sortable-disabled",!!i)):t.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(e,i){var s=null,n=!1,o=this;return this.reverting?!1:this.options.disabled||"static"===this.options.type?!1:(this._refreshItems(e),t(e.target).parents().each(function(){return t.data(this,o.widgetName+"-item")===o?(s=t(this),!1):undefined}),t.data(e.target,o.widgetName+"-item")===o&&(s=t(e.target)),s?!this.options.handle||i||(t(this.options.handle,s).find("*").addBack().each(function(){this===e.target&&(n=!0)}),n)?(this.currentItem=s,this._removeCurrentsFromItems(),!0):!1:!1)},_mouseStart:function(e,i,s){var n,o,a=this.options;if(this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(e),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},t.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(e),this.originalPageX=e.pageX,this.originalPageY=e.pageY,a.cursorAt&&this._adjustOffsetFromHelper(a.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!==this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),a.containment&&this._setContainment(),a.cursor&&"auto"!==a.cursor&&(o=this.document.find("body"),this.storedCursor=o.css("cursor"),o.css("cursor",a.cursor),this.storedStylesheet=t("").appendTo(o)),a.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",a.opacity)),a.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",a.zIndex)),this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",e,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!s)for(n=this.containers.length-1;n>=0;n--)this.containers[n]._trigger("activate",e,this._uiHash(this));return t.ui.ddmanager&&(t.ui.ddmanager.current=this),t.ui.ddmanager&&!a.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(e),!0},_mouseDrag:function(e){var i,s,n,o,a=this.options,r=!1;for(this.position=this._generatePosition(e),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs),this.options.scroll&&(this.scrollParent[0]!==document&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-e.pageY=0;i--)if(s=this.items[i],n=s.item[0],o=this._intersectsWithPointer(s),o&&s.instance===this.currentContainer&&n!==this.currentItem[0]&&this.placeholder[1===o?"next":"prev"]()[0]!==n&&!t.contains(this.placeholder[0],n)&&("semi-dynamic"===this.options.type?!t.contains(this.element[0],n):!0)){if(this.direction=1===o?"down":"up","pointer"!==this.options.tolerance&&!this._intersectsWithSides(s))break;this._rearrange(e,s),this._trigger("change",e,this._uiHash());break}return this._contactContainers(e),t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),this._trigger("sort",e,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(e,i){if(e){if(t.ui.ddmanager&&!this.options.dropBehaviour&&t.ui.ddmanager.drop(this,e),this.options.revert){var s=this,n=this.placeholder.offset(),o=this.options.axis,a={};o&&"x"!==o||(a.left=n.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft)),o&&"y"!==o||(a.top=n.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop)),this.reverting=!0,t(this.helper).animate(a,parseInt(this.options.revert,10)||500,function(){s._clear(e)})}else this._clear(e,i);return!1}},cancel:function(){if(this.dragging){this._mouseUp({target:null}),"original"===this.options.helper?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var e=this.containers.length-1;e>=0;e--)this.containers[e]._trigger("deactivate",null,this._uiHash(this)),this.containers[e].containerCache.over&&(this.containers[e]._trigger("out",null,this._uiHash(this)),this.containers[e].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),"original"!==this.options.helper&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),t.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?t(this.domPosition.prev).after(this.currentItem):t(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},t(i).each(function(){var i=(t(e.item||this).attr(e.attribute||"id")||"").match(e.expression||/(.+)[\-=_](.+)/);i&&s.push((e.key||i[1]+"[]")+"="+(e.key&&e.expression?i[1]:i[2]))}),!s.length&&e.key&&s.push(e.key+"="),s.join("&")},toArray:function(e){var i=this._getItemsAsjQuery(e&&e.connected),s=[];return e=e||{},i.each(function(){s.push(t(e.item||this).attr(e.attribute||"id")||"")}),s},_intersectsWith:function(t){var e=this.positionAbs.left,i=e+this.helperProportions.width,s=this.positionAbs.top,n=s+this.helperProportions.height,o=t.left,a=o+t.width,r=t.top,h=r+t.height,l=this.offset.click.top,c=this.offset.click.left,u="x"===this.options.axis||s+l>r&&h>s+l,d="y"===this.options.axis||e+c>o&&a>e+c,p=u&&d;return"pointer"===this.options.tolerance||this.options.forcePointerForContainers||"pointer"!==this.options.tolerance&&this.helperProportions[this.floating?"width":"height"]>t[this.floating?"width":"height"]?p:e+this.helperProportions.width/2>o&&a>i-this.helperProportions.width/2&&s+this.helperProportions.height/2>r&&h>n-this.helperProportions.height/2},_intersectsWithPointer:function(t){var i="x"===this.options.axis||e(this.positionAbs.top+this.offset.click.top,t.top,t.height),s="y"===this.options.axis||e(this.positionAbs.left+this.offset.click.left,t.left,t.width),n=i&&s,o=this._getDragVerticalDirection(),a=this._getDragHorizontalDirection();return n?this.floating?a&&"right"===a||"down"===o?2:1:o&&("down"===o?2:1):!1},_intersectsWithSides:function(t){var i=e(this.positionAbs.top+this.offset.click.top,t.top+t.height/2,t.height),s=e(this.positionAbs.left+this.offset.click.left,t.left+t.width/2,t.width),n=this._getDragVerticalDirection(),o=this._getDragHorizontalDirection();return this.floating&&o?"right"===o&&s||"left"===o&&!s:n&&("down"===n&&i||"up"===n&&!i)},_getDragVerticalDirection:function(){var t=this.positionAbs.top-this.lastPositionAbs.top;return 0!==t&&(t>0?"down":"up")},_getDragHorizontalDirection:function(){var t=this.positionAbs.left-this.lastPositionAbs.left;return 0!==t&&(t>0?"right":"left")},refresh:function(t){return this._refreshItems(t),this.refreshPositions(),this},_connectWith:function(){var t=this.options;return t.connectWith.constructor===String?[t.connectWith]:t.connectWith},_getItemsAsjQuery:function(e){function i(){r.push(this)}var s,n,o,a,r=[],h=[],l=this._connectWith();if(l&&e)for(s=l.length-1;s>=0;s--)for(o=t(l[s]),n=o.length-1;n>=0;n--)a=t.data(o[n],this.widgetFullName),a&&a!==this&&!a.options.disabled&&h.push([t.isFunction(a.options.items)?a.options.items.call(a.element):t(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a]);for(h.push([t.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):t(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]),s=h.length-1;s>=0;s--)h[s][0].each(i);return t(r)},_removeCurrentsFromItems:function(){var e=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=t.grep(this.items,function(t){for(var i=0;e.length>i;i++)if(e[i]===t.item[0])return!1;return!0})},_refreshItems:function(e){this.items=[],this.containers=[this];var i,s,n,o,a,r,h,l,c=this.items,u=[[t.isFunction(this.options.items)?this.options.items.call(this.element[0],e,{item:this.currentItem}):t(this.options.items,this.element),this]],d=this._connectWith();if(d&&this.ready)for(i=d.length-1;i>=0;i--)for(n=t(d[i]),s=n.length-1;s>=0;s--)o=t.data(n[s],this.widgetFullName),o&&o!==this&&!o.options.disabled&&(u.push([t.isFunction(o.options.items)?o.options.items.call(o.element[0],e,{item:this.currentItem}):t(o.options.items,o.element),o]),this.containers.push(o));for(i=u.length-1;i>=0;i--)for(a=u[i][1],r=u[i][0],s=0,l=r.length;l>s;s++)h=t(r[s]),h.data(this.widgetName+"-item",a),c.push({item:h,instance:a,width:0,height:0,left:0,top:0})},refreshPositions:function(e){this.offsetParent&&this.helper&&(this.offset.parent=this._getParentOffset());var i,s,n,o;for(i=this.items.length-1;i>=0;i--)s=this.items[i],s.instance!==this.currentContainer&&this.currentContainer&&s.item[0]!==this.currentItem[0]||(n=this.options.toleranceElement?t(this.options.toleranceElement,s.item):s.item,e||(s.width=n.outerWidth(),s.height=n.outerHeight()),o=n.offset(),s.left=o.left,s.top=o.top);if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(i=this.containers.length-1;i>=0;i--)o=this.containers[i].element.offset(),this.containers[i].containerCache.left=o.left,this.containers[i].containerCache.top=o.top,this.containers[i].containerCache.width=this.containers[i].element.outerWidth(),this.containers[i].containerCache.height=this.containers[i].element.outerHeight();return this},_createPlaceholder:function(e){e=e||this;var i,s=e.options;s.placeholder&&s.placeholder.constructor!==String||(i=s.placeholder,s.placeholder={element:function(){var s=e.currentItem[0].nodeName.toLowerCase(),n=t("<"+s+">",e.document[0]).addClass(i||e.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");return"tr"===s?e.currentItem.children().each(function(){t(" ",e.document[0]).attr("colspan",t(this).attr("colspan")||1).appendTo(n)}):"img"===s&&n.attr("src",e.currentItem.attr("src")),i||n.css("visibility","hidden"),n},update:function(t,n){(!i||s.forcePlaceholderSize)&&(n.height()||n.height(e.currentItem.innerHeight()-parseInt(e.currentItem.css("paddingTop")||0,10)-parseInt(e.currentItem.css("paddingBottom")||0,10)),n.width()||n.width(e.currentItem.innerWidth()-parseInt(e.currentItem.css("paddingLeft")||0,10)-parseInt(e.currentItem.css("paddingRight")||0,10)))}}),e.placeholder=t(s.placeholder.element.call(e.element,e.currentItem)),e.currentItem.after(e.placeholder),s.placeholder.update(e,e.placeholder)},_contactContainers:function(s){var n,o,a,r,h,l,c,u,d,p,f=null,g=null;for(n=this.containers.length-1;n>=0;n--)if(!t.contains(this.currentItem[0],this.containers[n].element[0]))if(this._intersectsWith(this.containers[n].containerCache)){if(f&&t.contains(this.containers[n].element[0],f.element[0]))continue;f=this.containers[n],g=n}else this.containers[n].containerCache.over&&(this.containers[n]._trigger("out",s,this._uiHash(this)),this.containers[n].containerCache.over=0);if(f)if(1===this.containers.length)this.containers[g].containerCache.over||(this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1);else{for(a=1e4,r=null,p=f.floating||i(this.currentItem),h=p?"left":"top",l=p?"width":"height",c=this.positionAbs[h]+this.offset.click[h],o=this.items.length-1;o>=0;o--)t.contains(this.containers[g].element[0],this.items[o].item[0])&&this.items[o].item[0]!==this.currentItem[0]&&(!p||e(this.positionAbs.top+this.offset.click.top,this.items[o].top,this.items[o].height))&&(u=this.items[o].item.offset()[h],d=!1,Math.abs(u-c)>Math.abs(u+this.items[o][l]-c)&&(d=!0,u+=this.items[o][l]),a>Math.abs(u-c)&&(a=Math.abs(u-c),r=this.items[o],this.direction=d?"up":"down"));if(!r&&!this.options.dropOnEmpty)return;if(this.currentContainer===this.containers[g])return;r?this._rearrange(s,r,null,!0):this._rearrange(s,null,this.containers[g].element,!0),this._trigger("change",s,this._uiHash()),this.containers[g]._trigger("change",s,this._uiHash(this)),this.currentContainer=this.containers[g],this.options.placeholder.update(this.currentContainer,this.placeholder),this.containers[g]._trigger("over",s,this._uiHash(this)),this.containers[g].containerCache.over=1}},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper)?t(i.helper.apply(this.element[0],[e,this.currentItem])):"clone"===i.helper?this.currentItem.clone():this.currentItem;return s.parents("body").length||t("parent"!==i.appendTo?i.appendTo:this.currentItem[0].parentNode)[0].appendChild(s[0]),s[0]===this.currentItem[0]&&(this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")}),(!s[0].style.width||i.forceHelperSize)&&s.width(this.currentItem.width()),(!s[0].style.height||i.forceHelperSize)&&s.height(this.currentItem.height()),s},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var e=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&t.ui.ie)&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var t=this.currentItem.position();return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:t.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options;"parent"===n.containment&&(n.containment=this.helper[0].parentNode),("document"===n.containment||"window"===n.containment)&&(this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,t("document"===n.containment?document:window).width()-this.helperProportions.width-this.margins.left,(t("document"===n.containment?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]),/^(document|window|parent)$/.test(n.containment)||(e=t(n.containment)[0],i=t(n.containment).offset(),s="hidden"!==t(e).css("overflow"),this.containment=[i.left+(parseInt(t(e).css("borderLeftWidth"),10)||0)+(parseInt(t(e).css("paddingLeft"),10)||0)-this.margins.left,i.top+(parseInt(t(e).css("borderTopWidth"),10)||0)+(parseInt(t(e).css("paddingTop"),10)||0)-this.margins.top,i.left+(s?Math.max(e.scrollWidth,e.offsetWidth):e.offsetWidth)-(parseInt(t(e).css("borderLeftWidth"),10)||0)-(parseInt(t(e).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,i.top+(s?Math.max(e.scrollHeight,e.offsetHeight):e.offsetHeight)-(parseInt(t(e).css("borderTopWidth"),10)||0)-(parseInt(t(e).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top])},_convertPositionTo:function(e,i){i||(i=this.position);var s="absolute"===e?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(n[0].tagName);return{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():o?0:n.scrollTop())*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():o?0:n.scrollLeft())*s}},_generatePosition:function(e){var i,s,n=this.options,o=e.pageX,a=e.pageY,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&t.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=/(html|body)/i.test(r[0].tagName);return"relative"!==this.cssPosition||this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0]||(this.offset.relative=this._getRelativeOffset()),this.originalPosition&&(this.containment&&(e.pageX-this.offset.click.leftthis.containment[2]&&(o=this.containment[2]+this.offset.click.left),e.pageY-this.offset.click.top>this.containment[3]&&(a=this.containment[3]+this.offset.click.top)),n.grid&&(i=this.originalPageY+Math.round((a-this.originalPageY)/n.grid[1])*n.grid[1],a=this.containment?i-this.offset.click.top>=this.containment[1]&&i-this.offset.click.top<=this.containment[3]?i:i-this.offset.click.top>=this.containment[1]?i-n.grid[1]:i+n.grid[1]:i,s=this.originalPageX+Math.round((o-this.originalPageX)/n.grid[0])*n.grid[0],o=this.containment?s-this.offset.click.left>=this.containment[0]&&s-this.offset.click.left<=this.containment[2]?s:s-this.offset.click.left>=this.containment[0]?s-n.grid[0]:s+n.grid[0]:s)),{top:a-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():h?0:r.scrollTop()),left:o-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():h?0:r.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var n=this.counter;this._delay(function(){n===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){function i(t,e,i){return function(s){i._trigger(t,s,e._uiHash(e))}}this.reverting=!1;var s,n=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(s in this._storedCSS)("auto"===this._storedCSS[s]||"static"===this._storedCSS[s])&&(this._storedCSS[s]="");this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();for(this.fromOutside&&!e&&n.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||n.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(n.push(function(t){this._trigger("remove",t,this._uiHash())}),n.push(function(t){return function(e){t._trigger("receive",e,this._uiHash(this))}}.call(this,this.currentContainer)),n.push(function(t){return function(e){t._trigger("update",e,this._uiHash(this))}}.call(this,this.currentContainer)))),s=this.containers.length-1;s>=0;s--)e||n.push(i("deactivate",this,this.containers[s])),this.containers[s].containerCache.over&&(n.push(i("out",this,this.containers[s])),this.containers[s].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,this.cancelHelperRemoval){if(!e){for(this._trigger("beforeStop",t,this._uiHash()),s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!1}if(e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null,!e){for(s=0;n.length>s;s++)n[s].call(this,t);this._trigger("stop",t,this._uiHash())}return this.fromOutside=!1,!0},_trigger:function(){t.Widget.prototype._trigger.apply(this,arguments)===!1&&this.cancel()},_uiHash:function(e){var i=e||this;return{helper:i.helper,placeholder:i.placeholder||t([]),position:i.position,originalPosition:i.originalPosition,offset:i.positionAbs,item:i.currentItem,sender:e?e.element:null}}})})(jQuery); \ No newline at end of file +!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(b){"use strict";b.ui=b.ui||{};b.ui.version="1.13.1";var o,i=0,r=Array.prototype.hasOwnProperty,h=Array.prototype.slice;b.cleanData=(o=b.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=b._data(i,"events"))&&e.remove&&b(i).triggerHandler("remove");o(t)}),b.widget=function(t,i,e){var s,o,n,r={},h=t.split(".")[0],a=h+"-"+(t=t.split(".")[1]);return e||(e=i,i=b.Widget),Array.isArray(e)&&(e=b.extend.apply(null,[{}].concat(e))),b.expr.pseudos[a.toLowerCase()]=function(t){return!!b.data(t,a)},b[h]=b[h]||{},s=b[h][t],o=b[h][t]=function(t,e){if(!this||!this._createWidget)return new o(t,e);arguments.length&&this._createWidget(t,e)},b.extend(o,s,{version:e.version,_proto:b.extend({},e),_childConstructors:[]}),(n=new i).options=b.widget.extend({},n.options),b.each(e,function(e,s){function o(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}r[e]="function"==typeof s?function(){var t,e=this._super,i=this._superApply;return this._super=o,this._superApply=n,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:s}),o.prototype=b.widget.extend(n,{widgetEventPrefix:s&&n.widgetEventPrefix||t},r,{constructor:o,namespace:h,widgetName:t,widgetFullName:a}),s?(b.each(s._childConstructors,function(t,e){var i=e.prototype;b.widget(i.namespace+"."+i.widgetName,o,e._proto)}),delete s._childConstructors):i._childConstructors.push(o),b.widget.bridge(t,o),o},b.widget.extend=function(t){for(var e,i,s=h.call(arguments,1),o=0,n=s.length;o",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=b(e||this.defaultElement||this)[0],this.element=b(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=b(),this.hoverable=b(),this.focusable=b(),this.classesElementLookup={},e!==this&&(b.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=b(e.style?e.ownerDocument:e.document||e),this.window=b(this.document[0].defaultView||this.document[0].parentWindow)),this.options=b.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:b.noop,_create:b.noop,_init:b.noop,destroy:function(){var i=this;this._destroy(),b.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:b.noop,widget:function(){return this.element},option:function(t,e){var i,s,o,n=t;if(0===arguments.length)return b.widget.extend({},this.options);if("string"==typeof t)if(n={},t=(i=t.split(".")).shift(),i.length){for(s=n[t]=b.widget.extend({},this.options[t]),o=0;o=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),b.ui.plugin={add:function(t,e,i){var s,o=b.ui[t].prototype;for(s in i)o.plugins[s]=o.plugins[s]||[],o.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var o,n=t.plugins[e];if(n&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(o=0;o").css("position","absolute").appendTo(t.parent()).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).offset(t.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(t){var e=b.ui.safeActiveElement(this.document[0]);b(t.target).closest(e).length||b.ui.safeBlur(e)},_mouseStart:function(t){var e=this.options;return this.helper=this._createHelper(t),this._addClass(this.helper,"ui-draggable-dragging"),this._cacheHelperProportions(),b.ui.ddmanager&&(b.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=0i[2]&&(n=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(r=i[3]+this.offset.click.top)),s.grid&&(t=s.grid[1]?this.originalPageY+Math.round((r-this.originalPageY)/s.grid[1])*s.grid[1]:this.originalPageY,r=!i||t-this.offset.click.top>=i[1]||t-this.offset.click.top>i[3]?t:t-this.offset.click.top>=i[1]?t-s.grid[1]:t+s.grid[1],t=s.grid[0]?this.originalPageX+Math.round((n-this.originalPageX)/s.grid[0])*s.grid[0]:this.originalPageX,n=!i||t-this.offset.click.left>=i[0]||t-this.offset.click.left>i[2]?t:t-this.offset.click.left>=i[0]?t-s.grid[0]:t+s.grid[0]),"y"===s.axis&&(n=this.originalPageX),"x"===s.axis&&(r=this.originalPageY)),{top:r-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:o?0:this.offset.scroll.top),left:n-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:o?0:this.offset.scroll.left)}},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(t,e,i){return i=i||this._uiHash(),b.ui.plugin.call(this,t,[e,i,this],!0),/^(drag|start|stop)/.test(t)&&(this.positionAbs=this._convertPositionTo("absolute"),i.offset=this.positionAbs),b.Widget.prototype._trigger.call(this,t,e,i)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),b.ui.plugin.add("draggable","connectToSortable",{start:function(e,t,i){var s=b.extend({},t,{item:i.element});i.sortables=[],b(i.options.connectToSortable).each(function(){var t=b(this).sortable("instance");t&&!t.options.disabled&&(i.sortables.push(t),t.refreshPositions(),t._trigger("activate",e,s))})},stop:function(e,t,i){var s=b.extend({},t,{item:i.element});i.cancelHelperRemoval=!1,b.each(i.sortables,function(){var t=this;t.isOver?(t.isOver=0,i.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,s))})},drag:function(i,s,o){b.each(o.sortables,function(){var t=!1,e=this;e.positionAbs=o.positionAbs,e.helperProportions=o.helperProportions,e.offset.click=o.offset.click,e._intersectsWith(e.containerCache)&&(t=!0,b.each(o.sortables,function(){return this.positionAbs=o.positionAbs,this.helperProportions=o.helperProportions,this.offset.click=o.offset.click,t=this!==e&&this._intersectsWith(this.containerCache)&&b.contains(e.element[0],this.element[0])?!1:t})),t?(e.isOver||(e.isOver=1,o._parent=s.helper.parent(),e.currentItem=s.helper.appendTo(e.element).data("ui-sortable-item",!0),e.options._helper=e.options.helper,e.options.helper=function(){return s.helper[0]},i.target=e.currentItem[0],e._mouseCapture(i,!0),e._mouseStart(i,!0,!0),e.offset.click.top=o.offset.click.top,e.offset.click.left=o.offset.click.left,e.offset.parent.left-=o.offset.parent.left-e.offset.parent.left,e.offset.parent.top-=o.offset.parent.top-e.offset.parent.top,o._trigger("toSortable",i),o.dropped=e.element,b.each(o.sortables,function(){this.refreshPositions()}),o.currentItem=o.element,e.fromOutside=o),e.currentItem&&(e._mouseDrag(i),s.position=e.position)):e.isOver&&(e.isOver=0,e.cancelHelperRemoval=!0,e.options._revert=e.options.revert,e.options.revert=!1,e._trigger("out",i,e._uiHash(e)),e._mouseStop(i,!0),e.options.revert=e.options._revert,e.options.helper=e.options._helper,e.placeholder&&e.placeholder.remove(),s.helper.appendTo(o._parent),o._refreshOffsets(i),s.position=o._generatePosition(i,!0),o._trigger("fromSortable",i),o.dropped=!1,b.each(o.sortables,function(){this.refreshPositions()}))})}}),b.ui.plugin.add("draggable","cursor",{start:function(t,e,i){var s=b("body"),i=i.options;s.css("cursor")&&(i._cursor=s.css("cursor")),s.css("cursor",i.cursor)},stop:function(t,e,i){i=i.options;i._cursor&&b("body").css("cursor",i._cursor)}}),b.ui.plugin.add("draggable","opacity",{start:function(t,e,i){e=b(e.helper),i=i.options;e.css("opacity")&&(i._opacity=e.css("opacity")),e.css("opacity",i.opacity)},stop:function(t,e,i){i=i.options;i._opacity&&b(e.helper).css("opacity",i._opacity)}}),b.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(t,e,i){var s=i.options,o=!1,n=i.scrollParentNotHidden[0],r=i.document[0];n!==r&&"HTML"!==n.tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+n.offsetHeight-t.pageY
").css({overflow:"hidden",position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&b(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy(),this._addedHandles.remove();function t(t){b(t).removeData("resizable").removeData("ui-resizable").off(".resizable")}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;case"aspectRatio":this._aspectRatio=!!e}},_setupHandles:function(){var t,e,i,s,o,n=this.options,r=this;if(this.handles=n.handles||(b(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=b(),this._addedHandles=b(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split(","),this.handles={},e=0;e"),this._addClass(o,"ui-resizable-handle "+s),o.css({zIndex:n.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.children(this.handles[t]).length||(this.element.append(o),this._addedHandles=this._addedHandles.add(o));this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=b(this.handles[e]),this._on(this.handles[e],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=b(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add(this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),n.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._addedHandles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=b(this.handles[e])[0])!==t.target&&!b.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,o=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=b(s.containment).scrollLeft()||0,i+=b(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:o.width(),height:o.height()},this.originalSize=this._helper?{width:o.outerWidth(),height:o.outerHeight()}:{width:o.width(),height:o.height()},this.sizeDiff={width:o.outerWidth()-o.width(),height:o.outerHeight()-o.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=b(".ui-resizable-"+this.axis).css("cursor"),b("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),b.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,o=this.options,n=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:n.sizeDiff.height,i=e?0:n.sizeDiff.width,e={width:n.helper.width()-i,height:n.helper.height()-s},i=parseFloat(n.element.css("left"))+(n.position.left-n.originalPosition.left)||null,s=parseFloat(n.element.css("top"))+(n.position.top-n.originalPosition.top)||null,o.animate||this.element.css(b.extend(e,{top:s,left:i})),n.helper.height(n.size.height),n.helper.width(n.size.width),this._helper&&!o.animate&&this._proportionallyResize()),b("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,o={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,i=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,t=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),i>o.minHeight&&(o.minHeight=i),st.width,r=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,h=this.originalPosition.left+this.originalSize.width,a=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return n&&(t.width=e.minWidth),r&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),o&&(t.height=e.maxHeight),n&&l&&(t.left=h-e.minWidth),s&&l&&(t.left=h-e.maxWidth),r&&i&&(t.top=a-e.minHeight),o&&i&&(t.top=a-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],o=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(o[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e
").css({overflow:"hidden"}),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return b.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e,i){return b.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return b.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return b.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){b.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,e,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),b.ui.plugin.add("resizable","animate",{stop:function(e){var i=b(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,o=s.length&&/textarea/i.test(s[0].nodeName),n=o&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,o={width:i.size.width-r,height:i.size.height-n},r=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,n=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(b.extend(o,n&&r?{top:n,left:r}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&b(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),b.ui.plugin.add("resizable","containment",{start:function(){var i,s,o=b(this).resizable("instance"),t=o.options,e=o.element,n=t.containment,r=n instanceof b?n.get(0):/parent/.test(n)?e.parent().get(0):n;r&&(o.containerElement=b(r),/document/.test(n)||n===document?(o.containerOffset={left:0,top:0},o.containerPosition={left:0,top:0},o.parentData={element:b(document),left:0,top:0,width:b(document).width(),height:b(document).height()||document.body.parentNode.scrollHeight}):(i=b(r),s=[],b(["Top","Right","Left","Bottom"]).each(function(t,e){s[t]=o._num(i.css("padding"+e))}),o.containerOffset=i.offset(),o.containerPosition=i.position(),o.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=o.containerOffset,e=o.containerSize.height,n=o.containerSize.width,n=o._hasScroll(r,"left")?r.scrollWidth:n,e=o._hasScroll(r)?r.scrollHeight:e,o.parentData={element:r,left:t.left,top:t.top,width:n,height:e}))},resize:function(t){var e=b(this).resizable("instance"),i=e.options,s=e.containerOffset,o=e.position,n=e._aspectRatio||t.shiftKey,r={top:0,left:0},h=e.containerElement,t=!0;h[0]!==document&&/static/.test(h.css("position"))&&(r=s),o.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-r.left),n&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),o.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),n&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0),i=e.containerElement.get(0)===e.element.parent().get(0),o=/relative|absolute/.test(e.containerElement.css("position")),i&&o?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),o=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-r.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-r.top:e.offset.top-s.top)),o+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-o,n&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,n&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=b(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,o=t.containerElement,n=b(t.helper),r=n.offset(),h=n.outerWidth()-t.sizeDiff.width,n=n.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(o.css("position"))&&b(this).css({left:r.left-s.left-i.left,width:h,height:n}),t._helper&&!e.animate&&/static/.test(o.css("position"))&&b(this).css({left:r.left-s.left-i.left,width:h,height:n})}}),b.ui.plugin.add("resizable","alsoResize",{start:function(){var t=b(this).resizable("instance").options;b(t.alsoResize).each(function(){var t=b(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=b(this).resizable("instance"),s=e.options,o=e.originalSize,n=e.originalPosition,r={height:e.size.height-o.height||0,width:e.size.width-o.width||0,top:e.position.top-n.top||0,left:e.position.left-n.left||0};b(s.alsoResize).each(function(){var t=b(this),s=b(this).data("ui-resizable-alsoresize"),o={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];b.each(e,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&0<=i&&(o[e]=i||null)}),t.css(o)})},stop:function(){b(this).removeData("ui-resizable-alsoresize")}}),b.ui.plugin.add("resizable","ghost",{start:function(){var t=b(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==b.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=b(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=b(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),b.ui.plugin.add("resizable","grid",{resize:function(){var t,e=b(this).resizable("instance"),i=e.options,s=e.size,o=e.originalSize,n=e.originalPosition,r=e.axis,h="number"==typeof i.grid?[i.grid,i.grid]:i.grid,a=h[0]||1,l=h[1]||1,c=Math.round((s.width-o.width)/a)*a,p=Math.round((s.height-o.height)/l)*l,d=o.width+c,u=o.height+p,f=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>u;i.grid=h,m&&(d+=a),s&&(u+=l),f&&(d-=a),g&&(u-=l),/^(se|s|e)$/.test(r)?(e.size.width=d,e.size.height=u):/^(ne)$/.test(r)?(e.size.width=d,e.size.height=u,e.position.top=n.top-p):/^(sw)$/.test(r)?(e.size.width=d,e.size.height=u,e.position.left=n.left-c):((u-l<=0||d-a<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0"),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(i){var s=this,t=this.options;this.opos=[i.pageX,i.pageY],this.elementPos=b(this.element[0]).offset(),this.options.disabled||(this.selectees=b(t.filter,this.element[0]),this._trigger("start",i),b(t.appendTo).append(this.helper),this.helper.css({left:i.pageX,top:i.pageY,width:0,height:0}),t.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var t=b.data(this,"selectable-item");t.startselected=!0,i.metaKey||i.ctrlKey||(s._removeClass(t.$element,"ui-selected"),t.selected=!1,s._addClass(t.$element,"ui-unselecting"),t.unselecting=!0,s._trigger("unselecting",i,{unselecting:t.element}))}),b(i.target).parents().addBack().each(function(){var t,e=b.data(this,"selectable-item");if(e)return t=!i.metaKey&&!i.ctrlKey||!e.$element.hasClass("ui-selected"),s._removeClass(e.$element,t?"ui-unselecting":"ui-selected")._addClass(e.$element,t?"ui-selecting":"ui-unselecting"),e.unselecting=!t,e.selecting=t,(e.selected=t)?s._trigger("selecting",i,{selecting:e.element}):s._trigger("unselecting",i,{unselecting:e.element}),!1}))},_mouseDrag:function(s){if(this.dragged=!0,!this.options.disabled){var t,o=this,n=this.options,r=this.opos[0],h=this.opos[1],a=s.pageX,l=s.pageY;return aa||i.rightl||i.bottomr&&i.righth&&i.bottom *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return e<=t&&t*{ cursor: "+n.cursor+" !important; }").appendTo(o)),n.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",n.zIndex)),n.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",n.opacity)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!i)for(s=this.containers.length-1;0<=s;s--)this.containers[s]._trigger("activate",t,this._uiHash(this));return b.ui.ddmanager&&(b.ui.ddmanager.current=this),b.ui.ddmanager&&!n.dropBehaviour&&b.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this.helper.parent().is(this.appendTo)||(this.helper.detach().appendTo(this.appendTo),this.offset.parent=this._getParentOffset()),this.position=this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,this.lastPositionAbs=this.positionAbs=this._convertPositionTo("absolute"),this._mouseDrag(t),!0},_scroll:function(t){var e=this.options,i=!1;return this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageYt[this.floating?"width":"height"]?l&&c:n",i.document[0]);return i._addClass(t,"ui-sortable-placeholder",s||i.currentItem[0].className)._removeClass(t,"ui-sortable-helper"),"tbody"===o?i._createTrPlaceholder(i.currentItem.find("tr").eq(0),b("",i.document[0]).appendTo(t)):"tr"===o?i._createTrPlaceholder(i.currentItem,t):"img"===o&&t.attr("src",i.currentItem.attr("src")),s||t.css("visibility","hidden"),t},update:function(t,e){s&&!n.forcePlaceholderSize||(e.height()&&(!n.forcePlaceholderSize||"tbody"!==o&&"tr"!==o)||e.height(i.currentItem.innerHeight()-parseInt(i.currentItem.css("paddingTop")||0,10)-parseInt(i.currentItem.css("paddingBottom")||0,10)),e.width()||e.width(i.currentItem.innerWidth()-parseInt(i.currentItem.css("paddingLeft")||0,10)-parseInt(i.currentItem.css("paddingRight")||0,10)))}}),i.placeholder=b(n.placeholder.element.call(i.element,i.currentItem)),i.currentItem.after(i.placeholder),n.placeholder.update(i,i.placeholder)},_createTrPlaceholder:function(t,e){var i=this;t.children().each(function(){b(" ",i.document[0]).attr("colspan",b(this).attr("colspan")||1).appendTo(e)})},_contactContainers:function(t){for(var e,i,s,o,n,r,h,a,l,c=null,p=null,d=this.containers.length-1;0<=d;d--)b.contains(this.currentItem[0],this.containers[d].element[0])||(this._intersectsWith(this.containers[d].containerCache)?c&&b.contains(this.containers[d].element[0],c.element[0])||(c=this.containers[d],p=d):this.containers[d].containerCache.over&&(this.containers[d]._trigger("out",t,this._uiHash(this)),this.containers[d].containerCache.over=0));if(c)if(1===this.containers.length)this.containers[p].containerCache.over||(this.containers[p]._trigger("over",t,this._uiHash(this)),this.containers[p].containerCache.over=1);else{for(i=1e4,s=null,o=(a=c.floating||this._isFloating(this.currentItem))?"left":"top",n=a?"width":"height",l=a?"pageX":"pageY",e=this.items.length-1;0<=e;e--)b.contains(this.containers[p].element[0],this.items[e].item[0])&&this.items[e].item[0]!==this.currentItem[0]&&(r=this.items[e].item.offset()[o],h=!1,t[l]-r>this.items[e][n]/2&&(h=!0),Math.abs(t[l]-r)this.containment[2]&&(i=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(s=this.containment[3]+this.offset.click.top)),e.grid&&(t=this.originalPageY+Math.round((s-this.originalPageY)/e.grid[1])*e.grid[1],s=!this.containment||t-this.offset.click.top>=this.containment[1]&&t-this.offset.click.top<=this.containment[3]?t:t-this.offset.click.top>=this.containment[1]?t-e.grid[1]:t+e.grid[1],t=this.originalPageX+Math.round((i-this.originalPageX)/e.grid[0])*e.grid[0],i=!this.containment||t-this.offset.click.left>=this.containment[0]&&t-this.offset.click.left<=this.containment[2]?t:t-this.offset.click.left>=this.containment[0]?t-e.grid[0]:t+e.grid[0])),{top:s-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():n?0:o.scrollTop()),left:i-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():n?0:o.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var o=this.counter;this._delay(function(){o===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)"auto"!==this._storedCSS[i]&&"static"!==this._storedCSS[i]||(this._storedCSS[i]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();function o(e,i,s){return function(t){s._trigger(e,t,i._uiHash(i))}}for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;0<=i;i--)e||s.push(o("deactivate",this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(o("out",this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(i=0;i+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 Date: Mon, 24 Jan 2022 03:05:48 +0000 Subject: [PATCH 58/74] Solve dynamically loaded threads not being filtered. Possibly a hack-fix. This seems like the most appropriate simple fix, hopefully not too wasteful. --- templates/themes/overboards/overboard.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/templates/themes/overboards/overboard.js b/templates/themes/overboards/overboard.js index c07e8452..4fef7f79 100644 --- a/templates/themes/overboards/overboard.js +++ b/templates/themes/overboards/overboard.js @@ -75,6 +75,8 @@ $(document).ready(function() { addHideButton.call(boardLink); // Trigger an event to let the world know that we have a new thread aboard $(document).trigger('new_post', elem); + // Make the post filter (if enabled) re-run on this page to consider new threads. + $(document).trigger('filter_page'); }; var attemptLoadNext = function() { From 4d3988bc7c4eed2afd42da9ce041711dd1244b0e Mon Sep 17 00:00:00 2001 From: discomrade Date: Sat, 12 Feb 2022 01:34:46 -0100 Subject: [PATCH 59/74] Added multiple file select dialog for post form Mostly https://git.leftypol.org/leftypol/leftypol_vichan/commit/808c2072d382722a435ddffd023eda38c413975e --- inc/functions.php | 18 ++++++++++++++++ post.php | 44 +++++++++++++++++++++++++++------------- templates/post_form.html | 9 ++++++-- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 035d1fcc..ab43210b 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -2853,6 +2853,24 @@ function link_for($post, $page50 = false, $foreignlink = false, $thread = false) return sprintf($tpl, $id, $slug); } +// Generate filename, extension, file id and file and thumb paths of a file +function process_filenames($file, $board_dir, $multiple, $i){ + global $config; + $file['filename'] = urldecode($file['name']); + $file['extension'] = strtolower(mb_substr($file['filename'], mb_strrpos($file['filename'], '.') + 1)); + if (isset($config['filename_func'])) + $file['file_id'] = $config['filename_func']($file); + else + $file['file_id'] = time() . substr(microtime(), 2, 3); + + if ($multiple) + $file['file_id'] .= "-$i"; + + $file['file'] = $board_dir . $config['dir']['img'] . $file['file_id'] . '.' . $file['extension']; + $file['thumb'] = $board_dir . $config['dir']['thumb'] . $file['file_id'] . '.' . ($config['thumb_ext'] ? $config['thumb_ext'] : $file['extension']); + return $file; +} + function prettify_textarea($s){ return str_replace("\t", ' ', str_replace("\n", ' ', htmlentities($s))); } diff --git a/post.php b/post.php index 3b6ba440..599e9353 100644 --- a/post.php +++ b/post.php @@ -657,6 +657,28 @@ function handle_post(){ } + // Convert multiple upload format to array of files. This makes the following code + // work the same whether we used the JS or HTML multiple file upload techniques. + if (array_key_exists('file_multiple', $_FILES)) { + $file_array = $_FILES['file_multiple']; + $_FILES = []; + // If more than 0 files were uploaded + if (!empty($file_array['tmp_name'][0])) { + $i = 0; + $n = count($file_array['tmp_name']); + while ($i < $n) { + $_FILES[strval($i+1)] = array( + 'name' => $file_array['name'][$i], + 'tmp_name' => $file_array['tmp_name'][$i], + 'type' => $file_array['type'][$i], + 'error' => $file_array['error'][$i], + 'size' => $file_array['size'][$i] + ); + $i++; + } + } + } + $post['name'] = $_POST['name'] != '' ? $_POST['name'] : $config['anonymous']; $post['subject'] = $_POST['subject']; $post['email'] = str_replace(' ', '%20', htmlspecialchars($_POST['email'])); @@ -781,20 +803,14 @@ function handle_post(){ $i = 0; foreach ($_FILES as $key => $file) { if ($file['size'] && $file['tmp_name']) { - $file['filename'] = urldecode($file['name']); - $file['extension'] = strtolower(mb_substr($file['filename'], mb_strrpos($file['filename'], '.') + 1)); - if (isset($config['filename_func'])) - $file['file_id'] = $config['filename_func']($file); - else - $file['file_id'] = time() . substr(microtime(), 2, 3); - - if (sizeof($_FILES) > 1) - $file['file_id'] .= "-$i"; - - $file['file'] = $board['dir'] . $config['dir']['img'] . $file['file_id'] . '.' . $file['extension']; - $file['thumb'] = $board['dir'] . $config['dir']['thumb'] . $file['file_id'] . '.' . ($config['thumb_ext'] ? $config['thumb_ext'] : $file['extension']); - $post['files'][] = $file; - $i++; + if (!in_array($file['error'], array(UPLOAD_ERR_NO_FILE, UPLOAD_ERR_OK))) { + error(sprintf3($config['error']['phpfileserror'], array( + 'index' => $i+1, + 'code' => $file['error'] + ))); + } + $post['files'][] = process_filenames($file, $board['dir'], (sizeof($_FILES) > 1), $i); + $i++; } } } diff --git a/templates/post_form.html b/templates/post_form.html index 1d77443a..02c6087f 100644 --- a/templates/post_form.html +++ b/templates/post_form.html @@ -146,10 +146,15 @@ {% trans %}File{% endtrans %} - + {% if 'js/file-selector.js' in config.additional_javascript %} - + {% endif %} From 3c74f3b34ae72ff3956decd654a5e2d9c5c5f6f6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 1 Mar 2022 01:54:05 +0100 Subject: [PATCH 60/74] Adds saboteur banner --- banners/saboteurs.webp | Bin 0 -> 13604 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 banners/saboteurs.webp diff --git a/banners/saboteurs.webp b/banners/saboteurs.webp new file mode 100644 index 0000000000000000000000000000000000000000..b7f1ecda2ff76e5e6bee679716f95201213b384b GIT binary patch literal 13604 zcmV+0d5iEd5jcFZCbXzw@5~{YCzA z|9kES`i1_R``7Oe`5%gJQ9ssy%>UN*0sPbZ7y1wGe(FEv|K@*<_bK}&{|o!yzz6d` z>Ywj@s(-$F2>*xwckC7X$NO*m&t@<7pZY)7e*gUwe$Id1|2O;b^b`EY`!D>D&QFjJ zKo39;#NX^)tN&B{cm1jLfAO!CevSCa{fGWf_&PG|84E#{Wtdi+HZ3Hwf}egfcgObDg3|tFZK`FFYbT& zzN!Ct;^p>#@qg;S$$mL~fqy0bdHy&1=lNgqf8sy+eXsu+{{#GQ`oH+!;D7)7_x#iQ z$NOLK|L1?||AYVa_znDX`PcYg?;quV-hY7q>;DVy57=+*zp=0DC;R`-(mf*YnIKsZ zsTRS~8i9XbFlc^srdoDK9|sgI)YimVm4o-UMusM0#z%e~PwnV%f;tB+XhVt(Bo({I z>u3xk3g4p)w-}`&@t@f5=;6QBj=NJDn9}n6W&cnzQqV~O72{~;l*UVq8DGcH$8 z6g{x?>atWFZF9T0X6xwH8jPU(VaeY{aHAiO^*ex~mr_Oxk017&2F$i>(V^x(PA zv^^LU?g|^w4^cNYnm;HNQ#J>)Z{DCgO)LSbh`GQ%0*zQLK+QMnwt?6(-e;T4Pv3e# zEuD%5G3B<-p2o5|Z{pOdB+$`|R0=HNCE30g8ZMflnnU-VQ%C9|cG7a&-zi^PUUN-UY?LN zv?#t7T}xncJ@(d$JSdB-<92>q(NwZGS5WBK94N-LzWOHy3Z&owi^`|MH&s_d%WPA< zYIt?{7abQtR2AdOziT#1W!%zW8!}D*?G(x>M9t3@6rc#_+fnywM}<(r0r^C1d)syTWU_yuLzsE4?_sjB zk|rY%5!%J$f%p040<<){b+fjy=hUQs*9;On(EisU=Fs;z0d)GJ_1Zs!Ik02a9C>JB zoi$fNSP0F-F}biujo}*;n7-OZc(MyiHtQB$Jw;G`aRJysZNH_5xQIl4*z;F3ozeg_ z{o_kh08WsK%T&{LqAFIpa(O(1_uur2LP*OYJE2JdSxGN|4YiwRQ@SS^7OsIQ)wqRQ zsIbA8isb(P4(`CtD8M0-prvK?WbG?UHgP+IOxaFc{BEJ$?`L()aQ(e#=MBerLVg#* zSNy&(q7c|^UpM*5Lx!?Fqg2g;ag#Nze?Xuzi=jB#{r|Vftz|DyQDJeTSAAGcCp%=) zGMB-{SV4BS9#l(Zf@Jg2mZb8;9lz_5Jh4N?f_3KQ8moYYCt@C`98JssXnGdDb!#YZ{-g(H{CYOahd}yn@P_2o~6=xIfS4 zAMvxAl1ic8)Zzs}Nifuth)i`h!a+tYzChMd5haQ7a#Qq0GRf+0Bq<`F^MeB$v%l5G z9ULlR-`(c~=Xu5{)%D-VV3PC9Q(j8#Ml|D@Fcag{n}Wn`@iiBIg~j@fx8eqK2BUSr zM!AZ{KhU^n;Qyh9gxaa!B?an;n%WGzk50#y`Ab)>wUrdB z{Eccxuq5=7*l9k3;zTYO=$ReTnL{aks`cfv(Oh0WL*Nv)7sHuaQAMzHy4f{(`5N#x zTG3{vYydSIImMgpl;AxSNcz>7TnD%KfVlXp;o1kb5VR{6=<6zG(rY`P(zPZ2oRUTk zX97+mampPV-0j;ohEQ)G5R{Jj0DhuLO(64d-ZQxg<8E_0QWelkUsQ7$810!`>mrC1i0qqW*{&? zoOWx+jy0m610)!O;b}!5!Et8h4!LytYs9)%3Y;`HYXNwnx2!x2-D1%3|ClIgMGex5 zP*#pAf`fsYKi5+UzELwDQ$M%l%iasmWynk1JuW4;cO@YqS27N#V&{d|@q3cVA*KWx zo#_kVGA)U)yOIZA;sjr0k6Oife6CZaoc-#bwCbO=5i zHuVe!sTS0Do`aY|!C6(&y{IhCUJS$>hpmPP1?nKIz%l9Cyz=aOBL-ZJ1&!vOgP?`- z>-ysd=P}8@#kwtENc5$B%W&_k{!%kPM7_&)a=|ub(Zsq`Q%#D5v7iQ!tmKEcb}L$d z{=i>NVfEO{t*twx-dlUFSB$=4i427j@4sF_e%D&@UOX zD?6gad2UNu<;jPz*U_&KVrhCn)uD(e{$=B}$>J~?qVuatK;jZV^JRMi2Ni3Q9hex91)k1Z1> zn!fIAJuJin@J={Lc!%Fq&$ExXs|XuVB{p(ymiC=TKqf!OLCz;H%f}2Pa?9)VAzZ7J ztdM_nl&Py7=UUcK8_Z(@EJ{EZSbS+jtDdBlpYKC1^mD5S8kd+?=A*?h;g^J%rq!s*|5628cMlMMQmhXb}+V3*Dp+ za{KdFzii)}Zi6#2k~UX)g*_TdxM8rRcdN2*C-Ghu9ZMtY=OAbg@qBd15$O07G(EW* zl*Oq5k_g3G4Tq3N_mf1+cRdp2wRo_1uSB$c+t4lmaqjMUzU~25aBqaafc++>)fB`J zN|Qj))VM|c$oQ-|&-NG3?OsSWq-Nhn^t_o>%+0+v8Kny_R=NPPL}NA69t5LKEap#V z(7;(%>`+lZeeb$SyEjOsRfLwqUY&wy$NFTAho&OWBhM44eDF%c!D|LiuJ**Quu5i9 z+O>Sq2m|M>dR-^*f*{sL9#X71RLJ`5Cy}L?kyw0DVySYTY#>(z)=sY&2OdUTw0hv+ zz`tqht|s1;aWF+#d{(7vJT(;(`FSjM^GNyg&rWIevDBK69D2Cu-J-2;(Yl)UTs5o{~%II!z3qt zK^XWn-;t0wL8C|56@2qVS#rbX!<;)I0YK4V;lI7(#`NSyQT0$!pS$>2NZac_tmXPs zhk^t5@P%b@FL`GRXSH}V6hR-zyKda~BIe#}N<-jZt zv{IkWAEld?1mF?P>m>EX^dY{%*Oqsyx|-ehvs* zwOw_$lw=~!Txh0m>r=G_n>lmon+}9sO)IuMwRWq+pAI+B12*$BzyK~ykv5cK2okdlgjK z657=NM4*zCZ63vxV{U2fQ>#3I{d{F5A&XavZ;OsbdxL^7f105BlD^TR+l3iY26*r` zp#fH1J^56N&U+^dSuJ;plFa}LA%`Q8brBg}Uf)}|R%R2ryn14YzU$B8<6I6Oq!!pXL`76}}v;?suM zm~)?rarFT7D&DeziCW#)Nm(^r1IxF(PbsjOo>wb=y8HMk7o%Q z;lcO5ChP?3KvL07F~UBQArG%z!qv^hI92&0ooN`9K)3lU9mI9qA(Ozog5MB24K1qA zEt2%2Pw7+A96xC|$EPagN=#kb28}Y=bGjkft^eKsi0cCiLK#k@<=2;|Jr&jB zMG1Nh#27E%F^vKC50Y35{>B|{HTS=g$8@v*irpIfP9G*qG&K~~SF>`gDq<}1oXd;K zk@WCgXZMB9D<~F7;N8#xuzs$(I$CN2=^wql87P*YcToj`E4TFoPk{d=eDH3A%dImK zqT-I&{Nf%S8KiM)Hd7F`{^rwPzkAMJYIimw;E9!L(Jz@#OXgSS0d&7^Y#*P~@u;mu z0e#bQIlP1p7@r_oEJ6+t9b$tA_)lcc(+o+0vk200au3EmZ1>-Z zNi5KMFbIdlBn^Z{?kXRf#gsdrGkSt1kAe)G8u8a(CJi8F%X)C$v88le`BqaTuoPZT zq_2qLu~S28>I1qlUyGT6sO=DXJ$zrFdIWc(c-DC)RQOcX$intR8C*Y}yD_#ioc%2iEocySAgQ6dJ0y&kd5Fssn7)(|6(OG1N+D&BkOl1S3C_Y5)L|v zkiog=KA!k5m?L7i6ioL!$bjQM8kG~O^86=RWT)I~E}azexsQUx9LH{Jv4g;#w1*Xc zVYnC=98CvN%X@4hiGQFw|He}R6dJ~Vwn z-$n7Wn`)r+^-FM*B*jpGFk`PL;QX@QI*JyHVl7i-eEu$vuF-yCW$L$M+ZF>%+4z55 zl0PmT zN4-(g1J9oOSFi5|ng&z_i%IZ+QFx2D7#oxTh8>;~VhUmIw}oF%SLt6i0OE*nAeFc) z-H#n^-I2et6dLzDL!AK6ki*_V+r|A;CiYZn?b~saQG$Afs0A(?c`rWgAa;lnGtvj- z9>=Cu^uBj~UsXvzbapbwyB)P*!j+4)TI}8;DLXZqQ~YMwBZtz{LgBP@mWacnWIW~ zl0kmBh(2lGTdb+tFW)bVL=t{PKho;{yrQ<+5f3JvtEQBLLFpG@aA=_qRB*OV3@}~^ zMM0e+ond`)CK8kfu78Uk+~6sXWptJ+LDbWxrqK+O75DCgc>wSV*)5n01n%CsNpx~q z*^mFpn1+UYU?mc?HCVo=mLFXOAO9Um+u;NX%fhO3EU*ZKM< z-rOl66s(I76qoqF1#?2`E#@fp#cn>Af%}(X8u*^+h*6pjQy=TAD0jOSnx$B2h?E@d z{oGmpOf}bXTT*R}ftI_#Ye}ue2KS4sDOp8pL;KW5B;<))_@G5VlIC>d_;hi-AFMs@ z^S%2As9`UJ9mq-VE{8R=>61e+7kR)ZgITAvjH-zTAie~s9jk#;wmo8Eh#-1|njCli z0gLHGLoO1N@q!v(s!U6)QK;sninB$AeNf1NcfPM3?{p%D*doh<>D-+)5R&Q3RC*aW ze9d>Coc{8&`7bA~Jk|ksVlB?QHbkHXdr~9Ndi@#My4bmI$!2&AJ&on;N4cVZmjDqR zNvVsFry0HINqYqR2zmCJFEIuSo1mq+ZvBgpJEbFro*sWO?3q9_nAk%yk)LAJoF|19 zLl_C!oEj|77!q@@!oxSNOpV`YFHkv`c{X(< ziW-!!HW*U4S>?MV(I%ji_d)j-=r0pCTRl!JpzhDs=~%{(^-I@Qidsw>OtuZxlFL@v zO-5L^0z6l>ua4tOiJL-q_NO?ey=#?z$qDSR(659RoFnP3T;I7MZ7>^2m= znuiSn^H&Q?ZbZl-4b>F*cQ#Jk2cTvr0sfhmj9W0z@3`T@yr9!y|Dh+pa$Be_XZ0QB z6d(eh65ko#&xnyUN~R5$ath&?7gps%(9Dvs1Rt6sGrLBC8~yllfO(bNIiW;!6=l>b zm-+;5N7(w?y|&a*<MLDGAGXc$i?Ba4}AV%t!3122^j`|HGwPP+npFi|Y z<<@&Kk$44!6NbNqnOGZ0hlCU6EJ^U^Gp?Jmyg>E=Y4~u{&rii|7v~{UYKf&hUZmzx zcIJ!Urh&j>6IU&OuHY~Lof>=eUmzZ{&;?ZwPwN71d$Ha9knl&k5n2nq%WJC$~NaG&!KmhqcX$Y-85Eh097b~B^# z|1TOO=7qlc4Y8W59uey>i^4!K{t9K;?!4N<94&HEXsZ#mP_j`lIXtEe$0IVkMLNj^ zA2YGCOsCx%C1-r;vEHTJ0566OM^c9X0hSOvQ?0T}lK$1$038u$&jh!&|J;$av&F`= zPpnKHQ530efuO8Lkl{+L0xu|v%*kbiZTG^cQ(A`%_2ewMMhdolykilisrW!vQ&vOL zl?g^7|M8NHde%?wk$*UFsC9>_X9I5=e0@$66y!zy*Ove>z*7mZO-*z00fz!Av#NVZzx5ZH-f2tZn0%kJN$zT)g=q|6s`*f*{@PxkH9iF;_ z)b^EGKXsbo-1n|}G5rW0Z_%)JPhcSZn}nAntz$lF+jJ2J-Gd=-#X*FN&4J0fG6NVl zH23w>tI0ZuU@QK!+}c>03x;KV0B;qR#VDkktDT(*PwR`flE+N?E;T7g2aK4VRYp$U zBMVU!rqzgZ1@?t5D@yRjIFZ#Bzz*X8)nerLqSU|;-vG|T3&sGoh&1A?xeF$=6~VBy|Mo&#=?+-GMA36j%_kvsR)$QqjgD zz>ypB)kr;6ZZ0N6?X-jYD^;D9*U>^2)2G1Nhg$ z=+oTk@9W-sQEpq6eM>h2jvM%nH2fm6h3~2pHDp9l4uSHxljjT7AQxg z+Nz`$YLxfjdgKZK&UCOh!yFfqBqxP^b@KKvQK#Uqw;hhm0eIx@GzIhC6~5o0ff`7X z^VI%GIF6EW3cyKC2xebz^5MZ+o;1|u=!;8wN79oAxEwgCa=8GkPY#%Mc-vC5tNTVF z#sbjR#`tYo2CN0`Z}LDU#cWu zG0oDY1eZSLZcw*)nKh8>qG_#l)%lRFFH@>tHjKp`Y+ON4M9}ON7mjAxOxh+BzTj3R z2HBZdO)qO=f4YRn*}Q4`c0ULdmt9WzRN}>}F;?xFS9uC`1epT?(Es(f%|}j6{O0)) z5j5FcE6SL5ceGZ^py^X3J7`Z;LTO9M^tIiLLRA8AqsDxB+ydZN7D8j(B5maN8bhYb zLX1@1x96{0TqM5;OD>DbQ>bn&j_MYaj=^y`3g`pPcg*`}291#Kvz$d#d~lsMgXXRW z(`OctP!FFnlNy0br+?y$5vfThNg#@-Ut@IBA1y{YvHab7CSWm!>2%Ed34pv)9nYOJ z2T5CgzS#BRfD{LMZCe+>24>K3c<|NI=p!x6byl}9Ddx?Ppm}27_}|F`ZNbwpr4M^( z;qvrVPH6v+_jCfIUT_bPCsI)H@z~ura8j^Zu+DM1V>)2o8u`G;vo4LZ zy=KM<%;d-Q`#*6T?m6I&u-#(ZOR7nEiU6_=L&AeTruo-39`}~zQKm5(&$|oK$6iDu zifzb!ggDF=7!8vefZQ*ri(^?1N z`26Heb3+`J%voftfp z-Xx^M`}b1O9G%y{6Yl0v1wC?R4mkl_C@m@#eV4Ag$>+@ z*w$R5ZB*OmfKbK@zLQ7Kw#ca$J0IzTy9ENl`~83ST67MUz6jX@U9wBbMF z6J^(iU^(DE6VkO1n4qK`XVU5a4MBdVkEVdj5`7P3O-SU@&}*R|QFVD6Bb5moB3B7O zKDV$zTCYVz03odwKuW`#4 zRy?$1lrP;tTxrD2pk(gfz0wG52h~meV~7B_drM;45aW?BgS|L!! zKZx~&*B;ci!l8-*;~5D!$)xRfuCn&!C5c-{8LhKquEHjy_ zbKn~)-%T~DQh?vpS5%%od0H*yuJ$6Zjv8ysN?TXrO!Js)N3jaq`cGPJ5=YBB({2@^ zdGj#9w-C>dq5g!xYN&*lmCF8BwY@DF)wYQ5)cuchoul`P@datO7xJV_{QqBI9H)Re z3Q)+ooc;rwmj3fm1dynR?5w?Qd>C-;guZW6&JlYMHQCSnKnV8IX;*Ln4dF~ zc5~yupmD`!ek`SX13e?Z#`ziEOx0rv=bzdn_Vm*QFUFiH1NkbDzSj#gQYL#>oKixa zuxVG|+;$G4;4mKGTzTckZZ^07iiJ~B{k#<*Ph&aE=$8iMrS1w7SBu9zW!2R5ZzLOs zBSTee8DzLLPw=udkWR8xhCHG$w)w|kEXrikp=6E{p`~tj^=%m&_6NQb(QJZFg)n{S zOZb^V@#>$>iH4rSrf-$3l}w>;Q<;=Q^wTI)9AUIqh!WiVgkc5xdso$brA=3id{Bxs zGbFfN>p8p%->P;Ozk9wV89?fybUr_`Y$f>c5)SpT_RGqvc4Y7m_2!iq>6GDM1eLY| z&JQ&~=EE`(N=RC}3rsJ=Jc$8Yr)-TYh;$A5l7=t?&Rb*!G?^75x6G1-+hBciZ@b>} zKH80Hv2fb67Jpff!}!XbrV=M!)uWg@O zbyn>tFY#b6jBi&Wg?t1MqoCdt1j$1H!(KD&6UeyWtHWk#J?&%x3I?|>d@NxUNFqhL zrmJE~t50m!O5f-s41NJuWR9#P+2CmQT`}uwJ0Pm!E6}wpv6Q8*Dv}jJVo|*(&u-$V z=|HAjy>~aXVNL_T(~_V=@QuDjG^AyZ`-}U8gbS`A$OHx!iU|OBMygug#i?JH!#Wr-eL3%cQ(^Z(rn01?a{QloTp#JeYs~Bw8(ESNMdBE4{y;V$dv8uV9 zjW)Wy(wMPVSV`h6c`?yL=UawY2KQ zOd)>#`htf~8I6N3O}l_OfzjB)*^=17yqv41CsNX@85GpyMO(wooOZ%{9_9}y^9Ds& zTzn_p!~NP}aF&dBpoGL$0-JKgrC-=~4Qo-H*@nPnMieJD*X$w>(et{CFl*`UBG1uo z^p>~}Lk(#UxkDgNwU_jTl| z6N^EBO2&2`)z^~0;l9BSfT8M7$2MhnjCzr(p>|**7L-#6uRkM{qgi^ArC5 zS%U?4UE@%myYHn{0Su|^jUS*hGA0o!*!&~S`t%IoJ@{#|Q>bH;#7)Ium#?cv5T`Rv zanFs#Y?-+i9>J{hHtEQwQcBwRMF`4|4pq3-dC>47Kj6EIwjL2(G-BQSdZin<5Yzr*yZve0IAkb@@my{ z$IGXIDK0s0Ku;bJLPRv~HFJT4oTXLCR58a=zx`F$#ifn=L}FlR6Nui?T>UGXvyKbP zzDV8}t!?VN>k1!**2Et>-#$q_x6Nar{eD(@;erO|@rmoT$F*s#F8kx!2R(AI|L*n2!i$3pSqk+kNJ*~@MY^-gtcx5^X^-{agVC~C9`ha1sA+O3iKCx z+_u6FG|pgxWT-0|*F`y|$2~pk&}HhZxm+>9maSsoxTerJZv44=tG$567FJv0=A{W^ zBvdJwIdyPVe5p-X1&AP)mkSKLTd8#+P-lTE{*h!^INON`dB$j2+1M4&N?pOlSQ{;W zOpri;#9^H<<)QpaxclzQ?1q!`9BEk@%+n|5K-}$Dz`!46>SRA_Iex{vA>YfH28s#dutRFgi9x8%POy~y7B9xwQ%IRuh zl`O+Tm~8u7XT)zM&>j(({kzh$0X(_hD47#N1hb?+=Y(Q8U+!@KO;*4oz&#lWRA9sE zDh)gzB@Qkb`haBnoW5Ir+Si5w95|^E7XnDkF4X4HY@3(x^chpkvvl*|CwjL55^TUK<+msbzT6A5$S=98< zO+i7udTU#`Mn1z%)!k{)rP{5y_?ofWI&vv}(v>~hp{I`4+(sQmU6|F*vK{d(G2JVt z!u+ieuQ7mX*%lx?SGFuNoYcN6x2Qah_OP-1S6OaUg4g&>wj~;U>PSXfp)u}TXRRBi z1oAZSri$)JLfC14=~!053YL00K$1XcIc)(4Q>HASW4+1)% z(BX&OPad0h_{}&1Y+M^AH3>4a>~|5e`|P_Itklh2UNHFezZ6L+^);F3++Oguk6PYl ze4D3fIMd}Wy9yU%6?WSUks=)o^d;a9kM+Dng--RF@M-4st01AvINyPEJuq;2N<$UZ zK~+$ppXQDCXRV;4iWL$C`GKP}LrDCKcYU4{0DaXwZe7yBz;jNIF;gV|n)3cK$rV9U zK$x>c4PwhE?UkHb0H&n(mln(dy=k!qYx(kF`yJ=zn-sb*^y*TUJq{yhXWPx(M14jj z*t4YxNefpyZ2X0Bq$NM^NWC0lg`E3M7l$rql4zr8+4vW3LftTZP?EZH5_I&UPDWeplR8(yJXk4_8Nx4YMr;IS;KvauwC~ z?!odOD$hqMY4hJ`QiRY24HDE;sG%l~Bg7ONwYm!z6_61Gjach2G&ptnuXGq_WIXgU zH_Zpy-|h9UUx%Bw9Qv^)7Sd8^O326;N9rBUFM`E5(mM3cdHlLbR?*NC zim>HhFM7hW=?ipZo} z%o_0Hvz1~z7|jXdxk2t~tc((T4;CYu10(tu&3l9Vep=aAc4yvS>rxZ8K1S4+gC2be z;^uSp8&n9*&tPB9lyZJkXqZIg%d{GZtqo@sV`sgcF>+Z`xqwL!j~J%^aP2y4c#fr} z>~O;o=G6;whd=E>C14cS_nj=pTfmprwy>mO%c9MWbi^TJe(#7w3H{qZXbtBUHSe@i zuX2=rS6f;n>`g?DKf#h%{S!;4+c(sZfEhFU=(0y)>(0GK?uiectM*Epx0Ro1SCKBY z&eP^$j9@E-GY4!`;u|brFG7L=?mHfh0-KIC#ZFjG2D7P?#81CM$WCXUb(*V?)i3+* zQw{WS6?BVN5jKffmNsd!AU#Av2K*BUo32aZBH~<}n=y5XFh^2hyUTx->mjZ;;AQgR zzu$0u@)`8Gmk_>9Vl_2#>kKl4^CxFJeYQ2uYu37BK(dZ}C&2A|Fp+7|5xIU|Yp#Nw zqU6+eUvoOr3`fc~6UWaXsW8_$@$LkgakH5s;Y<2*HM~-m8hpwSf-Ai^V)|QaTj7vy zA~dRDtFig(6d=aXre%wiShNP>FlRC8YE-VhJYEARa{YtFBn&+e(v_62oh1;u2=UHg zs>p(JDJr}Erv}1LaF~&8D#ER?tO>DPEP>XKNLGfVxk;LzHGkOiQ4rY6IM|Un$-pIX z{AYEzwx5WW(OJOgyS98i4v`TPGp+n836!!7$+~jf6Z+mGXv9ZF6zJ@pyXfJ}36DB$ z6-MENzDI=UkV6KrRgX0!?v&D()_~dY7b6W}*@9%HcDm(?5qDEtvx_!Y9Yj z2c7|4#DU2RY{{4k^I4QAa+B;9aA@Db)EB%i1LvrZ;%Y)MTE&>)h8;SGVqkCChif{c zDj{ys^UtNFI%E$S*_=-dk6Lxg3S+eiQNyXE*U)__F4=D1?*SsxBp zSEkoREl;z2V6gYbWT-=kIg_c#8ny&Zk>!`V1O(zzjuedMUq+G+eslHbPP6Zpjf)AU zn9AhgNpVTFM*iAxf^=9U>yhYn{;%Z<9x_8=qGA5v*FnHNbu4ypV5~2_#nZ|UzPkn; z&kH7CSN1WJp}hGZP!N7+%Ns0g27r=T?A{kwRU~LI*!Qxw5G^x+HHY4v-Xx<68RLJN zhitf)g9U|?$Vx2KE{kd9KI^&!hbAc(Keorx0?B(Q3^4s1I0B7in+-EggQWe^Q`blf zYqD&toKSPxGNdcDqtY=K(iG%b%%vMP+A{{sIR{zd$Un7K&X!Cu#yn8!Lbs7dVoD|m z{;;fl=#~0x1N)@NJy+;ypDz#IO0hqIi4}oH=C4PIm^o0}yPY&cR|l0ktA$5ly&80j z6ISJFB%tc@Navc6RXqw=d!LXJj$M!g8+6t<|JL}Pa%u@rdkTHiI7sBeqP|aS3?g~u z2jGBx6XZ>v<4*AX3d{3`EK-_`m8(*;Q)OiFz5^QcRGO@q_ z4Gcd7;9aL}_*xrehH@ZL$WD*r^8kF@*yVtxjxQ0t+DQMjy#}-m9Dlmr_s<vCXp?`oWK9@NE^OA---6J=TYP&(3yfgC<;Ji?tiY$oS~!jS}g$~ zfT}~5wSvjyAB6kD#Jdp$3q4p8*fjVsIyDPFfO3!wbl(x}sI=#kmFM&dLZdxC8mM>F zElPwgo8z>Rb9N~pFHwLqFKT{NxFM$QKgt> zUqs5$v>NrPT(N}USV^`^`Wgdb!j-EOtXvJ}R5a8%UwV#HFzr*MsJ`~cesoP*^z&Qi zNSqgM;Hsd5r1oeG(y`#{w;a0c_)FPbZoG_l$IHAnk|*~^Vbfdso4uw*_SD%!Zi>e+ q=u;wu?bF``#4mnw{N!W1!YfzC&nfUK^2=SUtqpa1|VZkE&l literal 0 HcmV?d00001 From 985d6f4dd66bfead158c2be016024347073f8864 Mon Sep 17 00:00:00 2001 From: discomrade Date: Tue, 1 Mar 2022 04:55:53 -0100 Subject: [PATCH 61/74] Fix status.php --- status.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/status.php b/status.php index 3857fa25..5ba4c0cc 100644 --- a/status.php +++ b/status.php @@ -1,6 +1,6 @@ Date: Wed, 30 Mar 2022 23:59:21 +0000 Subject: [PATCH 62/74] use more cache. Speeds up page builds (#72) use more cache. Speeds up page builds. Tested as much as reasonably possible. Works well. cuts self delete from ~8 seconds to ~1 second. and mod delete from 10-14 seconds to ~4 seconds. Co-authored-by: nonmakina Co-committed-by: nonmakina --- inc/functions.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/inc/functions.php b/inc/functions.php index ab43210b..1ff9768a 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -1690,6 +1690,21 @@ function buildIndex($global_api = "yes") { if (!$content) break; + // Tries to avoid rebuilding if the body is the same as the one in cache. + if ($config['cache']['enabled']) { + $contentHash = md5(json_encode($content['body'])); + $contentHashKey = '_index_hashed_'. $board['uri'] . '_' . $page; + $cachedHash = cache::get($contentHashKey); + if ($cachedHash == $contentHash){ + if ($config['api']['enabled']) { + // this is needed for the thread.json and catalog.json rebuilding below, which includes all pages. + $catalog[$page-1] = $content['threads']; + } + continue; + } + cache::set($contentHashKey, $contentHash, 3600); + } + // json api if ($config['api']['enabled']) { $threads = $content['threads']; From 6f2e953bd51e273af63e49b457ab410c6e33684a Mon Sep 17 00:00:00 2001 From: nonmakina Date: Sun, 3 Apr 2022 22:06:42 +0000 Subject: [PATCH 63/74] Matrix report integration (#74) Enables posting reports to a matrix room. Co-authored-by: nonmakina Co-committed-by: nonmakina --- inc/config.php | 8 ++++++++ post.php | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/inc/config.php b/inc/config.php index c5fa69d9..1b80cd22 100644 --- a/inc/config.php +++ b/inc/config.php @@ -1824,6 +1824,14 @@ * ==================== */ + // Matrix integration for reports + // $config['matrix'] = array( + // 'access_token' => 'ACCESS_TOKEN', + // 'room_id' => '%21askjdlkajsdlka:matrix.org', + // 'host' => 'https://matrix.org', + // 'max_message_length' => 240 + // ); + //Securimage captcha //Note from lainchan PR: "TODO move a bunch of things here" diff --git a/post.php b/post.php index 599e9353..7996cedb 100644 --- a/post.php +++ b/post.php @@ -390,6 +390,24 @@ function handle_report(){ } + if(isset($config['matrix'])){ + $reported_post_url = $config['domain'] . "/mod.php?/" . $board['dir'] . $config['dir']['res'] . ( $thread['thread'] ? $thread['thread'] : $id ) . ".html"; + $post_url = $config['matrix']['host'] . "/_matrix/client/r0/rooms/" . $config['matrix']['room_id'] . "/send/m.room.message?access_token=" . $config['matrix']['access_token']; + + $trimmed_post = strlen($thread['body_nomarkup']) > $config['matrix']['max_message_length'] ? ' [...]' : ''; + $postcontent = mb_substr($thread['body_nomarkup'], 0, $config['matrix']['max_message_length']) . $trimmed_post; + $matrix_message = $reported_post_url . ($thread['thread'] ? '#' . $id : '') . " \nReason:\n" . $reason . " \nPost:\n" . $postcontent . " \n"; + $post_data = json_encode(array( + "msgtype" => "m.text", + "body" => $matrix_message + )); + + $ch = curl_init($post_url); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $postResult = curl_exec($ch); + curl_close($ch); + } } $is_mod = isset($_POST['mod']) && $_POST['mod']; From fcb7944a35680e964b6eb947c9e5f0efbbed90f7 Mon Sep 17 00:00:00 2001 From: discomrade Date: Sun, 22 May 2022 19:42:57 -0200 Subject: [PATCH 64/74] Added Feature - Premade Ban Reasons see https://git.leftypol.org/leftypol/leftypol_vichan/commit/13ac9172e7467519a4dfcab8c6919e05fcc05438 --- inc/config.php | 13 +++++++++++++ inc/mod/pages.php | 1 + js/mod/mod_snippets.js | 12 ++++++++++++ stylesheets/style.css | 10 ++++++++++ templates/header.html | 3 +++ templates/mod/ban_form.html | 31 +++++++++++++++++++++++++++++-- 6 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 js/mod/mod_snippets.js diff --git a/inc/config.php b/inc/config.php index 1b80cd22..b69806cb 100644 --- a/inc/config.php +++ b/inc/config.php @@ -669,6 +669,19 @@ // a link to an email address or IRC chat room to appeal the ban. $config['ban_page_extra'] = ''; + // Pre-configured ban reasons that pre-fill the ban form when clicked. + // To disable, set $config['ban_reasons'] = false; + $config['ban_reasons'] = array( + array( 'reason' => 'Low-quality posting', + 'length' => '1d'), + array( 'reason' => 'Off-topic', + 'length' => '1d'), + array( 'reason' => 'Ban evasion', + 'length' => '30d'), + array( 'reason' => 'Illegal content', + 'length' => ''), + ); + // Allow users to appeal bans through Tinyboard. $config['ban_appeals'] = false; diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 1b68fb2c..c2927de0 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -1872,6 +1872,7 @@ function mod_ban_post($board, $delete, $post, $token = false) { 'board' => $board, 'delete' => (bool)$delete, 'boards' => listBoards(), + 'reasons' => $config['ban_reasons'], 'token' => $security_token ); diff --git a/js/mod/mod_snippets.js b/js/mod/mod_snippets.js new file mode 100644 index 00000000..8e9ab800 --- /dev/null +++ b/js/mod/mod_snippets.js @@ -0,0 +1,12 @@ +/* + * mod_snippets.js + * + * Javascript snippets to be loaded when in mod mode + * + */ + +function populateFormJQuery(frm, data) { + $.each(data, function(key, value){ + $('[name='+key+']', frm).val(value); + }); +} \ No newline at end of file diff --git a/stylesheets/style.css b/stylesheets/style.css index 1803bb9a..60c826c7 100644 --- a/stylesheets/style.css +++ b/stylesheets/style.css @@ -1958,6 +1958,16 @@ div.mix { display: inline-block; } + +.ban-reason-table .warning-reason-table tr td:first-child { + text-align: right; + padding-right: 10px; +} +.ban-reason-table .warning-reason-table tr:hover td { + cursor: pointer; + background-color: rgba(100%,100%,100%,0.2); +} + footer { margin-bottom: 50px; } diff --git a/templates/header.html b/templates/header.html index 0a7aa95f..68c0b8af 100644 --- a/templates/header.html +++ b/templates/header.html @@ -24,6 +24,9 @@ {% for javascript in config.additional_javascript_defer %}{% endfor %} {% endif %} {% endif %} + {% if mod %} + + {% endif %} {% endif %} {% if config.recaptcha %} diff --git a/templates/mod/ban_form.html b/templates/mod/ban_form.html index 1f940ff8..100c497f 100644 --- a/templates/mod/ban_form.html +++ b/templates/mod/ban_form.html @@ -4,7 +4,17 @@ {% set action = '?/ban' %} {% endif %} -
+{% if reasons %} + +{% endif %} + {% if redirect %} @@ -41,7 +51,7 @@ {% if post and board and not delete %} - + @@ -93,3 +103,20 @@
+{% if reasons %} +
+

Predefined Reasons:

+ + + + + + {% for key, reason in reasons %} + + + + + {% endfor %} +
LengthReason
{% if not reason.length %}forever{% else %}{{ reason.length|e }}{% endif %}{{ reason.reason|e }}
+
+{% endif %} \ No newline at end of file From 31b97dd61dfe0d176f599fbaa0e46f5d29becd20 Mon Sep 17 00:00:00 2001 From: discomrade Date: Sun, 22 May 2022 20:00:40 -0200 Subject: [PATCH 65/74] Fixes for delete-stray tool and cli.php --- tools/delete-stray-images.php | 27 ++++++++++++++++----------- tools/inc/cli.php | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/tools/delete-stray-images.php b/tools/delete-stray-images.php index cf94dfe5..1c334afd 100755 --- a/tools/delete-stray-images.php +++ b/tools/delete-stray-images.php @@ -18,17 +18,22 @@ foreach ($boards as $board) { openBoard($board['uri']); - $query = query(sprintf("SELECT `file`, `thumb` FROM ``posts_%s`` WHERE `file` IS NOT NULL", $board['uri'])); + $query = query(sprintf("SELECT `files` FROM ``posts_%s`` WHERE `files` IS NOT NULL", $board['uri'])); $valid_src = array(); $valid_thumb = array(); - + while ($post = $query->fetch(PDO::FETCH_ASSOC)) { - $valid_src[] = $post['file']; - $valid_thumb[] = $post['thumb']; + $files = json_decode($post['files']); + foreach ($files as $i => $f) { + if ($f->file != 'deleted' && $f->file != 'spoiler' && $f->file != 'file'){ + $valid_src[] = $f->filename; + $valid_thumb[] = $f->thumb; + } + } } - - $files_src = array_map('basename', glob($board['dir'] . $config['dir']['img'] . '*')); - $files_thumb = array_map('basename', glob($board['dir'] . $config['dir']['thumb'] . '*')); + + $files_src = array_map('basename', glob($board['uri'] . "/" . $config['dir']['img'] . '*')); + $files_thumb = array_map('basename', glob($board['uri'] . "/" . $config['dir']['thumb'] . '*')); $stray_src = array_diff($files_src, $valid_src); $stray_thumb = array_diff($files_thumb, $valid_thumb); @@ -40,8 +45,8 @@ foreach ($boards as $board) { foreach ($stray_src as $src) { $stats['deleted']++; - $stats['size'] = filesize($board['dir'] . $config['dir']['img'] . $src); - if (!file_unlink($board['dir'] . $config['dir']['img'] . $src)) { + $stats['size'] += filesize($board['uri'] . "/" . $config['dir']['img'] . $src); + if (!file_unlink($board['uri'] . "/" . $config['dir']['img'] . $src)) { $er = error_get_last(); die("error: " . $er['message'] . "\n"); } @@ -49,8 +54,8 @@ foreach ($boards as $board) { foreach ($stray_thumb as $thumb) { $stats['deleted']++; - $stats['size'] = filesize($board['dir'] . $config['dir']['thumb'] . $thumb); - if (!file_unlink($board['dir'] . $config['dir']['thumb'] . $thumb)) { + $stats['size'] += filesize($board['uri'] . "/" . $config['dir']['thumb'] . $thumb); + if (!file_unlink($board['uri'] . "/" . $config['dir']['thumb'] . $thumb)) { $er = error_get_last(); die("error: " . $er['message'] . "\n"); } diff --git a/tools/inc/cli.php b/tools/inc/cli.php index 95d51573..b04d042a 100644 --- a/tools/inc/cli.php +++ b/tools/inc/cli.php @@ -38,7 +38,7 @@ if(!getenv('TINYBOARD_PATH')) { putenv('TINYBOARD_PATH=' . getcwd()); -require 'inc/functions.php'; +require 'inc/bootstrap.php'; $mod = Array( 'id' => -1, From 631a5b5fc705252697734c74a69e9edffbd55bec Mon Sep 17 00:00:00 2001 From: discomrade Date: Sun, 22 May 2022 20:20:50 -0200 Subject: [PATCH 66/74] Update composer.lock --- composer.lock | 51 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/composer.lock b/composer.lock index c93f2d17..60e12cb0 100644 --- a/composer.lock +++ b/composer.lock @@ -53,6 +53,10 @@ "geolocation", "maxmind" ], + "support": { + "issues": "https://github.com/maxmind/geoip-api-php/issues", + "source": "https://github.com/maxmind/geoip-api-php/tree/master" + }, "time": "2016-05-16T19:06:50+00:00" }, { @@ -101,6 +105,11 @@ "i18n", "translation" ], + "support": { + "email": "oom@oscarotero.com", + "issues": "https://github.com/oscarotero/Gettext/issues", + "source": "https://github.com/php-gettext/Gettext/tree/v1.1.5" + }, "time": "2014-10-22T15:53:45+00:00" }, { @@ -144,6 +153,10 @@ "ipv4", "ipv6" ], + "support": { + "issues": "https://github.com/lifo101/ip/issues", + "source": "https://github.com/lifo101/ip/tree/master" + }, "time": "2020-04-02T11:09:10+00:00" }, { @@ -189,25 +202,34 @@ ], "description": "Minify is a PHP5 app that helps you follow several rules for client-side performance. It combines multiple CSS or Javascript files, removes unnecessary whitespace and comments, and serves them with gzip encoding and optimal client-side cache headers", "homepage": "http://code.google.com/p/minify/", + "support": { + "email": "minify@googlegroups.com", + "issues": "http://code.google.com/p/minify/issues/list", + "source": "https://github.com/mrclay/minify/tree/2.x", + "wiki": "http://code.google.com/p/minify/w/list" + }, "time": "2017-11-03T21:04:01+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.23.0", + "version": "v1.24.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + "reference": "30885182c981ab175d4d034db0f6f469898070ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", - "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", "shasum": "" }, "require": { "php": ">=7.1" }, + "provide": { + "ext-ctype": "*" + }, "suggest": { "ext-ctype": "For best performance" }, @@ -251,6 +273,9 @@ "polyfill", "portable" ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.24.0" + }, "funding": [ { "url": "https://symfony.com/sponsor", @@ -265,20 +290,20 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2021-10-20T20:35:02+00:00" }, { "name": "twig/twig", - "version": "v1.44.4", + "version": "v1.44.6", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "4d400421528e9fa40caaffcf7824c172526dd99d" + "reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/4d400421528e9fa40caaffcf7824c172526dd99d", - "reference": "4d400421528e9fa40caaffcf7824c172526dd99d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/ae39480f010ef88adc7938503c9b02d3baf2f3b3", + "reference": "ae39480f010ef88adc7938503c9b02d3baf2f3b3", "shasum": "" }, "require": { @@ -329,6 +354,10 @@ "keywords": [ "templating" ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v1.44.6" + }, "funding": [ { "url": "https://github.com/fabpot", @@ -339,7 +368,7 @@ "type": "tidelift" } ], - "time": "2021-05-16T12:11:20+00:00" + "time": "2021-11-25T13:31:46+00:00" } ], "packages-dev": [], @@ -350,5 +379,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "1.1.0" + "plugin-api-version": "2.2.0" } From 188f961f7c57ad75e6b2c03bdb295530b0ee0930 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 22 Jun 2022 20:39:47 +0200 Subject: [PATCH 67/74] add some stuff to the api, to match vichan's api at the request of a user. fixed the delete-stray-images script --- inc/api.php | 3 +++ tools/delete-stray-images.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/inc/api.php b/inc/api.php index a60d9b41..cf507302 100644 --- a/inc/api.php +++ b/inc/api.php @@ -95,6 +95,9 @@ class Api { $this->translateFields($this->fileFields, $file, $apiPost); $apiPost['filename'] = @substr($file->name, 0, strrpos($file->name, '.')); + $dotPos = strrpos($file->file, '.'); + $apiPost['ext'] = substr($file->file, $dotPos); + $apiPost['tim'] = substr($file->file, 0, $dotPos); if (isset ($file->thumb) && $file->thumb) { $apiPost['spoiler'] = $file->thumb === 'spoiler'; } diff --git a/tools/delete-stray-images.php b/tools/delete-stray-images.php index 1c334afd..36962730 100755 --- a/tools/delete-stray-images.php +++ b/tools/delete-stray-images.php @@ -23,10 +23,10 @@ foreach ($boards as $board) { $valid_thumb = array(); while ($post = $query->fetch(PDO::FETCH_ASSOC)) { - $files = json_decode($post['files']); + $files = json_decode($post['files']); foreach ($files as $i => $f) { if ($f->file != 'deleted' && $f->file != 'spoiler' && $f->file != 'file'){ - $valid_src[] = $f->filename; + $valid_src[] = $f->file; $valid_thumb[] = $f->thumb; } } From cdf46126729016686fe0bece7298823212b432d5 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 16 Jul 2022 00:26:59 +0200 Subject: [PATCH 68/74] mute redefinition. reference: https://github.com/vichan-devel/vichan/commit/00349d031566bf09423ecde8915ec62cf0c0674d --- inc/bootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/bootstrap.php b/inc/bootstrap.php index 165d2a1d..e948c15c 100644 --- a/inc/bootstrap.php +++ b/inc/bootstrap.php @@ -1,3 +1,3 @@ Date: Sat, 16 Jul 2022 00:28:59 +0200 Subject: [PATCH 69/74] moves modifiers, as per https://github.com/vichan-devel/vichan/pull/377/files --- templates/thread.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/thread.html b/templates/thread.html index dec9952c..8e38d40c 100644 --- a/templates/thread.html +++ b/templates/thread.html @@ -13,7 +13,7 @@ {% include 'header.html' %} - {% set meta_subject %}{% if config.thread_subject_in_title and thread.subject %}{{ thread.subject|e }}{% else %}{{ thread.body_nomarkup[:256]|remove_modifiers|newline_to_full_stop|remove_markup|e }}{% endif %}{% endset %} + {% set meta_subject %}{% if config.thread_subject_in_title and thread.subject %}{{ thread.subject|e }}{% else %}{{ thread.body_nomarkup|remove_modifiers|newline_to_full_stop|remove_markup|e[:256] }}{% endif %}{% endset %} @@ -24,7 +24,7 @@ {% if thread.files.0.thumb %}{% endif %} - + {% if isnoko50 %}{% endif %} {{ board.url }} - {{ meta_subject }} From 858a501b1f652831feafd9b51c6f06c3b92e30a0 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 4 Aug 2022 09:18:31 +0200 Subject: [PATCH 70/74] add colon to character class for cites --- inc/functions.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inc/functions.php b/inc/functions.php index 1ff9768a..0c45591e 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -2086,7 +2086,7 @@ function markup(&$body, $track_cites = false, $op = false) { $tracked_cites = array(); // Cites - if (isset($board) && preg_match_all('/(^|\s)>>(\d+?)((?=[\s,.)?!])|$)/m', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { + if (isset($board) && preg_match_all('/(^|\s)>>(\d+?)((?=[\s,.:)?!])|$)/m', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycites']); } @@ -2133,7 +2133,7 @@ function markup(&$body, $track_cites = false, $op = false) { } // Cross-board linking - if (preg_match_all('/(^|\s)>>>\/(' . $config['board_regex'] . 'f?)\/(\d+)?((?=[\s,.)?!])|$)/um', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { + if (preg_match_all('/(^|\s)>>>\/(' . $config['board_regex'] . 'f?)\/(\d+)?((?=[\s,.:)?!])|$)/um', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { if (count($cites[0]) > $config['max_cites']) { error($config['error']['toomanycross']); } From 4caef0a2abc2c6415f719befe2d11c746f813c48 Mon Sep 17 00:00:00 2001 From: discomrade Date: Thu, 6 Oct 2022 07:10:10 -0100 Subject: [PATCH 71/74] Add various flags --- static/flags/anime.png | Bin 0 -> 573 bytes static/flags/booba.png | Bin 0 -> 1613 bytes static/flags/champagne_socialism.png | Bin 0 -> 776 bytes static/flags/chapo.png | Bin 0 -> 6495 bytes static/flags/cold_steel.png | Bin 0 -> 910 bytes static/flags/corn.png | Bin 0 -> 605 bytes static/flags/cpusa.png | Bin 0 -> 5169 bytes static/flags/dark_acceleration.png | Bin 0 -> 1970 bytes static/flags/doge.png | Bin 0 -> 6487 bytes static/flags/eco-anarchism.png | Bin 0 -> 5505 bytes static/flags/eurasian.png | Bin 0 -> 14934 bytes static/flags/femboy.png | Bin 0 -> 5343 bytes static/flags/glowie.png | Bin 0 -> 5749 bytes static/flags/guillotine.png | Bin 0 -> 238 bytes static/flags/half-life_3.png | Bin 0 -> 596 bytes static/flags/illegalism.png | Bin 0 -> 1802 bytes static/flags/iron_cross.png | Bin 0 -> 433 bytes static/flags/libya.png | Bin 0 -> 5324 bytes static/flags/mao.png | Bin 0 -> 7269 bytes static/flags/maupin.png | Bin 0 -> 6465 bytes static/flags/minecraft.png | Bin 0 -> 512 bytes static/flags/nuclear.png | Bin 0 -> 9710 bytes static/flags/o_group.png | Bin 0 -> 594 bytes static/flags/poljak.png | Bin 0 -> 5935 bytes static/flags/saint_george_ribbon.png | Bin 0 -> 6235 bytes static/flags/scared_porky.png | Bin 0 -> 1052 bytes static/flags/spectacle.png | Bin 0 -> 206 bytes static/flags/stirner.png | Bin 0 -> 793 bytes static/flags/ultima_viii.png | Bin 0 -> 755 bytes static/flags/ushanka.png | Bin 0 -> 11991 bytes static/flags/weed.png | Bin 0 -> 6511 bytes static/flags/youtube.png | Bin 0 -> 326 bytes 32 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/flags/anime.png create mode 100644 static/flags/booba.png create mode 100644 static/flags/champagne_socialism.png create mode 100644 static/flags/chapo.png create mode 100644 static/flags/cold_steel.png create mode 100644 static/flags/corn.png create mode 100644 static/flags/cpusa.png create mode 100644 static/flags/dark_acceleration.png create mode 100644 static/flags/doge.png create mode 100644 static/flags/eco-anarchism.png create mode 100644 static/flags/eurasian.png create mode 100644 static/flags/femboy.png create mode 100644 static/flags/glowie.png create mode 100644 static/flags/guillotine.png create mode 100644 static/flags/half-life_3.png create mode 100644 static/flags/illegalism.png create mode 100644 static/flags/iron_cross.png create mode 100644 static/flags/libya.png create mode 100644 static/flags/mao.png create mode 100644 static/flags/maupin.png create mode 100644 static/flags/minecraft.png create mode 100644 static/flags/nuclear.png create mode 100644 static/flags/o_group.png create mode 100644 static/flags/poljak.png create mode 100644 static/flags/saint_george_ribbon.png create mode 100644 static/flags/scared_porky.png create mode 100644 static/flags/spectacle.png create mode 100644 static/flags/stirner.png create mode 100644 static/flags/ultima_viii.png create mode 100644 static/flags/ushanka.png create mode 100644 static/flags/weed.png create mode 100644 static/flags/youtube.png diff --git a/static/flags/anime.png b/static/flags/anime.png new file mode 100644 index 0000000000000000000000000000000000000000..8c1a18f386eacb598f9759756b7234989b3fe777 GIT binary patch literal 573 zcmV-D0>b@?P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0j^0zK~yMHb!3613$d;d7l5hr|gfafiXCQN08thu3;H0z)R3R)oOqM%)l*BJ+wh5SiuanfSwFj z-~Acw<2;c%FyaJ}VnQOxP2E?iH-EDQi1&4c)ggB#I&r2x>dO3nyzr^L#HJr;Dm({Q0yU ziSXq-=J0m^6qJFS@&}=00000 LNkvXXu0mjfS@Y_9 literal 0 HcmV?d00001 diff --git a/static/flags/booba.png b/static/flags/booba.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5fb1b51b8e78f2d30f4ced3e9c526614b1f8ce GIT binary patch literal 1613 zcmV-T2D15yP)Px#1ZP1_K>z@;j|==^1pojA_en%SR7guDm0O5iXBmc{f1UPu4w*@3nmv=w3^`0< znb-*=4P&(;wFilypruq4qzH-@ucX*og6)krwG_OtLI{YtQ;S&4MQp7^!IrjZqmXox zPCDnqo|!%Syw}lp?b-0LHf#Og|9$`az3=;*yLUfM=70GT&%d?Iig9`2sad{zeg?}p z#8#Q*4?pCiH?A`K=qV1&OyhV3EGMJy2EqnJ4U#w{P7<(O(6=bIFy+%kJM&mkn}5D{ zi=VvqHW|-hv(d#UH=oTw9AO1p>+D8ZcDx+N#s>M$*JrR@LsBTy^-A1*|0YLImnlu& z1I8k;(oimm3b*yAt!I}c(VO&p`m|j=^}l#n>kM-bOmY6)1VNPMB&r+jhyGhD@4nAp zKi#3$?()^y!&r1k0vqS88;WY@>MWUXcL_{_M0Snmlif@(X=_ex11dL zcdk+T+uyOxp!#P2-_C)<=gZ zpBlkr9i3i@Q9$IkRk%eQ`uMGS4~?{d2B6|miVNiWXnlT$+T0w8pCQQ|q}VsaE6+Yc z&eJw=tO$Ffv)Ub>oleNNzBtL5v(s4KeVC0Z#Xr7DetDI?@k6-zKGoOhA|(Y~g8B}A zeUC6yaXZ^P^?qn$t-~#1b-LJFJA~PS4pb&`ikvt$#Y@jTECiw+0-?rWf9dS(g`Kv~ z>o0x-+aAEXz6M#B&d3Ns#vwbL$9SG1E0WnFkWEml(cG?*8_0>2nclm^)=90bkW@}B zA@}yb$jmR2TV5uA<0jEP_Y$}<$0tUp*BgBB$-0o!elPs!2g#F<%`iDWj)@0|4wgx3 zg1Fu$*j^D;2~z z^*XkShW%-=$X*&}9CJbnPx`18u7#!R8hA5V4>3i6c$rQ$cV-g)=DJXVQV^Y{!V;LeTrjhk%$&flhh2Q__8n%@kyWq@k zaBBJp{<+fxlM~d3hp`6KgvcXW(G|fgnM?{LU2$M(mE2GXw@~cKE^UDIO`M=aP$&?W zavEQN(`u{X09(X#q%3!12XAQ&XKR=0fgD%H`{+o!XYhp_v3?rj@F| z_hnr2|5_88b@mqj%f)vW#igOC3!B?J^w&B(*x18fuV~(hjAMxQ#C^0+9wCw?`vU`# zn}s_#h%M-yVzEa+oV-v{1G^paHy6mPRdD65y*oiqODMR01TCpT<1`}bmTElro6Afb zo5YNtcqGXgNi2wX=81>-{`Vf$Rjbb1Qb9@|$;YHutYnyI{@qqXO$_789W$P*+qXdW z-#4(9t03b+24+&j*W5KV{q_l%-kxD>bi=y5c=Z~uzjvL>mtN-oZfOJi#M!$E00000 LNkvXXu0mjf#&9Ah literal 0 HcmV?d00001 diff --git a/static/flags/champagne_socialism.png b/static/flags/champagne_socialism.png new file mode 100644 index 0000000000000000000000000000000000000000..b7e5ff43b88a857e39feca3c976fa44b7ee7fcf8 GIT binary patch literal 776 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 literal 0 HcmV?d00001 diff --git a/static/flags/cold_steel.png b/static/flags/cold_steel.png new file mode 100644 index 0000000000000000000000000000000000000000..d2999366ab86a13c92eddb555875ceae823400d5 GIT binary patch literal 910 zcmV;919AL`P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0{=-wK~y+Tt&>Yk6Hyd~E10lQsSRRc2&fc9 zFqEMsV1ZI7P>Mtl1K~AD3v}8-Esuggp+Gg|83g3j^00v-YVZLH#uyWVQE@>`bY!vpYN;Y{u#Jta*cLWyu5kLSbnoD0q*!x_Hl zbWf`NcSX#VPo$WnxaM%dnN)?UihE=|-yKQ^T-h$zWp>z-Y&(_&%j;^Qx?glm6w6h| zurE;(Rbrh{&cLa3Vmxyk1M&fkXN<$0?e;L4F$s#G7WsVs(Y^Id_#}rU7itL24IQDo z<;-+qK6@Tz(Pi*I#0Omje?NZ=rww~a-6}WQ&bMw0cmn=j;XzuqJ(e+s+gWp%qp{0- z5O5>_Znqnoo10K56vz$FWkn0w3tnQA*tAMJ4tRvjMJNykSHx&OHY7B_nqmbRO+q4( z;PK)etgWuVYPCXsGL;p$R4!Pg?d+Wy4=M&x8d+@e5;FMmdI z);2uU*T8HxgN!0QT`^s13GKHup_D31Pkg3|lsk62^a$xVtkGzGUR0@YLJ$O-&4#H7 z2gVE?aE`5@j~w*~M-`*6Bw9elYM+-X#S*&Kb51=%2C-N?>h7|^R$hmRk!8Gk@dawK z9&=OcaJ1ZGH-cGXW4;k)r5UqXv(UxpX8v_}3F$aqR8aEk(b5*SHojuXwZY1kr`FJ& zUW-;`3#c**TCEmUSyfo1Uofql27PYRIfV?e=(LUpi*H%sljZlA&9B7EU?Fa*a@fr= zU9AH}QD`n|Mqg?#y9Av{oge6Cyw`9SI{a$mjh`zrwJ;X9Vp3LujgT-H^?EcmHbPyl zhT)O{mgM$78j*UnLs9eQnnH*Ch=M{+Awyn7Uei$85T@u~uRE^`>t_j6re8*FWew_6 z>(MXohe2#uW#$eyMG+NQaq~%`vJPgGR7Hq k>f-Bugz>`s_Sb^<7heVTsWqtnuK)l507*qoM6N<$f*L=Hk^lez literal 0 HcmV?d00001 diff --git a/static/flags/corn.png b/static/flags/corn.png new file mode 100644 index 0000000000000000000000000000000000000000..56c0cb038b1fafddb799c54bbd9202cd98d99988 GIT binary patch literal 605 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 literal 0 HcmV?d00001 diff --git a/static/flags/dark_acceleration.png b/static/flags/dark_acceleration.png new file mode 100644 index 0000000000000000000000000000000000000000..a028ef02e608fdc2f5dedf565214f8097cdeab94 GIT binary patch literal 1970 zcmV;j2Tk~iP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+O1Yuvco70{O1&N1dsrUR*30^@n@_3@hu1eehn(#|9f9iotq*!nhl4$9?_KhwT_P2E- zAL8=kjZ42c66525aW_BiW#GCnZba}pK&a_$JL}t8;nwQhU9?^p^{b)=+2%+ifk`OG zG0n?G@^xaEgU+d#5sA+BV-hnl|U$x zwVi-5C<3$u0gy4mBa1*$kONvsqJVJ@ihu-*=s^)M^tELUnGp*PJao78CK1A+ zM-puUMiI+eC-p;?rG}zIXPtB2kz?h8iypo8&U;V3H@QeimK=E^VhR))*|KBL#LR(X zfPm5iUGRYdhY(@}6=k6)xuV2J@gzu?Y;wsbN}NK9S;{Bd?6S|4Ifonz6fDvviZ4{S zgc7S!RXRnr)m2}qat$>$skMg9HrITk#x1nCRa>gQUH?Eevs8njRF9*rns^n_k;3$L z;<{#{7+52UQ&&I=8oFkhjkVB~>ze5Rawr@KNY}Md#dO6)LR$^EX0~>xa=+3|IsTPy z@J%_@rTagWQzG5FZXZ-D{XLh5V)GPsPBqHuYeEjNiXh#pxhi&qlo>1QZn8{lV5Yke zR?49+|1nz>!h#)iURukb; zxJM{obF25{-<}spwQWnC;}@LuLlqpI!NG(~nCWZ+f~XyK+7_SV^mJa%kUUgZAIFgI zeFx|kbRSV8Cp|8Q=3!`OUend*`KuBF=Q1ZqKjz2c%(IR3@RnA`wD6maet@NZ*wzVa z7ukjf7ce76ou~D`fl@zn{d-XA8uTwg>7$PBN`3?NVLc)HmvLY4433U>p`&+%# zR6o2lZ+%|9`a*l+J?Nibwd&y|{q}Bu#JhX;*+%SoWqIAM-RIbtyw!f_n`&eG0__2! ze)|*gi21owo_|H&$o?Iu6P!EWzbfj--u3PIQc`Ln@mHRUz8|M1{~?3$@Heu0MV^6; zJ%0cI0fT8nLr_UWLm+T+Z)Rz1WdHzpoPCi!NW(xJ#a~mUQYsEc5OK&*oh*ooIBFG& zP$AR`tvZ-o`UOoIk`xz5!L{Jv$70pN#aUMeS3wZ`0C9A3Qgo3L|Cbb6#CmYtk9YST zckck9US_)8H4f;8W2F*tDU)55LazuzzyKtO3bV~QSx%zk__{}cuXiz?)%o0?qgTt> z3TCPb{*cq7k1Hk6Cm<;zzElKEH7;cr5Tt(MqT0iA7?m(8g*T zv!bOFPZ38o-JpCSYT&7<@7nOYx*2O(CBL-p}ZpvOxbW5MJ|p zYwqLp0Z3C<$s6F{5Ev~`_IihR_q6x+@0n(QKSQ2!l&CTOF#rGnFi=cXMF0T+5E2g; z85c zL;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru<_ZE90tPRRnqU9`0Edmq^SR2kU{AG2Sp+N|B4_6lL87uQ2zt}2mVij3^MQj z|62e59nhR}?;h~Idjr&d=G?n?Z_WT2(tFOFIlVy;0FPoj)uq^CLI3~&07*qoM6N<$ Ef+bX(E&u=k literal 0 HcmV?d00001 diff --git a/static/flags/doge.png b/static/flags/doge.png new file mode 100644 index 0000000000000000000000000000000000000000..eebcb6906fe790a9fe4fa66a3b024c645435f48f GIT binary patch literal 6487 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 literal 0 HcmV?d00001 diff --git a/static/flags/eco-anarchism.png b/static/flags/eco-anarchism.png new file mode 100644 index 0000000000000000000000000000000000000000..e6d7e2562065c8a7072039fd1e0bc384cdd797dc GIT binary patch literal 5505 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 literal 0 HcmV?d00001 diff --git a/static/flags/eurasian.png b/static/flags/eurasian.png new file mode 100644 index 0000000000000000000000000000000000000000..26e89049d297f9e3f3abb0e0e14168f40268f7e8 GIT binary patch literal 14934 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 HJoNtn$UlU0 literal 0 HcmV?d00001 diff --git a/static/flags/femboy.png b/static/flags/femboy.png new file mode 100644 index 0000000000000000000000000000000000000000..fe2c17098266457d109b00ca619dded270a8c3b3 GIT binary patch literal 5343 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 QLAXTuc=)?lxUSmpUxF$zZvX%Q literal 0 HcmV?d00001 diff --git a/static/flags/glowie.png b/static/flags/glowie.png new file mode 100644 index 0000000000000000000000000000000000000000..de9576fe7782c180874d0df7b7f7def9c639abc1 GIT binary patch literal 5749 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 b)>rujFsxKhKV{Ro00000NkvXXu0mjfER?Ku literal 0 HcmV?d00001 diff --git a/static/flags/libya.png b/static/flags/libya.png new file mode 100644 index 0000000000000000000000000000000000000000..dd77558801a4c451f9c1f3d5da650e60d63a710e GIT binary patch literal 5324 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 literal 0 HcmV?d00001 diff --git a/static/flags/mao.png b/static/flags/mao.png new file mode 100644 index 0000000000000000000000000000000000000000..a46db39c91735fbe88fe75be412848a4a51336f0 GIT binary patch literal 7269 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 literal 0 HcmV?d00001 diff --git a/static/flags/maupin.png b/static/flags/maupin.png new file mode 100644 index 0000000000000000000000000000000000000000..0e9d89479719e9400ca960da8523a5ce6fa4131c GIT binary patch literal 6465 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 ND+@dG3e$s;{{hLHW4r(W literal 0 HcmV?d00001 diff --git a/static/flags/minecraft.png b/static/flags/minecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..fbb578f9caa7caf27cb59d68ef1f2ea6ccbd1111 GIT binary patch literal 512 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 G!~O?C<+gqR literal 0 HcmV?d00001 diff --git a/static/flags/o_group.png b/static/flags/o_group.png new file mode 100644 index 0000000000000000000000000000000000000000..86418226c1d565ff502abe64ef1cd95310981231 GIT binary patch literal 594 zcmV-Y0I&CqD{e zKyvb&+6u;0klb5^wNmvU7)U^kU)8*6vw4&CuqK-{EkgYrXXf`X!^~*E7xEwMWh=lg zq{qyv)`Vzjd(Gz!MjrF+< z)oiXO-UHZs;~GXHj?-u$7ni8NS_L3@>Lj753HHoRqn|j&_nWu-0fQILVkF|I@+T^n zuhXo2>lD?VzQCV;L?oTUNW`hHzC+Hto%q@_56vWT8jU`4Tg@+Dsa%=GX()!TCeeiO z0J=GbFKkfD6}B~ZAfGF2-g7`1~10vJctF7uZ~}0F7YGBs4jWCIs@ybL8V^ z9dOSj{)yIY`IU35Abw-Y*98~q67hIn`=&y*2=4L(j&~c-nK;ihC5y|??sr#;_ zHrrc z{-eCl;w@l%Z7b&~L+?Hm8>8E@i?_8$mO1{Cl`c9ESS*@qidE?=} zMtry0s)u*mUKV@lEL$_r=ZWgEuB(x6mjAZqq504(3uXRkdX0Le_fmuFraFb&VziWZ zKughC<%JX#(`o9FOSNaom$3mQ;#4QbYIn`M8FRr9ZEN}8Z3u38m#q9((k8* z$d8)I@4SFr}P3>^Io--maQ$jVDX@DZ0habk8LvW zkH^f7JO~Hs9D6`}n5V&%q;CM*_bSsO9_GEDHve~yQ2KQ0a)zt!!Y5Dp=Q&=6({w44{UBXIc)mScsDe4Zomq^gx85r(?iU*)m%#G zshv5$Im$4`Y9fH!`fAEy!3UK{JhE zudAx_0*Iw>f4gtzED!K>t42n02`ym9tw#Ok<~oMIRDNc7Pp4 zI`Y#^G53%50O*lp$IY;6FbEZz z1eTjbC|&xH*+a^meenb6-@7FKFjx7E`~&mi^EPix=dRd>XBA`Ea?SN`2ZB=nfD?>9 zs%Q>596P#Sb$;=SH$U&W-PFEa=yF7O!1`?3vff2gD)V*EZW}C44i~&+j9!`E!0`@d z6+X5w9%wqkh;3gnW!$bV#r*?+mEJygqr!Qi5h%4z^vNOZaQ~d2_v((|H8N{Y7G)R2 z0D#g)o{NhQ&Bf*O&WP-Xc?p^J9t}&48pHi-{Vb;k&WvjI$zQCi7j@H8x4`*`-pXk3 z)Z3}KBvT9A_TL#EX2mGPsaaR$91`B%qmKite~1onH_ zwNC3W>q77As?loyc##>ni_tCZj`{`X@n>^%;}e^9)!nN5W|KRP#&&~M!4XhVM#%M> zTZ*@slpOXyyYp3W@0rGsML{8N_WhY!kazZYTXe38#~N+VooHt#y#>3NCd*5`(^GX{ zURpA`IrN+>E_L++P_p=dvexkzsJ~Jkb*_AWSp#pOi>eDZ>VtIE2b42%pZsjR#QVvV zVMmpqxYqEaDpvas-C4P^NB!9&HC)B2+~cU#gMiD5P5hRMo??rhH|IajPVm<^JgJ%- z878`tkmmsKo?FJM7#S%;sx4td!-HLabdB403=E+d8j`(zi&AzVC)gYwa#97;y{M2# zfMc>nEEp#jh>?>F0PGy)VkQ&`%g`*C%M;pThEAWupm}V2OprAlq>EkP2%blr1on^f z4uIk!AzL=a(LvKrPDKC&u#Ab83;04QRc?=&z@;K>MK>OUo-mO`+GB$0K4=$_1V)o^ zBpir!lk?UQF%Ft&I|-XZ^>bbJ2?BYu$3)0vVk#aV6BC1rvBHTYTs*79W0cYd=0^dzW9ryCH#qU z*bpA(!ve%qibN%R6VjbV_xa+Xpn%I0h$p-dvcIvE@i>2z^-XSyk%@A?P6ToPg8Pm2 z=h`QX5i2^K>MDYw73tAj?Jv8fYHBGHOSBol0~Aeq9%l9&)1%d#OrSP+CD z8w$iGusEErplCv=j46a*1r!2~;~_YZHHX3mZEUbGWNm{bfz}kPEdiup2^3or3{gNf z$BOk8#0m)yQ6-cAbyf-}HUdQ?Lj)3mY>lN@K`boEnhar?Ajt|#Ah2wRNF0blw4Q)s zL)2v=iGYbrCr`lS!g#TeJ29Xjoa*F5v&Rr|;NLwye5QHnF^gE028oCEmRi? z%#?{F0U{CK9;1LjD?BIUjkcSd6c3&hv4~YD{*&hY;i$>C$tA$&O$?#Y6SAc;p~)ap z<~o=?5eV^{9D*X4LN1J~?@xmI+|T=m$zqeqWVQ{7jAgM16fB8EW+9Vh%f>R9Yzmoa z#kK(nlZAglmx?&D7^Vbv;v$tI)gS_zs0M95L8ZmFxx_@k3Z6h@Z4*F5Q~@BFYHdwb z2#i1lK@9#=!Fa{0{#>yg{(m^Jn=trl8$kRf`;hGg*{$$jwyRH^DQNr`KcD8}UyOi2 z{|NG3{QjWp2VLLAz;_w{P}dK-zKenHGX9~i{~KMJe_wcDA@VOM2D#4E==KwltB@MY z)7=#q1yljmk;6Hgksb}PM~D;vrs^mjB_KD?5a~q8XmmH!Q%yCLjdtGi6eR#q9-z58 z1(;tIWZ8SnRRU7O2fgW%Fw*rc+B!NCC#~%1P8liJF5gg3PB9O)yg~O2ty`B_=W(L@ zppVhY=9>jh17@!61^Qk$*x+GPHJ$hjI?gest5%mSGlIN8(wA|^zy(CbKn5){-V~`dowdLPd$FjgwQj= zEeDV2Oet_L^rh$Y<}|W=-F*4%>U({Fg9=brR~N0@9mzyqYkWF(#EMSsI0u| z=-?n+kl+x$(9Ji})6-MsvDh#fy}^_gyjWi*lN|`KEbu#u&R#x$j~8q0+UH58G)Ieb zkN&EtuOFL#DT?CY(A3nV#wX9!H!#qirdCy5o#Ki~YHjr_D=Rw?SQ_e)^){*I9-mNo z=Oa5Y@oZ2Id~!8TZuip^WhJC>jg;YIzOkx`;I(4Ki$>O~mxF_Y29|R&#>Le9%GsOV zpFDHMOCuR@^A#s1PS1fez09sZdNiZBL*vAQ^34s8X8}IIwR`vW+={M;Npma;ud6c{ zQR~*J0fuwtID>{$fF8-I!=|(-01YgixzV}6$7j4noRFZkuP;h2-x629J+M?2FyGzU za{m1JktLx1*0GkpH;+hk7u;?YddF~F{j>glr3R2WV4o3bo$jbwx%^ zI9T$$kX5zi$`$(PSR!eT)~{DM?COxR^74M8O9?G(A`#dLh@+!bH#hjMJKed}?&{o- zoW_R_jh4B)JI$Pe@ZbGvRPRz0e#iFh6+`D&g>TJX-rF}YFaT|Ca1w|_Pu{-OE$~tA z?CiWXHa1oqA0Hnc6>er`*8J|>JMPhdlECu7cal?O^Nfrx1_lLj%@!`y`b(%aa(?60 tzPTfEJFDEox1PKj{pexp_kR5d>hTm-*6jJ~E0LuD(A>OTE1cIP{}&qvIJp1- literal 0 HcmV?d00001 diff --git a/static/flags/saint_george_ribbon.png b/static/flags/saint_george_ribbon.png new file mode 100644 index 0000000000000000000000000000000000000000..1db682f27819d8f39efb5f9dc3fb70098557a23b GIT binary patch literal 6235 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 literal 0 HcmV?d00001 diff --git a/static/flags/scared_porky.png b/static/flags/scared_porky.png new file mode 100644 index 0000000000000000000000000000000000000000..648e256d238c59a4f0e68f7d2512dc2e01965f1d GIT binary patch literal 1052 zcmV+%1mpXOP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y1C2>UK~y+TZP9B?lUEoA@UtZtWi3w3T6zK7 zDI0Ee0SY!KP%83*Yk6raw^pD9q%vW)(hInY-3B_yE+&h^EgNcL%p6&C5}382K%gL( zY(}|>nYfs+?Zb%7E#wVe{=Ow4Ve|d)KRM?)d49=x4go-HHf309{I-KOoiaRhUY(x| zDak%775)D@SC*Hg*jJk+8)6_A$!=>@iOSrJ_&j*M&v#MDx~tkG#p;Is0!{18r{#-7 z<$L;8*Fzy@O~R%vFGVj&BcdUQkV3d|(~{!lEhj^l7j~AbflY;J;9KOQY%pH!*C*|cQ1 z!bNbgkeerhGdv0|z63!NjbF<2i+8=2wVarbkmJpSFmrLTdpG1X9lv#CnB)`{Wd ziP5lLz=9GMlcFtAiSgPZ^iUclCpJQe?m1)ph@=18A$H(UzZuAIoWUR2gt#zX4ZkigBW*0C)O6#HDZSj|d^p zaUv@@_qokCKib61k2NuKK`-<3MK?3!f1ml|S`*WfPceb7YMJ@#Elgj#n`uAkanMpkT76i(`m|f3ien!$*4ohnpdc8f-@M(k(bs zn-11HvlVLyiy9a$T9N$Yzx=vBPOoGMHl`a#40xCsRSb7DUSaA{V0xAt6PL!qWFRkQ wW3h)Ph&_yhso-b^LnJSU!0NmWOl)inqLvybr30RP09wc3>FVdQ&MBb@02sSB4FCWD literal 0 HcmV?d00001 diff --git a/static/flags/stirner.png b/static/flags/stirner.png new file mode 100644 index 0000000000000000000000000000000000000000..15402467c08f396b4a9ee097064f7a419c2471b4 GIT binary patch literal 793 zcmV+!1LpjRP)`f00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;(#7eog=Y0*XmQK~y+Tb(1|vvQZSrpVB_uw8;jS5D5hr zp`ZjY`j|``Y>+}o`&g7v6T}E>h!8^)LzITVhzvsN;aF#y|JwPn8P00000NkvXXu0mjf7U5(K literal 0 HcmV?d00001 diff --git a/static/flags/ultima_viii.png b/static/flags/ultima_viii.png new file mode 100644 index 0000000000000000000000000000000000000000..b63e46f8d74944fc790b8dccbf6d3d91dc16821a GIT binary patch literal 755 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 Z?fv7^C`va-;N2ntP*c)YtdX|~|34sU=Bxk! literal 0 HcmV?d00001 diff --git a/static/flags/weed.png b/static/flags/weed.png new file mode 100644 index 0000000000000000000000000000000000000000..72eaac836a79a7d0ab4e0e9d1303c0ca632e53e7 GIT binary patch literal 6511 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 Y4cN^L*kt50VE_OC07*qoM6N<$f;@qP-T(jq literal 0 HcmV?d00001 From e19826f35519e091f7947c42c74a3e6728b08666 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 7 Oct 2022 21:22:31 -0100 Subject: [PATCH 72/74] Remove fight float on select boxes I can't even find how this got it, but it's apparently been there for six years on lainchan --- stylesheets/style.css | 3 --- 1 file changed, 3 deletions(-) diff --git a/stylesheets/style.css b/stylesheets/style.css index 60c826c7..f141b832 100644 --- a/stylesheets/style.css +++ b/stylesheets/style.css @@ -37,9 +37,6 @@ html, body { .post-image{ max-width: 94%!important; } -select{ - float:right; -} div.pages{ From 0c205ab3222498fa2ee3d640b767950ae84b174f Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 7 Oct 2022 21:32:40 -0100 Subject: [PATCH 73/74] Describe sage option in email select 'sage' is too esoteric for noobs. Ideally we should make this a checkbox because always noko but whatever --- templates/post_form.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/post_form.html b/templates/post_form.html index 02c6087f..5f761c17 100644 --- a/templates/post_form.html +++ b/templates/post_form.html @@ -40,7 +40,7 @@ {% if config.field_email_selectbox %} {% else %} From 98b757e948f4694bbb0c8f37ef131dba5e0bdaa9 Mon Sep 17 00:00:00 2001 From: discomrade Date: Fri, 7 Oct 2022 21:35:18 -0100 Subject: [PATCH 74/74] Rename email field to options. (hack) Didn't worry about doing it properly with translations because this is a local fork --- templates/post_form.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/post_form.html b/templates/post_form.html index 5f761c17..ef51094e 100644 --- a/templates/post_form.html +++ b/templates/post_form.html @@ -33,7 +33,7 @@ {% endif %} {% if not config.field_disable_email or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %} - {% trans %}Email{% endtrans %} + {% trans %}Options{% endtrans %} {{ antibot.html() }}