diff --git a/bulktestall.php b/bulktestall.php
index 0077387d289248f57a40b453c65a481bd46b298d..a15c31c5d7fd4f4989ec44bc3daccf6702b18714 100644
--- a/bulktestall.php
+++ b/bulktestall.php
@@ -48,6 +48,8 @@ $PAGE->set_context($context);
 $title = stack_string('bulktesttitle', $context->get_context_name());
 $PAGE->set_title($title);
 
+require_login();
+
 // Create the helper class.
 $bulktester = new stack_bulk_tester();
 $allpassed = true;
diff --git a/bulktestindex.php b/bulktestindex.php
index e28964e1024bfaa7e174aaa41f7398a3c409ef5e..dcdd2fbe297350d57e7d25c4fe1ea456bc5d92ae 100644
--- a/bulktestindex.php
+++ b/bulktestindex.php
@@ -40,6 +40,8 @@ $PAGE->set_url('/question/type/stack/bulktestindex.php');
 $PAGE->set_context($context);
 $PAGE->set_title(stack_string('bulktestindextitle'));
 
+require_login();
+
 // Create the helper class.
 $bulktester = new stack_bulk_tester();
 
diff --git a/deploy.php b/deploy.php
index 2522962b3ec0851c6efcd27d66a1cd6e750fffb7..079c1c0d71754268be8dd1a14d2362a6fb52eae3 100644
--- a/deploy.php
+++ b/deploy.php
@@ -46,6 +46,8 @@ $PAGE->set_url($nexturl); // Since this script always ends in a redirect.
 $PAGE->set_heading($COURSE->fullname);
 $PAGE->set_pagelayout('admin');
 
