diff --git a/backend.php b/backend.php
index c316bcc44164f87534d968416face1a408412b65..44d4284c36cc2cb697d010eb250261db4a68392a 100644
--- a/backend.php
+++ b/backend.php
@@ -112,7 +112,7 @@
 		$op = "pluginhandler";
 	} */
 
-	$op = str_replace("-", "_", $op);
+	// $op = str_replace(, "_", $op);
 
 	$override = PluginHost::getInstance()->lookup_handler($op, $method);
 
diff --git a/classes/api.php b/classes/API.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/api.php
rename to classes/API.php
diff --git a/classes/article.php b/classes/Article.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/article.php
rename to classes/Article.php
diff --git a/classes/auth/base.php b/classes/Auth_Base.php
similarity index 100%
rename from classes/auth/base.php
rename to classes/Auth_Base.php
diff --git a/classes/cache/adapter.php b/classes/Cache_Adapter.php
similarity index 100%
rename from classes/cache/adapter.php
rename to classes/Cache_Adapter.php
diff --git a/classes/cache/local.php b/classes/Cache_Local.php
similarity index 100%
rename from classes/cache/local.php
rename to classes/Cache_Local.php
diff --git a/classes/config.php b/classes/Config.php
similarity index 100%
rename from classes/config.php
rename to classes/Config.php
diff --git a/classes/counters.php b/classes/Counters.php
similarity index 100%
rename from classes/counters.php
rename to classes/Counters.php
diff --git a/classes/db.php b/classes/Db.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/db.php
rename to classes/Db.php
diff --git a/classes/db/migrations.php b/classes/Db_Migrations.php
similarity index 100%
rename from classes/db/migrations.php
rename to classes/Db_Migrations.php
diff --git a/classes/db/prefs.php b/classes/Db_Prefs.php
similarity index 100%
rename from classes/db/prefs.php
rename to classes/Db_Prefs.php
diff --git a/classes/debug.php b/classes/Debug.php
similarity index 100%
rename from classes/debug.php
rename to classes/Debug.php
diff --git a/classes/digest.php b/classes/Digest.php
similarity index 100%
rename from classes/digest.php
rename to classes/Digest.php
diff --git a/classes/diskcache.php b/classes/DiskCache.php
similarity index 100%
rename from classes/diskcache.php
rename to classes/DiskCache.php
diff --git a/classes/errors.php b/classes/Errors.php
similarity index 100%
rename from classes/errors.php
rename to classes/Errors.php
diff --git a/classes/feedenclosure.php b/classes/FeedEnclosure.php
similarity index 100%
rename from classes/feedenclosure.php
rename to classes/FeedEnclosure.php
diff --git a/classes/feeditem.php b/classes/FeedItem.php
similarity index 100%
rename from classes/feeditem.php
rename to classes/FeedItem.php
diff --git a/classes/feeditem/atom.php b/classes/FeedItem_Atom.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/feeditem/atom.php
rename to classes/FeedItem_Atom.php
diff --git a/classes/feeditem/common.php b/classes/FeedItem_Common.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/feeditem/common.php
rename to classes/FeedItem_Common.php
diff --git a/classes/feeditem/rss.php b/classes/FeedItem_RSS.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/feeditem/rss.php
rename to classes/FeedItem_RSS.php
diff --git a/classes/feedparser.php b/classes/FeedParser.php
similarity index 100%
rename from classes/feedparser.php
rename to classes/FeedParser.php
diff --git a/classes/feeds.php b/classes/Feeds.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/feeds.php
rename to classes/Feeds.php
diff --git a/classes/handler.php b/classes/Handler.php
similarity index 100%
rename from classes/handler.php
rename to classes/Handler.php
diff --git a/classes/handler/administrative.php b/classes/Handler_Administrative.php
similarity index 100%
rename from classes/handler/administrative.php
rename to classes/Handler_Administrative.php
diff --git a/classes/handler/protected.php b/classes/Handler_Protected.php
similarity index 100%
rename from classes/handler/protected.php
rename to classes/Handler_Protected.php
diff --git a/classes/handler/public.php b/classes/Handler_Public.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/handler/public.php
rename to classes/Handler_Public.php
diff --git a/classes/iauthmodule.php b/classes/IAuthModule.php
similarity index 100%
rename from classes/iauthmodule.php
rename to classes/IAuthModule.php
diff --git a/classes/icatchall.php b/classes/ICatchall.php
similarity index 100%
rename from classes/icatchall.php
rename to classes/ICatchall.php
diff --git a/classes/ihandler.php b/classes/IHandler.php
similarity index 100%
rename from classes/ihandler.php
rename to classes/IHandler.php
diff --git a/classes/ivirtualfeed.php b/classes/IVirtualFeed.php
similarity index 100%
rename from classes/ivirtualfeed.php
rename to classes/IVirtualFeed.php
diff --git a/classes/labels.php b/classes/Labels.php
similarity index 100%
rename from classes/labels.php
rename to classes/Labels.php
diff --git a/classes/logger.php b/classes/Logger.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/logger.php
rename to classes/Logger.php
diff --git a/classes/logger/adapter.php b/classes/Logger_Adapter.php
similarity index 100%
rename from classes/logger/adapter.php
rename to classes/Logger_Adapter.php
diff --git a/classes/logger/sql.php b/classes/Logger_SQL.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/logger/sql.php
rename to classes/Logger_SQL.php
diff --git a/classes/logger/stdout.php b/classes/Logger_Stdout.php
similarity index 100%
rename from classes/logger/stdout.php
rename to classes/Logger_Stdout.php
diff --git a/classes/logger/syslog.php b/classes/Logger_Syslog.php
similarity index 100%
rename from classes/logger/syslog.php
rename to classes/Logger_Syslog.php
diff --git a/classes/mailer.php b/classes/Mailer.php
similarity index 100%
rename from classes/mailer.php
rename to classes/Mailer.php
diff --git a/classes/opml.php b/classes/OPML.php
similarity index 100%
rename from classes/opml.php
rename to classes/OPML.php
diff --git a/classes/plugin.php b/classes/Plugin.php
similarity index 100%
rename from classes/plugin.php
rename to classes/Plugin.php
diff --git a/classes/pluginhandler.php b/classes/PluginHandler.php
similarity index 100%
rename from classes/pluginhandler.php
rename to classes/PluginHandler.php
diff --git a/classes/pluginhost.php b/classes/PluginHost.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/pluginhost.php
rename to classes/PluginHost.php
diff --git a/classes/pref/feeds.php b/classes/Pref_Feeds.php
old mode 100755
new mode 100644
similarity index 99%
rename from classes/pref/feeds.php
rename to classes/Pref_Feeds.php
index fa56f6d1a0dc4447cec2a64900a7abfe0797f16c..60da4f18ccf3080fb3d8a417a751f643d5c229e1
--- a/classes/pref/feeds.php
+++ b/classes/Pref_Feeds.php
@@ -620,7 +620,7 @@ class Pref_Feeds extends Handler_Protected {
 		?>
 
 		<?= \Controls\hidden_tag("ids", $feed_ids) ?>
-		<?= \Controls\hidden_tag("op", "pref-feeds") ?>
+		<?= \Controls\hidden_tag("op", "Pref_Feeds") ?>
 		<?= \Controls\hidden_tag("method", "batchEditSave") ?>
 
 		<div dojoType="dijit.layout.TabContainer" style="height : 450px">
@@ -959,7 +959,7 @@ class Pref_Feeds extends Handler_Protected {
 			</div>
 			<div style="padding : 0px" dojoType="dijit.layout.ContentPane" region="center">
 				<div dojoType="fox.PrefFeedStore" jsId="feedStore"
-					url="backend.php?op=pref-feeds&method=getfeedtree">
+					url="backend.php?op=Pref_Feeds&method=getfeedtree">
 				</div>
 
 				<div dojoType="lib.CheckBoxStoreModel" jsId="feedModel" store="feedStore"
@@ -988,7 +988,7 @@ class Pref_Feeds extends Handler_Protected {
 			<label class='dijitButton'><?= __("Choose file...") ?>
 				<input style='display : none' id='opml_file' name='opml_file' type='file'>
 			</label>
-			<input type='hidden' name='op' value='pref-feeds'>
+			<input type='hidden' name='op' value='Pref_Feeds'>
 			<input type='hidden' name='csrf_token' value="<?= $_SESSION['csrf_token'] ?>">
 			<input type='hidden' name='method' value='importOpml'>
 			<button dojoType='dijit.form.Button' class='alt-primary' onclick="return Helpers.OPML.import()" type="submit">
diff --git a/classes/pref/filters.php b/classes/Pref_Filters.php
old mode 100755
new mode 100644
similarity index 99%
rename from classes/pref/filters.php
rename to classes/Pref_Filters.php
index 2656c037030be6c237edd464010ed3ec5277a611..1656e92b8d76a4b5bf258ea2447f79eb99a8f3ff
--- a/classes/pref/filters.php
+++ b/classes/Pref_Filters.php
@@ -696,7 +696,7 @@ class Pref_Filters extends Handler_Protected {
 			</div>
 			<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='center'>
 				<div dojoType="fox.PrefFilterStore" jsId="filterStore"
-					url="backend.php?op=pref-filters&method=getfiltertree">
+					url="backend.php?op=Pref_Filters&method=getfiltertree">
 				</div>
 				<div dojoType="lib.CheckBoxStoreModel" jsId="filterModel" store="filterStore"
 					query="{id:'root'}" rootId="root" rootLabel="Filters"
diff --git a/classes/pref/labels.php b/classes/Pref_Labels.php
similarity index 99%
rename from classes/pref/labels.php
rename to classes/Pref_Labels.php
index 2e128691e503f24c64bc4470326fd5f16c540d27..a9d35cdbfc5df371ad93ab845279a6bda9900813 100644
--- a/classes/pref/labels.php
+++ b/classes/Pref_Labels.php
@@ -199,7 +199,7 @@ class Pref_Labels extends Handler_Protected {
 
 			<div style='padding : 0px' dojoType='dijit.layout.ContentPane' region='center'>
 				<div dojoType='dojo.data.ItemFileWriteStore' jsId='labelStore'
-					url='backend.php?op=pref-labels&method=getlabeltree'>
+					url='backend.php?op=Pref_Labels&method=getlabeltree'>
 				</div>
 
 				<div dojoType='lib.CheckBoxStoreModel' jsId='labelModel' store='labelStore'
diff --git a/classes/pref/prefs.php b/classes/Pref_Prefs.php
similarity index 99%
rename from classes/pref/prefs.php
rename to classes/Pref_Prefs.php
index 2ce5f061bc5bbef413a272edfefac60f36aa1568..da0ee54f7f5282ae8c876c8c8feb9afb326485c7 100644
--- a/classes/pref/prefs.php
+++ b/classes/Pref_Prefs.php
@@ -285,7 +285,7 @@ class Pref_Prefs extends Handler_Protected {
 		?>
 		<form dojoType='dijit.form.Form'>
 
-			<?= \Controls\hidden_tag("op", "pref-prefs") ?>
+			<?= \Controls\hidden_tag("op", "Pref_Prefs") ?>
 			<?= \Controls\hidden_tag("method", "changePersonalData") ?>
 
 			<script type="dojo/method" event="onSubmit" args="evt">
@@ -334,7 +334,7 @@ class Pref_Prefs extends Handler_Protected {
 
 			<form dojoType='dijit.form.Form'>
 
-				<?= \Controls\hidden_tag("op", "pref-prefs") ?>
+				<?= \Controls\hidden_tag("op", "Pref_Prefs") ?>
 				<?= \Controls\hidden_tag("method", "changepassword") ?>
 
 				<!-- TODO: return JSON the backend call -->
@@ -426,7 +426,7 @@ class Pref_Prefs extends Handler_Protected {
 				?>
 
 				<form dojoType='dijit.form.Form'>
-					<?= \Controls\hidden_tag("op", "pref-prefs") ?>
+					<?= \Controls\hidden_tag("op", "Pref_Prefs") ?>
 					<?= \Controls\hidden_tag("method", "otpdisable") ?>
 
 					<!-- TODO: return JSON from the backend call -->
@@ -473,7 +473,7 @@ class Pref_Prefs extends Handler_Protected {
 
 				<form dojoType='dijit.form.Form'>
 
-					<?= \Controls\hidden_tag("op", "pref-prefs") ?>
+					<?= \Controls\hidden_tag("op", "Pref_Prefs") ?>
 					<?= \Controls\hidden_tag("method", "otpenable") ?>
 
 					<fieldset>
@@ -746,7 +746,7 @@ class Pref_Prefs extends Handler_Protected {
 	private function index_prefs(): void {
 		?>
 		<form dojoType='dijit.form.Form' id='changeSettingsForm'>
-			<?= \Controls\hidden_tag("op", "pref-prefs") ?>
+			<?= \Controls\hidden_tag("op", "Pref_Prefs") ?>
 			<?= \Controls\hidden_tag("method", "saveconfig") ?>
 
 			<script type="dojo/method" event="onSubmit" args="evt, quit">
@@ -836,7 +836,7 @@ class Pref_Prefs extends Handler_Protected {
 		?>
 		<form dojoType="dijit.form.Form" id="changePluginsForm">
 
-			<?= \Controls\hidden_tag("op", "pref-prefs") ?>
+			<?= \Controls\hidden_tag("op", "Pref_Prefs") ?>
 			<?= \Controls\hidden_tag("method", "setplugins") ?>
 
 			<div dojoType="dijit.layout.BorderContainer" gutters="false">
@@ -936,7 +936,7 @@ class Pref_Prefs extends Handler_Protected {
 					<script type='dojo/method' event='onSelected' args='evt'>
 						if (this.domNode.querySelector('.loading'))
 							window.setTimeout(() => {
-								xhr.post("backend.php", {op: 'pref-prefs', method: 'index_auth'}, (reply) => {
+								xhr.post("backend.php", {op: 'Pref_Prefs', method: 'index_auth'}, (reply) => {
 									this.attr('content', reply);
 								});
 							}, 100);
diff --git a/classes/pref/system.php b/classes/Pref_System.php
similarity index 98%
rename from classes/pref/system.php
rename to classes/Pref_System.php
index 806291c72bb12290e6445cff2c5e0ead19c66b67..e85c1134dd44307b82398c8673914aae2bb32e36 100644
--- a/classes/pref/system.php
+++ b/classes/Pref_System.php
@@ -194,7 +194,7 @@ class Pref_System extends Handler_Administrative {
 							}
 						</script>
 
-						<?= \Controls\hidden_tag("op", "pref-system") ?>
+						<?= \Controls\hidden_tag("op", "Pref_System") ?>
 						<?= \Controls\hidden_tag("method", "sendTestEmail") ?>
 
 						<fieldset>
@@ -210,7 +210,7 @@ class Pref_System extends Handler_Administrative {
 					<script type='dojo/method' event='onSelected' args='evt'>
 						if (this.domNode.querySelector('.loading'))
 							window.setTimeout(() => {
-								xhr.post("backend.php", {op: 'pref-system', method: 'getphpinfo'}, (reply) => {
+								xhr.post("backend.php", {op: 'Pref_System', method: 'getphpinfo'}, (reply) => {
 									this.attr('content', `<div class='phpinfo'>${reply}</div>`);
 								});
 							}, 200);
diff --git a/classes/pref/users.php b/classes/Pref_Users.php
similarity index 100%
rename from classes/pref/users.php
rename to classes/Pref_Users.php
diff --git a/classes/prefs.php b/classes/Prefs.php
similarity index 100%
rename from classes/prefs.php
rename to classes/Prefs.php
diff --git a/classes/rpc.php b/classes/RPC.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/rpc.php
rename to classes/RPC.php
diff --git a/classes/rssutils.php b/classes/RSSUtils.php
old mode 100755
new mode 100644
similarity index 100%
rename from classes/rssutils.php
rename to classes/RSSUtils.php
diff --git a/classes/sanitizer.php b/classes/Sanitizer.php
similarity index 100%
rename from classes/sanitizer.php
rename to classes/Sanitizer.php
diff --git a/classes/templator.php b/classes/Templator.php
similarity index 100%
rename from classes/templator.php
rename to classes/Templator.php
diff --git a/classes/timehelper.php b/classes/TimeHelper.php
similarity index 100%
rename from classes/timehelper.php
rename to classes/TimeHelper.php
diff --git a/classes/tracer.php b/classes/Tracer.php
similarity index 100%
rename from classes/tracer.php
rename to classes/Tracer.php
diff --git a/classes/urlhelper.php b/classes/UrlHelper.php
similarity index 100%
rename from classes/urlhelper.php
rename to classes/UrlHelper.php
diff --git a/classes/userhelper.php b/classes/UserHelper.php
similarity index 100%
rename from classes/userhelper.php
rename to classes/UserHelper.php
diff --git a/composer.json b/composer.json
index d4a1f66b18acfeacffbf22c5736b08e283ad3d62..2458104f962b4f3787c73c36623cb97437311345 100644
--- a/composer.json
+++ b/composer.json
@@ -12,6 +12,11 @@
 	      "url": "https://dev.tt-rss.org/fox/idiorm.git"
 	    }
 	  ],
+		"autoload": {
+			"psr-4": {
+				"": "classes/"
+			}
+	},
     "require": {
         "spomky-labs/otphp": "^10.0",
         "chillerlan/php-qrcode": "^4.3.3",
diff --git a/include/autoload.php b/include/autoload.php
index 4422a435ca65ffe662109fc640b492d76ce3c816..d019940b70097e821d2e645ee4ad282705e71172 100644
--- a/include/autoload.php
+++ b/include/autoload.php
@@ -1,17 +1,2 @@
 <?php
-	spl_autoload_register(function($class) {
-
-		$root_dir = dirname(__DIR__); // we were in tt-rss/include
-
-		// - internal tt-rss classes are loaded from classes/ and use special naming logic instead of namespaces
-		// - plugin classes are loaded by PluginHandler from plugins.local/ and plugins/
-
-		$class_file = "$root_dir/classes/" . str_replace("_", "/", strtolower($class)) . ".php";
-
-		if (file_exists($class_file))
-			include $class_file;
-
-	});
-
-	// also pull composer autoloader
 	require_once "vendor/autoload.php";
diff --git a/js/App.js b/js/App.js
index 963a032c5e7d02122cb16625247a9066b8f81760..9d3f6a47d49b2bb09ceaea39da831ba1dd32d4d1 100644
--- a/js/App.js
+++ b/js/App.js
@@ -153,7 +153,7 @@ const App = {
       return dijit.getEnclosingWidget(elem.closest('.dijitDialog'));
    },
    getPhArgs(plugin, method, args = {}) {
-      return {...{op: "pluginhandler", plugin: plugin, method: method}, ...args};
+      return {...{op: "PluginHandler", plugin: plugin, method: method}, ...args};
    },
    label_to_feed_id: function(label) {
       return this.LABEL_BASE_INDEX - 1 - Math.abs(label);
@@ -291,7 +291,7 @@ const App = {
 	setCombinedMode: function(combined) {
 		const value = combined ? "true" : "false";
 
-		xhr.post("backend.php", {op: "rpc", method: "setpref", key: "COMBINED_DISPLAY_MODE", value: value}, () => {
+		xhr.post("backend.php", {op: "RPC", method: "setpref", key: "COMBINED_DISPLAY_MODE", value: value}, () => {
 			this.setInitParam("combined_display_mode",
 				!this.getInitParam("combined_display_mode"));
 
@@ -306,7 +306,7 @@ const App = {
 		if (App.isCombinedMode()) {
 			const value = expand ? "true" : "false";
 
-			xhr.post("backend.php", {op: "rpc", method: "setpref", key: "CDM_EXPANDED", value: value}, () => {
+			xhr.post("backend.php", {op: "RPC", method: "setpref", key: "CDM_EXPANDED", value: value}, () => {
 				this.setInitParam("cdm_expanded", !this.getInitParam("cdm_expanded"));
 				Headlines.renderAgain();
 			});
@@ -440,7 +440,7 @@ const App = {
       }
    },
    hotkeyHelp: function() {
-      xhr.post("backend.php", {op: "rpc", method: "hotkeyHelp"}, (reply) => {
+      xhr.post("backend.php", {op: "RPC", method: "hotkeyHelp"}, (reply) => {
          const dialog = new fox.SingleUseDialog({
             title: __("Keyboard shortcuts"),
             content: reply,
@@ -621,7 +621,7 @@ const App = {
 
 			try {
 				xhr.post("backend.php",
-					{op: "rpc", method: "log",
+					{op: "RPC", method: "log",
 						file: params.filename ? params.filename : error.fileName,
 						line: params.lineno ? params.lineno : error.lineNumber,
 						msg: message,
@@ -703,7 +703,7 @@ const App = {
          this.initHotkeyActions();
 
          const params = {
-            op: "rpc",
+            op: "RPC",
             method: "sanityCheck",
             clientTzOffset: new Date().getTimezoneOffset() * 60,
             hasSandbox: "sandbox" in document.createElement("iframe"),
@@ -737,7 +737,7 @@ const App = {
       return errorMsg == "";
    },
    updateRuntimeInfo: function() {
-      xhr.json("backend.php", {op: "rpc", method: "getruntimeinfo"}, () => {
+      xhr.json("backend.php", {op: "RPC", method: "getruntimeinfo"}, () => {
          // handled by xhr.json()
       });
    },
@@ -858,7 +858,7 @@ const App = {
    checkForUpdates: function() {
       console.log('checking for updates...');
 
-      xhr.json("backend.php", {op: 'rpc', method: 'checkforupdates'})
+      xhr.json("backend.php", {op: 'RPC', method: 'checkforupdates'})
          .then((reply) => {
             console.log('update reply', reply);
 
@@ -965,7 +965,7 @@ const App = {
 
       if (article_id) Article.view(article_id);
 
-      xhr.post("backend.php", {op: "rpc", method: "setWidescreen", wide: wide ? 1 : 0});
+      xhr.post("backend.php", {op: "RPC", method: "setWidescreen", wide: wide ? 1 : 0});
    },
    initHotkeyActions: function() {
       if (this.is_prefs) {
@@ -1149,7 +1149,7 @@ const App = {
             if (!Feeds.activeIsCat() && parseInt(Feeds.getActive()) > 0) {
 
                /* global __csrf_token */
-               App.postOpenWindow("backend.php", {op: "feeds", method: "updatedebugger",
+               App.postOpenWindow("backend.php", {op: "Feeds", method: "updatedebugger",
                   feed_id: Feeds.getActive(), csrf_token: __csrf_token});
 
             } else {
@@ -1158,7 +1158,7 @@ const App = {
          };
 
          this.hotkey_actions["feed_debug_viewfeed"] = () => {
-            App.postOpenWindow("backend.php", {op: "feeds", method: "view",
+            App.postOpenWindow("backend.php", {op: "Feeds", method: "view",
                feed: Feeds.getActive(), timestamps: 1, debug: 1, cat: Feeds.activeIsCat(), csrf_token: __csrf_token});
          };
 
@@ -1177,13 +1177,13 @@ const App = {
             Headlines.reverse();
          };
          this.hotkey_actions["feed_toggle_grid"] = () => {
-            xhr.json("backend.php", {op: "rpc", method: "togglepref", key: "CDM_ENABLE_GRID"}, (reply) => {
+            xhr.json("backend.php", {op: "RPC", method: "togglepref", key: "CDM_ENABLE_GRID"}, (reply) => {
                App.setInitParam("cdm_enable_grid", reply.value);
                Headlines.renderAgain();
             })
          };
          this.hotkey_actions["feed_toggle_vgroup"] = () => {
-            xhr.post("backend.php", {op: "rpc", method: "togglepref", key: "VFEED_GROUP_BY_FEED"}, () => {
+            xhr.post("backend.php", {op: "RPC", method: "togglepref", key: "VFEED_GROUP_BY_FEED"}, () => {
                Feeds.reloadCurrent();
             })
          };
@@ -1274,7 +1274,7 @@ const App = {
             CommonDialogs.subscribeToFeed();
             break;
          case "qmcDigest":
-            window.location.href = "backend.php?op=digest";
+            window.location.href = "backend.php?op=Digest";
             break;
          case "qmcEditFeed":
             if (Feeds.activeIsCat())
diff --git a/js/Article.js b/js/Article.js
index 5f3a8c2e9d4ec964720ac7749e4d668bcf83bd44..85cee632247323add3fdd372b7fe4fd777973297 100644
--- a/js/Article.js
+++ b/js/Article.js
@@ -123,7 +123,7 @@ const Article = {
 		Article.setActive(0);
 	},
 	displayUrl: function (id) {
-		const query = {op: "article", method: "getmetadatabyid", id: id};
+		const query = {op: "Article", method: "getmetadatabyid", id: id};
 
 		xhr.json("backend.php", query, (reply) => {
 			if (reply && reply.link) {
@@ -136,7 +136,7 @@ const Article = {
 	openInNewWindow: function (id) {
 		/* global __csrf_token */
 		App.postOpenWindow("backend.php",
-			{ "op": "article", "method": "redirect", "id": id, "csrf_token": __csrf_token });
+			{ "op": "Article", "method": "redirect", "id": id, "csrf_token": __csrf_token });
 
 		Headlines.toggleUnread(id, 0);
 	},
@@ -395,7 +395,7 @@ const Article = {
 		const tmph = dojo.connect(dialog, 'onShow', function () {
 			dojo.disconnect(tmph);
 
-			xhr.json("backend.php", {op: "article", method: "printArticleTags", id: id}, (reply) => {
+			xhr.json("backend.php", {op: "Article", method: "printArticleTags", id: id}, (reply) => {
 
 				dijit.getEnclosingWidget(App.byId("tags_str"))
 					.attr('value', reply.tags.join(", "))
@@ -404,7 +404,7 @@ const Article = {
 				App.byId('tags_str').onkeyup = (e) => {
 					const last_tag = e.target.value.split(',').pop().trim();
 
-					xhr.json("backend.php", {op: 'article', method: 'completeTags', search: last_tag}, (data) => {
+					xhr.json("backend.php", {op: 'Article', method: 'completeTags', search: last_tag}, (data) => {
 						App.byId("tags_choices").innerHTML = `${data.map((tag) =>
 							`<a href="#" onclick="Article.autocompleteInject(this, 'tags_str')">${tag}</a>` )
 								.join(', ')}`
diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js
index a141c29bed90d83e9f78fc1d607416fc5e841ff0..e7190e07cd3793f78069207169a945a84c4984dd 100644
--- a/js/CommonDialogs.js
+++ b/js/CommonDialogs.js
@@ -28,7 +28,7 @@ const	CommonDialogs = {
 		},
 		subscribeToFeed: function() {
 			xhr.json("backend.php",
-					{op: "feeds", method: "subscribeToFeed"},
+					{op: "Feeds", method: "subscribeToFeed"},
 					(reply) => {
 						const dialog = new fox.SingleUseDialog({
 							title: __("Subscribe to feed"),
@@ -215,7 +215,7 @@ const	CommonDialogs = {
 		},
 		showFeedsWithErrors: function() {
 
-			xhr.json("backend.php", {op: "pref-feeds", method: "feedsWithErrors"}, (reply) => {
+			xhr.json("backend.php", {op: "Pref_Feeds", method: "feedsWithErrors"}, (reply) => {
 
 				const dialog = new fox.SingleUseDialog({
 					id: "errorFeedsDlg",
@@ -231,7 +231,7 @@ const	CommonDialogs = {
 								Notify.progress("Removing selected feeds...", true);
 
 								const query = {
-									op: "pref-feeds", method: "remove",
+									op: "Pref_Feeds", method: "remove",
 									ids: sel_rows.toString()
 								};
 
@@ -305,7 +305,7 @@ const	CommonDialogs = {
 
 			if (caption != undefined && caption.trim().length > 0) {
 
-				const query = {op: "pref-labels", method: "add", caption: caption.trim()};
+				const query = {op: "Pref_Labels", method: "add", caption: caption.trim()};
 
 				Notify.progress("Loading, please wait...", true);
 
@@ -325,7 +325,7 @@ const	CommonDialogs = {
 			if (typeof title == "undefined" || confirm(msg)) {
 				Notify.progress("Removing feed...");
 
-				const query = {op: "pref-feeds", quiet: 1, method: "remove", ids: feed_id};
+				const query = {op: "Pref_Feeds", quiet: 1, method: "remove", ids: feed_id};
 
 				xhr.post("backend.php", query, () => {
 					if (App.isPrefs()) {
@@ -348,7 +348,7 @@ const	CommonDialogs = {
 			if (feed_id <= 0)
 				return alert(__("You can't edit this kind of feed."));
 
-			const query = {op: "pref-feeds", method: "editfeed", id: feed_id};
+			const query = {op: "Pref_Feeds", method: "editfeed", id: feed_id};
 
 			console.log("editFeed", query);
 
@@ -378,7 +378,7 @@ const	CommonDialogs = {
 						const fd = new FormData();
 						fd.append('icon_file', icon_file)
 						fd.append('feed_id', feed_id);
-						fd.append('op', 'pref-feeds');
+						fd.append('op', 'Pref_Feeds');
 						fd.append('method', 'uploadIcon');
 						fd.append('csrf_token', App.getInitParam("csrf_token"));
 
@@ -427,7 +427,7 @@ const	CommonDialogs = {
 					if (confirm(__("Remove stored feed icon?"))) {
 						Notify.progress("Removing feed icon...", true);
 
-						xhr.post("backend.php", {op: "pref-feeds", method: "removeicon", feed_id: id}, () => {
+						xhr.post("backend.php", {op: "Pref_Feeds", method: "removeicon", feed_id: id}, () => {
 							Notify.info("Feed icon removed.");
 
 							if (App.isPrefs())
@@ -470,7 +470,7 @@ const	CommonDialogs = {
 			const tmph = dojo.connect(dialog, 'onShow', function () {
 				dojo.disconnect(tmph);
 
-				xhr.json("backend.php", {op: "pref-feeds", method: "editfeed", id: feed_id}, (reply) => {
+				xhr.json("backend.php", {op: "Pref_Feeds", method: "editfeed", id: feed_id}, (reply) => {
 					const feed = reply.feed;
 					const is_readonly = reply.user.access_level == App.UserAccessLevels.ACCESS_LEVEL_READONLY;
 
@@ -493,7 +493,7 @@ const	CommonDialogs = {
 							<div dojoType="dijit.layout.ContentPane" title="${__('General')}">
 
 								${App.FormFields.hidden_tag("id", feed_id)}
-								${App.FormFields.hidden_tag("op", "pref-feeds")}
+								${App.FormFields.hidden_tag("op", "Pref_Feeds")}
 								${App.FormFields.hidden_tag("method", "editSave")}
 
 								<section>
@@ -621,7 +621,7 @@ const	CommonDialogs = {
 
 			Notify.progress("Loading, please wait...", true);
 
-			xhr.json("backend.php", {op: "pref-feeds", method: "getsharedurl", id: feed, is_cat: is_cat, search: search}, (reply) => {
+			xhr.json("backend.php", {op: "Pref_Feeds", method: "getsharedurl", id: feed, is_cat: is_cat, search: search}, (reply) => {
 				try {
 					const dialog = new fox.SingleUseDialog({
 						title: __("Show as feed"),
@@ -630,7 +630,7 @@ const	CommonDialogs = {
 
 								Notify.progress("Trying to change address...", true);
 
-								const query = {op: "pref-feeds", method: "regenFeedKey", id: feed, is_cat: is_cat};
+								const query = {op: "Pref_Feeds", method: "regenFeedKey", id: feed, is_cat: is_cat};
 
 								xhr.json("backend.php", query, (reply) => {
 									const new_link = reply.link;
diff --git a/js/CommonFilters.js b/js/CommonFilters.js
index 1a0ce1606f40767d1939085c9d224112714cce6f..8be9e261300c794f79df251af5c85ed3c7e438b4 100644
--- a/js/CommonFilters.js
+++ b/js/CommonFilters.js
@@ -115,7 +115,7 @@ const	Filters = {
 			insertRule: function(parentNode, replaceNode) {
 				const rule = dojo.formToJson("filter_new_rule_form");
 
-				xhr.post("backend.php", {op: "pref-filters", method: "printrulename", rule: rule}, (reply) => {
+				xhr.post("backend.php", {op: "Pref_Filters", method: "printrulename", rule: rule}, (reply) => {
 					try {
 						const li = document.createElement('li');
 						li.addClassName("rule");
@@ -147,7 +147,7 @@ const	Filters = {
 
 				const action = dojo.formToJson(form);
 
-				xhr.post("backend.php", { op: "pref-filters", method: "printactionname", action: action }, (reply) => {
+				xhr.post("backend.php", { op: "Pref_Filters", method: "printactionname", action: action }, (reply) => {
 					try {
 						const li = document.createElement('li');
 						li.addClassName("action");
@@ -200,7 +200,7 @@ const	Filters = {
 
 					console.log(rule, dialog.filter_info);
 
-					xhr.json("backend.php", {op: "pref-filters", method: "editrule", ids: rule.feed_id.join(",")}, function (editrule) {
+					xhr.json("backend.php", {op: "Pref_Filters", method: "editrule", ids: rule.feed_id.join(",")}, function (editrule) {
 						edit_rule_dialog.attr('content',
 							`
 							<form name="filter_new_rule_form" id="filter_new_rule_form" onsubmit="return false">
@@ -326,7 +326,7 @@ const	Filters = {
 
 					dijit.byId("filterDlg_actionSelect").attr('value', action.action_id);
 
-					/*xhr.post("backend.php", {op: 'pref-filters', method: 'newaction', action: actionStr}, (reply) => {
+					/*xhr.post("backend.php", {op: 'Pref_Filters', method: 'newaction', action: actionStr}, (reply) => {
 						edit_action_dialog.attr('content', reply);
 
 						setTimeout(() => {
@@ -365,7 +365,7 @@ const	Filters = {
 
 					Notify.progress("Removing filter...");
 
-					const query = {op: "pref-filters", method: "remove", ids: this.attr('value').id};
+					const query = {op: "Pref_Filters", method: "remove", ids: this.attr('value').id};
 
 					xhr.post("backend.php", query, () => {
 						const tree = dijit.byId("filterTree");
@@ -411,7 +411,7 @@ const	Filters = {
 		const tmph = dojo.connect(dialog, 'onShow', function () {
 			dojo.disconnect(tmph);
 
-			xhr.json("backend.php", {op: "pref-filters", method: "edit", id: filter_id}, function (filter) {
+			xhr.json("backend.php", {op: "Pref_Filters", method: "edit", id: filter_id}, function (filter) {
 
 				dialog.filter_info = filter;
 
@@ -425,7 +425,7 @@ const	Filters = {
 				`
 					<form onsubmit='return false'>
 
-						${App.FormFields.hidden_tag("op", "pref-filters")}
+						${App.FormFields.hidden_tag("op", "Pref_Filters")}
 						${App.FormFields.hidden_tag("id", filter_id)}
 						${App.FormFields.hidden_tag("method", filter_id ? "editSave" : "add")}
 						${App.FormFields.hidden_tag("csrf_token", App.getInitParam('csrf_token'))}
@@ -541,7 +541,7 @@ const	Filters = {
 
 						dialog.editRule(null, dojo.toJson(rule));
 					} else {
-						const query = {op: "article", method: "getmetadatabyid", id: Article.getActive()};
+						const query = {op: "Article", method: "getmetadatabyid", id: Article.getActive()};
 
 						xhr.json("backend.php", query, (reply) => {
 							let title;
diff --git a/js/FeedTree.js b/js/FeedTree.js
index 3eaa61263befe79f61c199d16b3fecc2782a2065..df026a7bce115d22726b8f1a559eb9a3f352a0eb 100755
--- a/js/FeedTree.js
+++ b/js/FeedTree.js
@@ -104,7 +104,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co
 					menu.addChild(new dijit.MenuItem({
 						label: __("Open site"),
 						onClick: function() {
-							App.postOpenWindow("backend.php", {op: "feeds", method: "opensite",
+							App.postOpenWindow("backend.php", {op: "Feeds", method: "opensite",
 								feed_id: this.getParent().row_id, csrf_token: __csrf_token});
 						}}));
 
@@ -114,7 +114,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co
 						label: __("Debug feed"),
 						onClick: function() {
 							/* global __csrf_token */
-							App.postOpenWindow("backend.php", {op: "feeds", method: "updatedebugger",
+							App.postOpenWindow("backend.php", {op: "Feeds", method: "updatedebugger",
 								feed_id: this.getParent().row_id, csrf_token: __csrf_token});
 						}}));
 				}
diff --git a/js/Feeds.js b/js/Feeds.js
index 7a567808463ff03d78c381a88a460f41b0bc7942..a6eecaf8128394f4f4f0efd451fcdb8edbb98594 100644
--- a/js/Feeds.js
+++ b/js/Feeds.js
@@ -160,7 +160,7 @@ const	Feeds = {
 	},
 	// null = get all data, [] would give empty response for specific type
 	requestCounters: function(feed_ids = null, label_ids = null) {
-		xhr.json("backend.php", {op: "rpc",
+		xhr.json("backend.php", {op: "RPC",
 							method: "getAllCounters",
 							"feed_ids[]": feed_ids,
 							"feed_id_count": feed_ids ? feed_ids.length : -1,
@@ -179,7 +179,7 @@ const	Feeds = {
 			}
 
 			const store = new dojo.data.ItemFileWriteStore({
-				url: "backend.php?op=pref_feeds&method=getfeedtree&mode=2"
+				url: "backend.php?op=Pref_Feeds&method=getfeedtree&mode=2"
 			});
 
 			// noinspection JSUnresolvedFunction
@@ -347,7 +347,7 @@ const	Feeds = {
 	toggleUnread: function() {
 		const hide = !App.getInitParam("hide_read_feeds");
 
-		xhr.post("backend.php", {op: "rpc", method: "setpref", key: "HIDE_READ_FEEDS", value: hide}, () => {
+		xhr.post("backend.php", {op: "RPC", method: "setpref", key: "HIDE_READ_FEEDS", value: hide}, () => {
 			this.hideOrShowFeeds(hide);
 			App.setInitParam("hide_read_feeds", hide);
 		});
@@ -386,7 +386,7 @@ const	Feeds = {
 			}, 10 * 1000);
 		}
 
-		let query = {...{op: "feeds", method: "view", feed: feed}, ...dojo.formToObject("toolbar-main")};
+		let query = {...{op: "Feeds", method: "view", feed: feed}, ...dojo.formToObject("toolbar-main")};
 
 		if (method) query.m = method;
 
@@ -435,7 +435,7 @@ const	Feeds = {
 
 			Notify.progress("Marking all feeds as read...");
 
-			xhr.json("backend.php", {op: "feeds", method: "catchupAll"}, () => {
+			xhr.json("backend.php", {op: "Feeds", method: "catchupAll"}, () => {
 				this.reloadCurrent();
 			});
 
@@ -473,7 +473,7 @@ const	Feeds = {
 		}
 
 		const catchup_query = {
-			op: 'rpc', method: 'catchupFeed', feed_id: feed,
+			op: 'RPC', method: 'catchupFeed', feed_id: feed,
 			is_cat: is_cat, mode: mode, search_query: this.last_search_query[0],
 			search_lang: this.last_search_query[1]
 		};
@@ -612,7 +612,7 @@ const	Feeds = {
 	},
 	search: function() {
 		xhr.json("backend.php",
-					{op: "feeds", method: "search"},
+					{op: "Feeds", method: "search"},
 					(reply) => {
 						try {
 							const dialog = new fox.SingleUseDialog({
@@ -686,7 +686,7 @@ const	Feeds = {
 	updateRandom: function() {
 		console.log("in update_random_feed");
 
-		xhr.json("backend.php", {op: "rpc", method: "updaterandomfeed"}, () => {
+		xhr.json("backend.php", {op: "RPC", method: "updaterandomfeed"}, () => {
 			//
 		});
 	},
diff --git a/js/Headlines.js b/js/Headlines.js
index 5706377f8e6d3c72a75ed7a3ce1560d5a1583164..6a439f74417e3f936128e50eb11a48f024cae9de 100755
--- a/js/Headlines.js
+++ b/js/Headlines.js
@@ -160,26 +160,26 @@ const Headlines = {
 
 		if (ops.tmark.length != 0)
 			promises.push(xhr.post("backend.php",
-				{op: "rpc", method: "markSelected", "ids[]": ops.tmark, cmode: 2}));
+				{op: "RPC", method: "markSelected", "ids[]": ops.tmark, cmode: 2}));
 
 		if (ops.tpub.length != 0)
 			promises.push(xhr.post("backend.php",
-				{op: "rpc", method: "publishSelected", "ids[]": ops.tpub, cmode: 2}));
+				{op: "RPC", method: "publishSelected", "ids[]": ops.tpub, cmode: 2}));
 
 		if (ops.read.length != 0)
 			promises.push(xhr.post("backend.php",
-				{op: "rpc", method: "catchupSelected", "ids[]": ops.read, cmode: 0}));
+				{op: "RPC", method: "catchupSelected", "ids[]": ops.read, cmode: 0}));
 
 		if (ops.unread.length != 0)
 			promises.push(xhr.post("backend.php",
-				{op: "rpc", method: "catchupSelected", "ids[]": ops.unread, cmode: 1}));
+				{op: "RPC", method: "catchupSelected", "ids[]": ops.unread, cmode: 1}));
 
 		const scores = Object.keys(ops.rescore);
 
 		if (scores.length != 0) {
 			scores.forEach((score) => {
 				promises.push(xhr.post("backend.php",
-					{op: "article", method: "setScore", "ids[]": ops.rescore[score], score: score}));
+					{op: "Article", method: "setScore", "ids[]": ops.rescore[score], score: score}));
 			});
 		}
 
@@ -1132,7 +1132,7 @@ const Headlines = {
 		}
 
 		const query = {
-			op: "article", method: "removeFromLabel",
+			op: "Article", method: "removeFromLabel",
 			ids: ids.toString(), lid: id
 		};
 
@@ -1149,7 +1149,7 @@ const Headlines = {
 		}
 
 		const query = {
-			op: "article", method: "assignToLabel",
+			op: "Article", method: "assignToLabel",
 			ids: ids.toString(), lid: id
 		};
 
@@ -1181,7 +1181,7 @@ const Headlines = {
 			return;
 		}
 
-		const query = {op: "rpc", method: "delete", ids: rows.toString()};
+		const query = {op: "RPC", method: "delete", ids: rows.toString()};
 
 		xhr.json("backend.php", query, () => {
 			Feeds.reloadCurrent();
@@ -1586,7 +1586,7 @@ const Headlines = {
 			menu.addChild(new dijit.MenuItem({
 				label: __("Open site"),
 				onClick: function() {
-					App.postOpenWindow("backend.php", {op: "feeds", method: "opensite",
+					App.postOpenWindow("backend.php", {op: "Feeds", method: "opensite",
 						feed_id: this.getParent().currentTarget.getAttribute("data-feed-id"), csrf_token: __csrf_token});
 				}}));
 
@@ -1596,7 +1596,7 @@ const Headlines = {
 				label: __("Debug feed"),
 				onClick: function() {
 					/* global __csrf_token */
-					App.postOpenWindow("backend.php", {op: "feeds", method: "updatedebugger",
+					App.postOpenWindow("backend.php", {op: "Feeds", method: "updatedebugger",
 						feed_id: this.getParent().currentTarget.getAttribute("data-feed-id"), csrf_token: __csrf_token});
 				}}));
 
diff --git a/js/PrefFeedStore.js b/js/PrefFeedStore.js
index ee983af54c9fed31553690e3821d1b7addf6f68d..348cbd995793e12ca45d52217e931775f43fb024 100644
--- a/js/PrefFeedStore.js
+++ b/js/PrefFeedStore.js
@@ -8,7 +8,7 @@ define(["dojo/_base/declare", "dojo/data/ItemFileWriteStore"], function (declare
 
 			dojo.xhrPost({
 				url: "backend.php",
-				content: {op: "pref-feeds", method: "savefeedorder",
+				content: {op: "Pref_Feeds", method: "savefeedorder",
 					payload: newFileContentString},
 				error: saveFailedCallback,
 				load: saveCompleteCallback});
diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js
index 85b262b6de9ed34a9306b6bacf4e28aa247b4f75..f1729382c57c7fd72cf8086bca5a194750f7066f 100644
--- a/js/PrefFeedTree.js
+++ b/js/PrefFeedTree.js
@@ -150,7 +150,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 			const searchElem = App.byId("feed_search");
 			const search = (searchElem) ? searchElem.value : "";
 
-			xhr.post("backend.php", { op: "pref-feeds", search: search }, (reply) => {
+			xhr.post("backend.php", { op: "Pref_Feeds", search: search }, (reply) => {
 				dijit.byId('feedsTab').attr('content', reply);
 				Notify.close();
 			});
@@ -185,14 +185,14 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 		resetFeedOrder: function() {
 			Notify.progress("Loading, please wait...");
 
-			xhr.post("backend.php", {op: "pref-feeds", method: "feedsortreset"}, () => {
+			xhr.post("backend.php", {op: "Pref_Feeds", method: "feedsortreset"}, () => {
 				this.reload();
 			});
 		},
 		resetCatOrder: function() {
 			Notify.progress("Loading, please wait...");
 
-			xhr.post("backend.php", {op: "pref-feeds", method: "catsortreset"}, () => {
+			xhr.post("backend.php", {op: "Pref_Feeds", method: "catsortreset"}, () => {
 				this.reload();
 			});
 		},
@@ -200,7 +200,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 			if (confirm(__("Remove category %s? Any nested feeds would be placed into Uncategorized.").replace("%s", item.name))) {
 				Notify.progress("Removing category...");
 
-				xhr.post("backend.php", {op: "pref-feeds", method: "removeCat", ids: id}, () => {
+				xhr.post("backend.php", {op: "Pref_Feeds", method: "removeCat", ids: id}, () => {
 					Notify.close();
 					this.reload();
 				});
@@ -215,7 +215,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 					Notify.progress("Unsubscribing from selected feeds...", true);
 
 					const query = {
-						op: "pref-feeds", method: "remove",
+						op: "Pref_Feeds", method: "remove",
 						ids: sel_rows.toString()
 					};
 
@@ -231,14 +231,14 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 			return false;
 		},
 		checkErrorFeeds: function() {
-			xhr.json("backend.php", {op: "pref-feeds", method: "feedsWithErrors"}, (reply) => {
+			xhr.json("backend.php", {op: "Pref_Feeds", method: "feedsWithErrors"}, (reply) => {
 				if (reply.length > 0) {
 					Element.show(dijit.byId("pref_feeds_errors_btn").domNode);
 				}
 			});
 		},
 		checkInactiveFeeds: function() {
-			xhr.json("backend.php", {op: "pref-feeds", method: "inactivefeeds"}, (reply) => {
+			xhr.json("backend.php", {op: "Pref_Feeds", method: "inactivefeeds"}, (reply) => {
 				if (reply.length > 0) {
 					Element.show(dijit.byId("pref_feeds_inactive_btn").domNode);
 				}
@@ -264,7 +264,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 					Notify.progress("Removing selected categories...");
 
 					const query = {
-						op: "pref-feeds", method: "removeCat",
+						op: "Pref_Feeds", method: "removeCat",
 						ids: sel_rows.toString()
 					};
 
@@ -316,7 +316,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 
 			Notify.progress("Loading, please wait...");
 
-			xhr.post("backend.php", {op: "pref-feeds", method: "editfeeds", ids: rows.toString()}, (reply) => {
+			xhr.post("backend.php", {op: "Pref_Feeds", method: "editfeeds", ids: rows.toString()}, (reply) => {
 				Notify.close();
 
 				try {
@@ -393,7 +393,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 
 				Notify.progress("Loading, please wait...");
 
-				xhr.post("backend.php", { op: 'pref-feeds', method: 'renamecat', id: id, title: new_name }, () => {
+				xhr.post("backend.php", { op: 'Pref_Feeds', method: 'renamecat', id: id, title: new_name }, () => {
 					this.reload();
 				});
 			}
@@ -404,14 +404,14 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 			if (title) {
 				Notify.progress("Creating category...");
 
-				xhr.post("backend.php", {op: "pref-feeds", method: "addCat", cat: title}, () => {
+				xhr.post("backend.php", {op: "Pref_Feeds", method: "addCat", cat: title}, () => {
 					Notify.close();
 					this.reload();
 				});
 			}
 		},
 		batchSubscribe: function() {
-			xhr.json("backend.php", {op: 'pref-feeds', method: 'batchSubscribe'}, (reply) => {
+			xhr.json("backend.php", {op: 'Pref_Feeds', method: 'batchSubscribe'}, (reply) => {
 				const dialog = new fox.SingleUseDialog({
 					id: "batchSubDlg",
 					title: __("Batch subscribe"),
@@ -431,7 +431,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 					},
 					content: `
 						<form onsubmit='return false'>
-							${App.FormFields.hidden_tag("op", "pref-feeds")}
+							${App.FormFields.hidden_tag("op", "Pref_Feeds")}
 							${App.FormFields.hidden_tag("method", "batchaddfeeds")}
 
 							<header class='horizontal'>
@@ -484,7 +484,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 			});
 		},
 		showInactiveFeeds: function() {
-			xhr.json("backend.php", {op: 'pref-feeds', method: 'inactivefeeds'}, function (reply) {
+			xhr.json("backend.php", {op: 'Pref_Feeds', method: 'inactivefeeds'}, function (reply) {
 
 				const dialog = new fox.SingleUseDialog({
 					id: "inactiveFeedsDlg",
@@ -500,7 +500,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b
 								Notify.progress("Removing selected feeds...", true);
 
 								const query = {
-									op: "pref-feeds", method: "remove",
+									op: "Pref_Feeds", method: "remove",
 									ids: sel_rows.toString()
 								};
 
diff --git a/js/PrefFilterStore.js b/js/PrefFilterStore.js
index a41d841297faa99bd29f56bff6785ad867df2a18..f1192374a0472b58e64fb1627f796fafcae79ce0 100644
--- a/js/PrefFilterStore.js
+++ b/js/PrefFilterStore.js
@@ -9,7 +9,7 @@ define(["dojo/_base/declare", "dojo/data/ItemFileWriteStore"], function (declare
 			dojo.xhrPost({
 				url: "backend.php",
 				content: {
-					op: "pref-filters", method: "savefilterorder",
+					op: "Pref_Filters", method: "savefilterorder",
 					payload: newFileContentString
 				},
 				error: saveFailedCallback,
diff --git a/js/PrefFilterTree.js b/js/PrefFilterTree.js
index 149261abd0507b11b9423b079427ffe0e51b9d25..eded7e383f62d2853afeb1de8ba20265db0c5c6b 100644
--- a/js/PrefFilterTree.js
+++ b/js/PrefFilterTree.js
@@ -107,7 +107,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio
 			let search = "";
 			if (user_search) { search = user_search.value; }
 
-			xhr.post("backend.php", { op: "pref-filters", search: search }, (reply) => {
+			xhr.post("backend.php", { op: "Pref_Filters", search: search }, (reply) => {
 				dijit.byId('filtersTab').attr('content', reply);
 				Notify.close();
 			});
@@ -125,7 +125,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio
 		resetFilterOrder: function() {
 			Notify.progress("Loading, please wait...");
 
-			xhr.post("backend.php", {op: "pref-filters", method: "filtersortreset"}, () => {
+			xhr.post("backend.php", {op: "Pref_Filters", method: "filtersortreset"}, () => {
 				this.reload();
 			});
 		},
@@ -140,7 +140,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio
 			if (confirm(__("Combine selected filters?"))) {
 				Notify.progress("Joining filters...");
 
-				xhr.post("backend.php", {op: "pref-filters", method: "join", ids: rows.toString()}, () => {
+				xhr.post("backend.php", {op: "Pref_Filters", method: "join", ids: rows.toString()}, () => {
 					this.reload();
 				});
 			}
@@ -153,7 +153,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio
 					Notify.progress("Removing selected filters...");
 
 					const query = {
-						op: "pref-filters", method: "remove",
+						op: "Pref_Filters", method: "remove",
 						ids: sel_rows.toString()
 					};
 
diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js
index c0fff66c92737b382d4cebf67e4fef6c9873d6b7..7a4c9934072dc50f3c719b308fdece21f1de87f5 100644
--- a/js/PrefHelpers.js
+++ b/js/PrefHelpers.js
@@ -19,7 +19,7 @@ const	Helpers = {
 				alert("No passwords selected.");
 			} else if (confirm(__("Remove selected app passwords?"))) {
 
-				xhr.post("backend.php", {op: "pref-prefs", method: "deleteAppPasswords", "ids[]": rows}, (reply) => {
+				xhr.post("backend.php", {op: "Pref_Prefs", method: "deleteAppPasswords", "ids[]": rows}, (reply) => {
 					this.updateContent(reply);
 					Notify.close();
 				});
@@ -31,7 +31,7 @@ const	Helpers = {
 			const title = prompt("Password description:")
 
 			if (title) {
-				xhr.post("backend.php", {op: "pref-prefs", method: "generateAppPassword", title: title}, (reply) => {
+				xhr.post("backend.php", {op: "Pref_Prefs", method: "generateAppPassword", title: title}, (reply) => {
 					this.updateContent(reply);
 					Notify.close();
 				});
@@ -45,7 +45,7 @@ const	Helpers = {
 			if (confirm(__("This will invalidate all previously generated feed URLs. Continue?"))) {
 				Notify.progress("Clearing URLs...");
 
-				xhr.post("backend.php", {op: "pref-feeds", method: "clearKeys"}, () => {
+				xhr.post("backend.php", {op: "Pref_Feeds", method: "clearKeys"}, () => {
 					Notify.info("Generated URLs cleared.");
 				});
 			}
@@ -71,7 +71,7 @@ const	Helpers = {
 			const tmph = dojo.connect(dialog, 'onShow', function () {
 				dojo.disconnect(tmph);
 
-				xhr.json("backend.php", {op: "pref-prefs", method: "previewDigest"}, (reply) => {
+				xhr.json("backend.php", {op: "Pref_Prefs", method: "previewDigest"}, (reply) => {
 					dialog.domNode.querySelector('.digest-preview').innerHTML = reply[0];
 				});
 			});
@@ -91,7 +91,7 @@ const	Helpers = {
 		},
 		update: function() {
 			xhr.post("backend.php", {
-						op: "pref-system",
+						op: "Pref_System",
 						severity: dijit.byId("severity").attr('value'),
 						page: Helpers.EventLog.log_page
 					}, (reply) => {
@@ -114,7 +114,7 @@ const	Helpers = {
 
 				Notify.progress("Loading, please wait...");
 
-				xhr.post("backend.php", {op: "pref-system", method: "clearLog"}, () => {
+				xhr.post("backend.php", {op: "Pref_System", method: "clearLog"}, () => {
 					Helpers.EventLog.refresh();
 				});
 			}
@@ -135,7 +135,7 @@ const	Helpers = {
 						const new_title = prompt(__("Name for cloned profile:"));
 
 						if (new_title) {
-							xhr.post("backend.php", {op: "pref-prefs", method: "cloneprofile", "new_title": new_title, "old_profile": sel_rows[0]}, () => {
+							xhr.post("backend.php", {op: "Pref_Prefs", method: "cloneprofile", "new_title": new_title, "old_profile": sel_rows[0]}, () => {
 								Notify.close();
 								dialog.refresh();
 							});
@@ -153,7 +153,7 @@ const	Helpers = {
 						if (confirm(__("Remove selected profiles? Active and default profiles will not be removed."))) {
 							Notify.progress("Removing selected profiles...", true);
 
-							xhr.post("backend.php", {op: "pref-prefs", method: "remprofiles", "ids[]": sel_rows}, () => {
+							xhr.post("backend.php", {op: "Pref_Prefs", method: "remprofiles", "ids[]": sel_rows}, () => {
 								Notify.close();
 								dialog.refresh();
 							});
@@ -167,7 +167,7 @@ const	Helpers = {
 					if (this.validate()) {
 						Notify.progress("Creating profile...", true);
 
-						const query = {op: "pref-prefs", method: "addprofile", title: dialog.attr('value').newprofile};
+						const query = {op: "Pref_Prefs", method: "addprofile", title: dialog.attr('value').newprofile};
 
 						xhr.post("backend.php", query, () => {
 							Notify.close();
@@ -177,7 +177,7 @@ const	Helpers = {
 					}
 				},
 				refresh: function() {
-					xhr.json("backend.php", {op: 'pref-prefs', method: 'getprofiles'}, (reply) => {
+					xhr.json("backend.php", {op: 'Pref_Prefs', method: 'getprofiles'}, (reply) => {
 						dialog.attr('content', `
 							<div dojoType='fox.Toolbar'>
 								<div dojoType='fox.form.DropDownButton'>
@@ -210,7 +210,7 @@ const	Helpers = {
 															profile-id='${profile.id}'>${profile.title}
 																<script type='dojo/method' event='onChange' args='value'>
 																	xhr.post("backend.php",
-																		{op: 'pref-prefs', method: 'saveprofile', value: value, id: this.attr('profile-id')}, () => {
+																		{op: 'Pref_Prefs', method: 'saveprofile', value: value, id: this.attr('profile-id')}, () => {
 																			//
 																		});
 																</script>
@@ -242,7 +242,7 @@ const	Helpers = {
 						if (confirm(__("Activate selected profile?"))) {
 							Notify.progress("Loading, please wait...");
 
-							xhr.post("backend.php", {op: "pref-prefs", method: "activateprofile", id: sel_rows.toString()}, () => {
+							xhr.post("backend.php", {op: "Pref_Prefs", method: "activateprofile", id: sel_rows.toString()}, () => {
 								window.location.reload();
 							});
 						}
@@ -312,7 +312,7 @@ const	Helpers = {
 			const tmph = dojo.connect(dialog, 'onShow', function () {
 				dojo.disconnect(tmph);
 
-				xhr.json("backend.php", {op: "pref-prefs", method: "customizeCSS"}, (reply) => {
+				xhr.json("backend.php", {op: "Pref_Prefs", method: "customizeCSS"}, (reply) => {
 
 					const editor = dijit.getEnclosingWidget(dialog.domNode.querySelector(".user-css-editor"));
 
@@ -327,14 +327,14 @@ const	Helpers = {
 		},
 		confirmReset: function() {
 			if (confirm(__("Reset to defaults?"))) {
-				xhr.post("backend.php", {op: "pref-prefs", method: "resetconfig"}, (reply) => {
+				xhr.post("backend.php", {op: "Pref_Prefs", method: "resetconfig"}, (reply) => {
 					Helpers.Prefs.refresh();
 					Notify.info(reply);
 				});
 			}
 		},
 		refresh: function() {
-			xhr.post("backend.php", { op: "pref-prefs" }, (reply) => {
+			xhr.post("backend.php", { op: "Pref_Prefs" }, (reply) => {
 				dijit.byId('prefsTab').attr('content', reply);
 				Notify.close();
 			});
@@ -360,7 +360,7 @@ const	Helpers = {
 			this.render_contents();
 		},
 		reload: function() {
-			xhr.json("backend.php", {op: "pref-prefs", method: "getPluginsList"}, (reply) => {
+			xhr.json("backend.php", {op: "Pref_Prefs", method: "getPluginsList"}, (reply) => {
 				this._list_of_plugins = reply;
 				this.render_contents();
 			}, (e) => {
@@ -444,7 +444,7 @@ const	Helpers = {
 			if (confirm(__("Clear stored data for %s?").replace("%s", name))) {
 				Notify.progress("Loading, please wait...");
 
-				xhr.post("backend.php", {op: "pref-prefs", method: "clearPluginData", name: name}, () => {
+				xhr.post("backend.php", {op: "Pref_Prefs", method: "clearPluginData", name: name}, () => {
 					Helpers.Prefs.refresh();
 				});
 			}
@@ -455,7 +455,7 @@ const	Helpers = {
 			if (confirm(msg)) {
 				Notify.progress("Loading, please wait...");
 
-				xhr.json("backend.php", {op: "pref-prefs", method: "uninstallPlugin", plugin: plugin}, (reply) => {
+				xhr.json("backend.php", {op: "Pref_Prefs", method: "uninstallPlugin", plugin: plugin}, (reply) => {
 					if (reply && reply.status == 1)
 						Helpers.Plugins.reload();
 					else {
@@ -504,7 +504,7 @@ const	Helpers = {
 
 						const container = install_dialog.domNode.querySelector(".contents");
 
-						xhr.json("backend.php", {op: "pref-prefs", method: "installPlugin", plugin: plugin}, (reply) => {
+						xhr.json("backend.php", {op: "Pref_Prefs", method: "installPlugin", plugin: plugin}, (reply) => {
 							if (!reply) {
 								container.innerHTML = `<li class='text-center text-error'>${__("Operation failed: check event log.")}</li>`;
 							} else {
@@ -603,7 +603,7 @@ const	Helpers = {
 					const container = dialog.domNode.querySelector(".contents");
 					container.innerHTML = `<li class='text-center'>${__("Looking for plugins...")}</li>`;
 
-					xhr.json("backend.php", {op: "pref-prefs", method: "getAvailablePlugins"}, (reply) => {
+					xhr.json("backend.php", {op: "Pref_Prefs", method: "getAvailablePlugins"}, (reply) => {
 						dialog.entries = reply;
 						dialog.render_contents();
 					});
@@ -656,7 +656,7 @@ const	Helpers = {
 					container.innerHTML = `<li class='text-center'>${__("Updating, please wait...")}</li>`;
 					let enable_update_btn = false;
 
-					xhr.json("backend.php", {op: "pref-prefs", method: "updateLocalPlugins", plugins: dialog.plugins_to_update.join(",")}, (reply) => {
+					xhr.json("backend.php", {op: "Pref_Prefs", method: "updateLocalPlugins", plugins: dialog.plugins_to_update.join(",")}, (reply) => {
 
 						if (!reply) {
 							container.innerHTML = `<li class='text-center text-error'>${__("Operation failed: check event log.")}</li>`;
@@ -717,7 +717,7 @@ const	Helpers = {
 
 					//container.innerHTML = `<li class='text-center'>${__("Checking: %s...").replace("%s", name)}</li>`;
 
-					xhr.json("backend.php", {op: "pref-prefs", method: "checkForPluginUpdates", name: name}, (reply) => {
+					xhr.json("backend.php", {op: "Pref_Prefs", method: "checkForPluginUpdates", name: name}, (reply) => {
 
 						if (!reply) {
 							container.innerHTML += `<li class='text-error'>${__("%s: Operation failed: check event log.").replace("%s", name)}</li>`;
@@ -834,7 +834,7 @@ const	Helpers = {
 		},
 		export: function() {
 			console.log("export");
-			window.open("backend.php?op=opml&method=export&" + dojo.formToQuery("opmlExportForm"));
+			window.open("backend.php?op=OPML&method=export&" + dojo.formToQuery("opmlExportForm"));
 		},
 	}
 };
diff --git a/js/PrefLabelTree.js b/js/PrefLabelTree.js
index 39e3f83153ae903464e1126e3a2f17b72fdac076..582e5a9b92f52fbabc80272d9ef6162907da3cac 100644
--- a/js/PrefLabelTree.js
+++ b/js/PrefLabelTree.js
@@ -55,13 +55,13 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f
 			return rv;
 		},
 		reload: function() {
-			xhr.post("backend.php", { op: "pref-labels" }, (reply) => {
+			xhr.post("backend.php", { op: "Pref_Labels" }, (reply) => {
 				dijit.byId('labelsTab').attr('content', reply);
 				Notify.close();
 			});
 		},
 		editLabel: function(id) {
-			xhr.json("backend.php", {op: "pref-labels", method: "edit", id: id}, (reply) => {
+			xhr.json("backend.php", {op: "Pref_Labels", method: "edit", id: id}, (reply) => {
 
 				const fg_color = reply['fg_color'];
 				const bg_color = reply['bg_color'] ? reply['bg_color'] : '#fff7d5';
@@ -91,7 +91,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f
 						}
 
 						const query = {
-							op: "pref-labels", method: "colorset", kind: kind,
+							op: "Pref_Labels", method: "colorset", kind: kind,
 							ids: id, fg: fg, bg: bg, color: color
 						};
 
@@ -131,7 +131,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f
 						</section>
 
 						${App.FormFields.hidden_tag('id', id)}
-						${App.FormFields.hidden_tag('op', 'pref-labels')}
+						${App.FormFields.hidden_tag('op', 'Pref_Labels')}
 						${App.FormFields.hidden_tag('method', 'save')}
 
 						${App.FormFields.hidden_tag('fg_color', fg_color, {}, 'labelEdit_fgColor')}
@@ -189,7 +189,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f
 				if (confirm(__("Reset selected labels to default colors?"))) {
 
 					const query = {
-						op: "pref-labels", method: "colorreset",
+						op: "Pref_Labels", method: "colorreset",
 						ids: labels.toString()
 					};
 
@@ -210,7 +210,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f
 					Notify.progress("Removing selected labels...");
 
 					const query = {
-						op: "pref-labels", method: "remove",
+						op: "Pref_Labels", method: "remove",
 						ids: sel_rows.toString()
 					};
 
diff --git a/js/PrefUsers.js b/js/PrefUsers.js
index a6081f35f62a59923e694550191296053fe415c8..e8f4a7489a718f5c50131fc80e861891c6d41c7c 100644
--- a/js/PrefUsers.js
+++ b/js/PrefUsers.js
@@ -8,7 +8,7 @@ const	Users = {
 			const user_search = App.byId("user_search");
 			const search = user_search ? user_search.value : "";
 
-			xhr.post("backend.php", { op: "pref-users", sort: sort, search: search }, (reply) => {
+			xhr.post("backend.php", { op: "Pref_Users", sort: sort, search: search }, (reply) => {
 				dijit.byId('usersTab').attr('content', reply);
 				Notify.close();
 				resolve();
@@ -21,7 +21,7 @@ const	Users = {
 		if (login) {
 			Notify.progress("Adding user...");
 
-			xhr.post("backend.php", {op: "pref-users", method: "add", login: login}, (reply) => {
+			xhr.post("backend.php", {op: "Pref_Users", method: "add", login: login}, (reply) => {
 				Users.reload().then(() => {
 					Notify.info(reply);
 				})
@@ -30,7 +30,7 @@ const	Users = {
 		}
 	},
 	edit: function(id) {
-		xhr.json('backend.php', {op: 'pref-users', method: 'edit', id: id}, (reply) => {
+		xhr.json('backend.php', {op: 'Pref_Users', method: 'edit', id: id}, (reply) => {
 			const user = reply.user;
 			const admin_disabled = (user.id == 1);
 
@@ -53,7 +53,7 @@ const	Users = {
 					<form onsubmit='return false'>
 
 						${App.FormFields.hidden_tag('id', user.id.toString())}
-						${App.FormFields.hidden_tag('op', 'pref-users')}
+						${App.FormFields.hidden_tag('op', 'Pref_Users')}
 						${App.FormFields.hidden_tag('method', 'editSave')}
 
 						<div dojoType="dijit.layout.TabContainer" style="height : 400px">
@@ -104,7 +104,7 @@ const	Users = {
 							<div dojoType="dijit.layout.ContentPane" title="${__('User details')}">
 								<script type='dojo/method' event='onShow' args='evt'>
 									if (this.domNode.querySelector('.loading')) {
-										xhr.post("backend.php", {op: 'pref-users', method: 'userdetails', id: ${user.id}}, (reply) => {
+										xhr.post("backend.php", {op: 'Pref_Users', method: 'userdetails', id: ${user.id}}, (reply) => {
 											this.attr('content', reply);
 										});
 									}
@@ -147,7 +147,7 @@ const	Users = {
 
 			const id = rows[0];
 
-			xhr.post("backend.php", {op: "pref-users", method: "resetPass", id: id}, (reply) => {
+			xhr.post("backend.php", {op: "Pref_Users", method: "resetPass", id: id}, (reply) => {
 				Notify.close();
 				Notify.info(reply, true);
 			});
@@ -162,7 +162,7 @@ const	Users = {
 				Notify.progress("Removing selected users...");
 
 				const query = {
-					op: "pref-users", method: "remove",
+					op: "Pref_Users", method: "remove",
 					ids: sel_rows.toString()
 				};
 
diff --git a/prefs.php b/prefs.php
index 0a944e7122398b70138668887cf92034a41fa780..2c53443bab09d4436f5a013b46807edfd034c8af 100644
--- a/prefs.php
+++ b/prefs.php
@@ -142,26 +142,26 @@
 <div id="main" dojoType="dijit.layout.BorderContainer">
     <div dojoType="dijit.layout.TabContainer" region="center" id="pref-tabs">
         <div id="prefsTab" dojoType="dijit.layout.ContentPane"
-            href="backend.php?op=pref-prefs"
+            href="backend.php?op=Pref_Prefs"
             title="<i class='material-icons'>settings</i> <?= __('Preferences') ?>"></div>
         <div id="feedsTab" dojoType="dijit.layout.ContentPane"
-            href="backend.php?op=pref-feeds"
+            href="backend.php?op=Pref_Feeds"
             title="<i class='material-icons'>rss_feed</i>  <?= __('Feeds') ?>"></div>
         <div id="filtersTab" dojoType="dijit.layout.ContentPane"
             style="padding : 0px"
-            href="backend.php?op=pref-filters"
+            href="backend.php?op=Pref_Filters"
             title="<i class='material-icons'>filter_list1</i> <?= __('Filters') ?>"></div>
         <div id="labelsTab" dojoType="dijit.layout.ContentPane"
             style="padding : 0px"
-            href="backend.php?op=pref-labels"
+            href="backend.php?op=Pref_Labels"
             title="<i class='material-icons'>label_outline1</i> <?= __('Labels') ?>"></div>
         <?php if ($_SESSION["access_level"] >= UserHelper::ACCESS_LEVEL_ADMIN) { ?>
             <div id="usersTab" dojoType="dijit.layout.ContentPane"
                 style="padding : 0px"
-                href="backend.php?op=pref-users"
+                href="backend.php?op=Pref_Users"
                 title="<i class='material-icons'>person</i> <?= __('Users') ?>"></div>
             <div id="systemTab" dojoType="dijit.layout.ContentPane"
-                href="backend.php?op=pref-system"
+                href="backend.php?op=Pref_System"
                 title="<i class='material-icons'>info_outline</i> <?= __('System') ?>"></div>
         <?php } ?>
         <?php
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
index f3e3323499ba06cb5692aa3c527cb86428636e90..b2097d7a5efcfee57860bee91564e670222097ba 100644
--- a/vendor/composer/autoload_psr4.php
+++ b/vendor/composer/autoload_psr4.php
@@ -41,4 +41,5 @@ return array(
     'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'),
     'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'),
     'Assert\\' => array($vendorDir . '/beberlei/assert/lib/Assert'),
+    '' => array($baseDir . '/classes'),
 );
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
index dc6a806c60793b669920b27000c49761a814c3dc..ea20e0e094bfd2e1fcc1139ab66f8b52ccdc05e8 100644
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -331,6 +331,10 @@ class ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056
         ),
     );
 
+    public static $fallbackDirsPsr4 = array (
+        0 => __DIR__ . '/../..' . '/classes',
+    );
+
     public static $classMap = array (
         'AllowDynamicProperties' => __DIR__ . '/..' . '/symfony/polyfill-php82/Resources/stubs/AllowDynamicProperties.php',
         'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
@@ -1071,6 +1075,7 @@ class ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056
         return \Closure::bind(function () use ($loader) {
             $loader->prefixLengthsPsr4 = ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056::$prefixLengthsPsr4;
             $loader->prefixDirsPsr4 = ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056::$prefixDirsPsr4;
+            $loader->fallbackDirsPsr4 = ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056::$fallbackDirsPsr4;
             $loader->classMap = ComposerStaticInit19fc2ff1c0f9a92279c7979386bb2056::$classMap;
 
         }, null, ClassLoader::class);