+require_login();
+
 // Process deploy if applicable.
 $deploy = optional_param('deploy', null, PARAM_INT);
 if (!is_null($deploy)) {
diff --git a/equivdemo.php b/equivdemo.php
index 18b5b7683cffc2035ed56dc3a031d247c4a0ddb2..a5a0f621a1bb0bfda53343f2447659d9b4c6cf90 100644
--- a/equivdemo.php
+++ b/equivdemo.php
@@ -61,6 +61,8 @@ $PAGE->set_url('/question/type/stack/equivdemo.php', $urlparams);
 $title = "Equivalence reasoning test cases";
 $PAGE->set_title($title);
 
+require_login();
+
 echo $OUTPUT->header();
 echo $OUTPUT->heading($title);
 
diff --git a/exportone.php b/exportone.php
index cf23d80a8ad72c4f5d85c9df487e5dfe51e1a207..20496aa9a2909b1b79229facec333e42ec5a53c9 100644
--- a/exportone.php
+++ b/exportone.php
@@ -50,6 +50,8 @@ $PAGE->set_url($nexturl); // Since this script always ends in a redirect.
 $PAGE->set_heading($COURSE->fullname);
 $PAGE->set_pagelayout('admin');
 
+require_login();
+
 // Set up the export format.
 $qformat = new qformat_xml();
 $filename = question_default_export_filename($COURSE, $questiondata) .
diff --git a/lang/en/qtype_stack.php b/lang/en/qtype_stack.php
index 68b258351eade5257fe54617263807e799f95773..a9c6091ba47860b6dad9ead602b12a1796ceed38 100644
--- a/lang/en/qtype_stack.php
+++ b/lang/en/qtype_stack.php
@@ -702,6 +702,7 @@ $string['stackOptions_AnsTest_values_NumRelative']         = "NumRelative";
 $string['stackOptions_AnsTest_values_NumAbsolute']         = "NumAbsolute";
 $string['stackOptions_AnsTest_values_NumSigFigs']          = "NumSigFigs";
 $string['stackOptions_AnsTest_values_NumDecPlaces']        = "NumDecPlaces";
+$string['stackOptions_AnsTest_values_NumDecPlacesWrong']   = "NumDecPlacesWrong";
 $string['stackOptions_AnsTest_values_UnitsSigFigs']        = "UnitsSigFigs";
 $string['stackOptions_AnsTest_values_UnitsStrictSigFigs']  = "UnitsStrictSigFigs";
 $string['stackOptions_AnsTest_values_UnitsRelative']       = "UnitsRelative";
@@ -831,7 +832,7 @@ $string['ATNumDecPlaces_OptNotInt']    = 'For ATNumDecPlaces the test option mus
 $string['ATNumDecPlaces_NoDP']         = 'Your answer must be a decimal number, including a decimal point. ';
 $string['ATNumDecPlaces_Wrong_DPs']    = 'Your answer has been given to the wrong number of decimal places.';
 
-$string['ATNumDecPlacesWrong_OptNotInt']    = 'For ATNumDecPlacesWrong the test option must be a positive integer, in fact "{$a->opt}" was received. ';
+$string['ATNumDecPlacesWrong_OptNotInt']    = 'For ATNumDecPlacesWrong the test option must be a positive integer, in fact "{$a->opt}" was received. ';
 
 $string['ATSysEquiv_SA_not_list']               = 'Your answer should be a list, but it is not!';
 $string['ATSysEquiv_SB_not_list']               = 'The teacher\'s answer is not a list.  Please contact your teacher.';
diff --git a/questiontestdelete.php b/questiontestdelete.php
index 568ba6118ea2fbaa2f2ab6d80591fda73faa712f..d8a54d8b4b6ef93648532f804a30d9a6c2a722c2 100644
--- a/questiontestdelete.php
+++ b/questiontestdelete.php
@@ -52,6 +52,8 @@ $PAGE->set_url('/question/type/stack/questiontestdelete.php', $urlparams);
 $title = stack_string('deletetestcase',
         array('no' => $testcase, 'question' => format_string($question->name)));
 
+require_login();
+
 if (data_submitted() && confirm_sesskey()) {
     // User has confirmed. Actually delete the test case.
     question_bank::get_qtype('stack')->delete_question_test($questionid, $testcase);
diff --git a/questiontestedit.php b/questiontestedit.php
index 0388d83c99887e091ae75bcfa754584899bb4e5b..34617ef7c7218b29bc69270043687eab4c1410e2 100644
--- a/questiontestedit.php
+++ b/questiontestedit.php
@@ -65,6 +65,9 @@ $PAGE->set_url('/question/type/stack/questiontestedit.php', $urlparams);
 $PAGE->set_title($title);
 $PAGE->set_heading($title);
 $PAGE->set_pagelayout('popup');
+
+require_login();
+
 // Create the question usage we will use.
 $quba = question_engine::make_questions_usage_by_activity('qtype_stack', $context);
 $quba->set_preferred_behaviour('adaptive');
diff --git a/questiontestrun.php b/questiontestrun.php
index 8a022df5943f5645d06300f5ba93ba198bbebd69..8a256bdd0b967027f90d76dddae2c5dc5ca5193b 100644
--- a/questiontestrun.php
+++ b/questiontestrun.php
@@ -62,6 +62,8 @@ $PAGE->set_title($title);
 $PAGE->set_heading($title);
 $PAGE->set_pagelayout('popup');
 
+require_login();
+
 // Create some other useful links.
 $qbankparams = $urlparams;
 unset($qbankparams['questionid']);
diff --git a/stack/answertest/atdecplaceswrong.class.php b/stack/answertest/atdecplaceswrong.class.php
index 898856902f5e7cff9ce57ac5277b970fe127e69e..0427dce5605b5d3e72fd5971aee9459b66907630 100644
--- a/stack/answertest/atdecplaceswrong.class.php
+++ b/stack/answertest/atdecplaceswrong.class.php
@@ -60,8 +60,8 @@ class stack_anstest_atdecplaceswrong extends stack_anstest {
         $cascommands[] = "caschat0:{$this->sanskey}";
         $cascommands[] = "caschat1:{$this->tanskey}";
         $cascommands[] = "caschat2:ev({$this->atoption},simp)";
-        $cascommands[] = "caschat3:numberp({$this->sanskey})";
-        $cascommands[] = "caschat4:numberp({$this->tanskey})";
+        $cascommands[] = "caschat3:numberp({$this->sanskey})";
+        $cascommands[] = "caschat4:numberp({$this->tanskey})";
 
         $cts = array();
         foreach ($cascommands as $com) {
@@ -103,15 +103,15 @@ class stack_anstest_atdecplaceswrong extends stack_anstest {
             return null;
         }
 
-        if ('' != $session->get_errors_key('caschat3')) {
-            $this->aterror      = 'TEST_FAILED';
-            $this->atfeedback  .= stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('caschat3')));
-            $anotes[]           = 'ATNumDecPlacesWrong_ERR_sansnum';
-            $this->atansnote    = implode('. ', $anotes).'.';
-            $this->atmark       = 0;
-            $this->atvalid      = false;
-            return null;
-        }
+        if ('' != $session->get_errors_key('caschat3')) {
+            $this->aterror      = 'TEST_FAILED';
+            $this->atfeedback  .= stack_string('TEST_FAILED', array('errors' => $session->get_errors_key('caschat3')));
+            $anotes[]           = 'ATNumDecPlacesWrong_ERR_sansnum';
+            $this->atansnote    = implode('. ', $anotes).'.';
+            $this->atmark       = 0;
+            $this->atvalid      = false;
+            return null;
+        }
 
         if ('' != $session->get_errors_key('caschat4')) {
             $this->aterror      = 'TEST_FAILED';
@@ -124,13 +124,13 @@ class stack_anstest_atdecplaceswrong extends stack_anstest {
         }
 
         // These should not throw an error. The test just returns false.
-        if ('false' === $session->get_value_key('caschat3')) {
-            $anotes[]           = 'ATNumDecPlacesWrong_Sans_Not_Num';
-            $this->atansnote    = implode('. ', $anotes).'.';
-            $this->atmark       = 0;
-            $this->atvalid      = false;
-            return null;
-        }
+        if ('false' === $session->get_value_key('caschat3')) {
+            $anotes[]           = 'ATNumDecPlacesWrong_Sans_Not_Num';
+            $this->atansnote    = implode('. ', $anotes).'.';
+            $this->atmark       = 0;
+            $this->atvalid      = false;
+            return null;
+        }
 
         if ('false' === $session->get_value_key('caschat4')) {
             $anotes[]           = 'ATNumDecPlacesWrong_Tans_Not_Num';
@@ -147,16 +147,16 @@ class stack_anstest_atdecplaceswrong extends stack_anstest {
 
         // Ignore the decimal point by eliminating it.
         $sa = str_replace('.', '', $sa);
-        $ta = str_replace('.', '', $ta);
+        $ta = str_replace('.', '', $ta);
 
         // Remove any leading zeros.
         $sa = substr($sa, strcspn($sa, '123456789'));
         $ta = substr($ta, strcspn($ta, '123456789'));
-
+
         // Add sufficient trailing zeros.
         // This condones any lack of trailing zeros (for this test).
         $sa .= str_repeat('0', (int) $ndps);
-        $ta .= str_repeat('0', (int) $ndps);
+        $ta .= str_repeat('0', (int) $ndps);
 
         $sa = substr($sa, 0, (int) $ndps);
         $ta = substr($ta, 0, (int) $ndps);
diff --git a/stack/bulktester.class.php b/stack/bulktester.class.php
index 84b14a2793c2b3a4e481b651e0023a99662fe3b8..ae91bc848e48ee8111a1037a4c159cb687119b33 100644
--- a/stack/bulktester.class.php
+++ b/stack/bulktester.class.php
@@ -19,6 +19,8 @@
 // @copyright  2015 The Open University.
 // @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
 
+defined('MOODLE_INTERNAL') || die();
+
 class stack_bulk_tester  {
 
     /**
diff --git a/stack/cas/installhelper.class.php b/stack/cas/installhelper.class.php
index e1154170d4a46cbf9b177700318aebcf2296032e..67dff239c90092c6f9f7cab4820ff4a9637f7f18 100644
--- a/stack/cas/installhelper.class.php
+++ b/stack/cas/installhelper.class.php
@@ -16,9 +16,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-// The file provides helper code for creating the files needed to connect to the CAS.
-
-require_once(__DIR__.'/../../../../../config.php');
+// This provides helper code for creating the files needed to connect to the CAS.
 
 require_once(__DIR__ . '/../../locallib.php');
 require_once(__DIR__ . '/../utils.class.php');
diff --git a/tests/behat/behat_qtype_stack.php b/tests/behat/behat_qtype_stack.php
index 950b637ea3102b96853d743727f57166a75ba8d5..aa5936065215b62fa583e4b8a493eef020a12348 100644
--- a/tests/behat/behat_qtype_stack.php
+++ b/tests/behat/behat_qtype_stack.php
@@ -46,7 +46,7 @@ class behat_qtype_stack extends behat_base {
      *
      * @When /^I set up STACK using the PHPUnit configuration$/
      */
-    public function iSetUpStackUsingThePhpunitConfiguration() {
+    public function isetupstackusingthephpunitconfiguration() {
         // The require_once is here, this file may be required by behat before including /config.php.
         require_once(__DIR__ . '/../fixtures/test_maxima_configuration.php');
 
diff --git a/tests/input_textarea_test.php b/tests/input_textarea_test.php
index a3cb51d6a14739df158a8d9a30ecbb4b02297f47..a3098716f3edde6f66186d3b194ba432297d7424 100644
--- a/tests/input_textarea_test.php
+++ b/tests/input_textarea_test.php
@@ -179,6 +179,7 @@ class stack_textarea_input_test extends qtype_stack_testcase {
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class testable_stack_textarea_input extends stack_textarea_input {
+    // @codingStandardsIgnoreLine
     public function tokenize_list($in) {
         return parent::tokenize_list($in);
     }
diff --git a/tests/multilang_test.php b/tests/multilang_test.php
index 30ca7def01e9e61bc507d5cb85f16af1d305248f..524c154c52bd018246aaea7f8c02366195cb8c6f 100644
--- a/tests/multilang_test.php
+++ b/tests/multilang_test.php
@@ -21,8 +21,8 @@ require_once(__DIR__ . '/../lang/multilang.php');
 
 // Unit tests for stack_multilang.
 //
-// @copyright  2018 The University of Edinburgh
-// @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+// @copyright  2018 The University of Edinburgh.
+// @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
 
 /**
  * @group qtype_stack
diff --git a/tests/parser_test.php b/tests/parser_test.php
index f4f6389e8b667dde4a65960fbdf90c4539dbd017..f6fc8140557e241f3d888cf4fa4481ef7cc85b78 100644
--- a/tests/parser_test.php
+++ b/tests/parser_test.php
@@ -14,6 +14,8 @@
 // You should have received a copy of the GNU General Public License
 // along with Stack.  If not, see <http://www.gnu.org/licenses/>.
 
+defined('MOODLE_INTERNAL') || die();
+
 require_once(__DIR__ . '/../locallib.php');
 require_once(__DIR__ . '/fixtures/test_base.php');
 require_once(__DIR__ . '/../stack/cas/castext/castextparser.class.php');
diff --git a/tests/restore_logic_test.php b/tests/restore_logic_test.php
index bda993d9088fa6ce47dd55f8e20a06cc0a61d785..2711c3242a188888577a29c286606cbcb97b9526 100644
--- a/tests/restore_logic_test.php
+++ b/tests/restore_logic_test.php
@@ -65,6 +65,7 @@ class testable_restore_qtype_stack_plugin extends restore_qtype_stack_plugin {
         return $this->log;
     }
 
+    // @codingStandardsIgnoreLine
     public function after_execute_question() {
         // Make method public.
         parent::after_execute_question();
diff --git a/thirdpartylibs.xml b/thirdpartylibs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..41864283b9750a9b5f7a67a75613b774c63b567a
--- /dev/null
+++ b/thirdpartylibs.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0"?>
+<libraries>
+    <library>
+        <location>amd</location>
+        <name>JSXGraph</name>
+        <version>?</version>
+        <license>GNU LGPL or MIT License</license>
+    </library>
+    <library>
+        <location>thirdparty/php-peg</location>
+        <name>PHP-PEG</name>
+        <version>2.0.0</version>
+        <license>MIT, BSD, and GPL</license>
+    </library>
+    <library>
+        <location>stack/cas/castext/</location>
+        <name>PHP-PEG autogenerated PHP files</name>
+        <version>As for STACK</version>
+        <license>GPL</license>
+    </library>
+</libraries>
+
+
+
+
diff --git a/tidyquestion.php b/tidyquestion.php
index 4f323b0bfdf7f4f64be1af430db96e76aee1cca8..558b793fcfba9204de028689ebd770d52fa97f7d 100644
--- a/tidyquestion.php
+++ b/tidyquestion.php
@@ -49,6 +49,8 @@ $PAGE->set_title($title);
 $PAGE->set_heading($COURSE->fullname);
 $PAGE->set_pagelayout('admin');
 
+require_login();
+
 // The URL back to the preview page.
 $returnurl = question_preview_url($questionid, null, null, null, null, $context);