Merge branch 'MDL-49533-master' of git://github.com/andrewnicols/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 26 Jul 2016 08:40:17 +0000 (09:40 +0100)
committerDan Poltawski <dan@moodle.com>
Tue, 26 Jul 2016 08:40:17 +0000 (09:40 +0100)
199 files changed:
.eslintignore
admin/searchareas.php
admin/tool/cohortroles/tests/api_test.php
admin/tool/langimport/tests/events_test.php
admin/tool/messageinbound/classes/manager.php
admin/tool/monitor/tests/generator_test.php
admin/tool/monitor/tests/subscription_test.php
admin/tool/uploadcourse/tests/course_test.php
admin/tool/uploadcourse/tests/processor_test.php
backup/converter/moodle1/tests/moodle1_converter_test.php
backup/util/xml/parser/tests/parser_test.php
calendar/tests/externallib_test.php
calendar/tests/ical_test.php
calendar/tests/rrule_manager_tests.php
cohort/tests/cohortlib_test.php
cohort/tests/externallib_test.php
competency/tests/api_test.php
competency/tests/course_competency_settings_test.php
competency/tests/event_test.php
competency/tests/exporter_test.php
competency/tests/external_test.php
competency/tests/persistent_test.php
competency/tests/plan_test.php
composer.json
composer.lock
course/tests/externallib_test.php
enrol/tests/externallib_test.php
enrol/tests/role_external_test.php
files/tests/externallib_test.php
grade/grading/tests/grading_manager_test.php
group/tests/externallib_test.php
lang/en/moodle.php
lang/en/search.php
lib/amd/build/chart_axis.min.js [new file with mode: 0644]
lib/amd/build/chart_bar.min.js [new file with mode: 0644]
lib/amd/build/chart_base.min.js [new file with mode: 0644]
lib/amd/build/chart_builder.min.js [new file with mode: 0644]
lib/amd/build/chart_line.min.js [new file with mode: 0644]
lib/amd/build/chart_output.min.js [new file with mode: 0644]
lib/amd/build/chart_output_base.min.js [new file with mode: 0644]
lib/amd/build/chart_output_chartjs.min.js [new file with mode: 0644]
lib/amd/build/chart_output_htmltable.min.js [new file with mode: 0644]
lib/amd/build/chart_pie.min.js [new file with mode: 0644]
lib/amd/build/chart_series.min.js [new file with mode: 0644]
lib/amd/build/chartjs-lazy.min.js [new file with mode: 0644]
lib/amd/build/chartjs.min.js [new file with mode: 0644]
lib/amd/build/event.min.js
lib/amd/src/chart_axis.js [new file with mode: 0644]
lib/amd/src/chart_bar.js [new file with mode: 0644]
lib/amd/src/chart_base.js [new file with mode: 0644]
lib/amd/src/chart_builder.js [new file with mode: 0644]
lib/amd/src/chart_line.js [new file with mode: 0644]
lib/amd/src/chart_output.js [new file with mode: 0644]
lib/amd/src/chart_output_base.js [new file with mode: 0644]
lib/amd/src/chart_output_chartjs.js [new file with mode: 0644]
lib/amd/src/chart_output_htmltable.js [new file with mode: 0644]
lib/amd/src/chart_pie.js [new file with mode: 0644]
lib/amd/src/chart_series.js [new file with mode: 0644]
lib/amd/src/chartjs-lazy.js [new file with mode: 0644]
lib/amd/src/chartjs.js [new file with mode: 0644]
lib/amd/src/event.js
lib/classes/chart_axis.php [new file with mode: 0644]
lib/classes/chart_bar.php [new file with mode: 0644]
lib/classes/chart_base.php [new file with mode: 0644]
lib/classes/chart_line.php [new file with mode: 0644]
lib/classes/chart_pie.php [new file with mode: 0644]
lib/classes/chart_series.php [new file with mode: 0644]
lib/classes/event/dashboard_reset.php [new file with mode: 0644]
lib/classes/event/dashboard_viewed.php [new file with mode: 0644]
lib/classes/event/dashboards_reset.php [new file with mode: 0644]
lib/classes/requirejs.php
lib/deprecatedlib.php
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/autosave.js
lib/editor/atto/yui/src/editor/meta/editor.json
lib/external/tests/external_test.php
lib/filestorage/tests/file_storage_test.php
lib/modinfolib.php
lib/outputrenderers.php
lib/phpunit/classes/base_testcase.php
lib/phpunit/classes/unittestcase.php [deleted file]
lib/phpunit/lib.php
lib/phpunit/phpunit.xsd
lib/phpunit/tests/advanced_test.php
lib/templates/chart.mustache [new file with mode: 0644]
lib/testing/tests/generator_test.php
lib/tests/ajaxlib_test.php
lib/tests/completionlib_test.php
lib/tests/externallib_test.php
lib/tests/grading_externallib_test.php
lib/tests/modinfolib_test.php
lib/tests/moodle_page_test.php
lib/tests/outputrequirementslib_test.php
lib/tests/setuplib_test.php
lib/tests/update_checker_test.php
lib/tests/update_code_manager_test.php
lib/tests/user_test.php
lib/tests/weblib_test.php
lib/thirdpartylibs.xml
lib/upgrade.txt
lib/yui/build/moodle-core-event/moodle-core-event-debug.js
lib/yui/build/moodle-core-event/moodle-core-event-min.js
lib/yui/build/moodle-core-event/moodle-core-event.js
lib/yui/build/moodle-core-formchangechecker/moodle-core-formchangechecker-debug.js
lib/yui/build/moodle-core-formchangechecker/moodle-core-formchangechecker-min.js
lib/yui/build/moodle-core-formchangechecker/moodle-core-formchangechecker.js
lib/yui/src/event/js/event.js
lib/yui/src/formchangechecker/js/formchangechecker.js
lib/yui/src/formchangechecker/meta/formchangechecker.json
message/tests/externallib_test.php
mod/assign/amd/build/grading_panel.min.js
mod/assign/amd/src/grading_panel.js
mod/assign/externallib.php
mod/assign/tests/externallib_test.php
mod/assign/tests/locallib_test.php
mod/chat/db/access.php
mod/chat/lang/en/chat.php
mod/chat/lib.php
mod/chat/locallib.php
mod/chat/version.php
mod/choice/lib.php
mod/choice/renderer.php
mod/choice/tests/events_test.php
mod/choice/tests/lib_test.php
mod/data/db/access.php
mod/data/lang/en/data.php
mod/data/lib.php
mod/data/locallib.php
mod/data/rsslib.php
mod/data/version.php
mod/feedback/analysis.php
mod/feedback/item/info/lib.php
mod/feedback/item/multichoice/lib.php
mod/feedback/item/multichoicerated/lib.php
mod/feedback/item/numeric/lib.php
mod/feedback/item/textarea/lib.php
mod/feedback/item/textfield/lib.php
mod/forum/tests/events_test.php
mod/forum/tests/lib_test.php
mod/forum/tests/maildigest_test.php
mod/glossary/tests/external_test.php
mod/lti/templates/tool_proxy_registration_form.mustache
mod/lti/tests/externallib_test.php
mod/quiz/renderer.php
mod/quiz/report/overview/overviewgraph.php
mod/quiz/report/overview/report.php
mod/quiz/report/overview/tests/report_test.php
mod/quiz/report/statistics/report.php
mod/quiz/report/statistics/statistics_graph.php
mod/quiz/report/statistics/statisticslib.php
mod/quiz/report/statistics/upgrade.txt [new file with mode: 0644]
mod/quiz/tests/structure_test.php
mod/scorm/report/graphs/classes/report.php
mod/scorm/report/graphs/graph.php
mod/scorm/tests/events_test.php
mod/scorm/tests/externallib_test.php
mod/scorm/tests/lib_test.php
mod/wiki/tests/externallib_test.php
mod/workshop/allocation/random/tests/allocator_test.php
mod/workshop/form/accumulative/tests/lib_test.php
mod/workshop/tests/locallib_test.php
my/index.php
my/lib.php
my/tests/events_test.php [new file with mode: 0644]
notes/tests/externallib_test.php
phpunit.xml.dist
question/behaviour/informationitem/tests/walkthrough_test.php
question/behaviour/manualgraded/tests/walkthrough_test.php
question/behaviour/missing/tests/missingbehaviour_test.php
question/engine/tests/questionattempt_with_steps_test.php
question/engine/tests/questionattemptiterator_test.php
question/engine/tests/questionattemptstep_test.php
question/engine/tests/questionattemptstepiterator_test.php
question/engine/tests/questionengine_test.php
question/engine/tests/questionusage_autosave_test.php
question/engine/tests/questionusagebyactivity_test.php
question/engine/tests/questionutils_test.php
question/type/calculated/tests/variablesubstituter_test.php
question/type/missingtype/tests/missingtype_test.php
report/courseoverview/index.php
report/courseoverview/locallib.php [new file with mode: 0644]
report/courseoverview/reportsgraph.php
report/log/graph.php
report/log/locallib.php
report/log/user.php
report/stats/graph.php
report/stats/locallib.php
report/stats/user.php
report/upgrade.txt
repository/tests/generator_test.php
search/classes/manager.php
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/style/moodle.css
user/tests/externallib_test.php
user/tests/myprofile_test.php
version.php
webservice/xmlrpc/tests/lib_test.php

index 11819ae..576c8c4 100644 (file)
@@ -48,6 +48,7 @@ lib/mustache/
 lib/amd/src/mustache.js
 lib/graphlib.php
 lib/spout/
+lib/amd/src/chartjs-lazy.js
 mod/assign/feedback/editpdf/fpdi/
 repository/s3/S3.php
 theme/bootstrapbase/less/bootstrap/
index 884d5b8..dcbc7cb 100644 (file)
@@ -95,7 +95,7 @@ if (empty($searchmanagererror)) {
 }
 
 if (!empty($searchmanagererror)) {
-    $errorstr = get_string($searchmanagererror->errorcode, $searchmanagererror->module);
+    $errorstr = get_string($searchmanagererror->errorcode, $searchmanagererror->module, $searchmanagererror->a);
     echo $OUTPUT->notification($errorstr, \core\output\notification::NOTIFY_ERROR);
 } else {
     echo $OUTPUT->notification(get_string('indexinginfo', 'admin'), \core\output\notification::NOTIFY_INFO);
index 27c4cd8..2fa061b 100644 (file)
@@ -62,9 +62,10 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
         cohort_add_member($this->cohort->id, $this->userassignover->id);
     }
 
-
+    /**
+     * @expectedException required_capability_exception
+     */
     public function test_create_cohort_role_assignment_without_permission() {
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->userassignto);
         $params = (object) array(
             'userid' => $this->userassignto->id,
@@ -74,8 +75,10 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
         api::create_cohort_role_assignment($params);
     }
 
+    /**
+     * @expectedException core_competency\invalid_persistent_exception
+     */
     public function test_create_cohort_role_assignment_with_invalid_data() {
-        $this->setExpectedException('core_competency\invalid_persistent_exception');
         $this->setAdminUser();
         $params = (object) array(
             'userid' => $this->userassignto->id,
@@ -99,6 +102,9 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
         $this->assertEquals($result->get_cohortid(), $this->cohort->id);
     }
 
+    /**
+     * @expectedException required_capability_exception
+     */
     public function test_delete_cohort_role_assignment_without_permission() {
         $this->setAdminUser();
         $params = (object) array(
@@ -107,11 +113,13 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
             'cohortid' => $this->cohort->id
         );
         $result = api::create_cohort_role_assignment($params);
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->userassignto);
         api::delete_cohort_role_assignment($result->get_id());
     }
 
+    /**
+     * @expectedException dml_missing_record_exception
+     */
     public function test_delete_cohort_role_assignment_with_invalid_data() {
         $this->setAdminUser();
         $params = (object) array(
@@ -120,7 +128,6 @@ class tool_cohortroles_api_testcase extends advanced_testcase {
             'cohortid' => $this->cohort->id
         );
         $result = api::create_cohort_role_assignment($params);
-        $this->setExpectedException('dml_missing_record_exception');
         api::delete_cohort_role_assignment($result->get_id() + 1);
     }
 
index 0a75b34..d2164cf 100644 (file)
@@ -56,8 +56,11 @@ class tool_langimport_events_testcase extends advanced_testcase {
         $this->assertEquals(context_system::instance(), $event->get_context());
     }
 
+    /**
+     * @expectedException        coding_exception
+     * @expectedExceptionMessage The 'langcode' value must be set to a valid language code
+     */
     public function test_langpack_updated_validation() {
-        $this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
 
         \tool_langimport\event\langpack_updated::event_with_langcode('broken langcode');
     }
@@ -75,8 +78,11 @@ class tool_langimport_events_testcase extends advanced_testcase {
         $this->assertEquals(context_system::instance(), $event->get_context());
     }
 
+    /**
+     * @expectedException        coding_exception
+     * @expectedExceptionMessage The 'langcode' value must be set to a valid language code
+     */
     public function test_langpack_installed_validation() {
-        $this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
 
         \tool_langimport\event\langpack_imported::event_with_langcode('broken langcode');
     }
@@ -94,8 +100,11 @@ class tool_langimport_events_testcase extends advanced_testcase {
         $this->assertEquals(context_system::instance(), $event->get_context());
     }
 
+    /**
+     * @expectedException        coding_exception
+     * @expectedExceptionMessage The 'langcode' value must be set to a valid language code
+     */
     public function test_langpack_removed_validation() {
-        $this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
 
         \tool_langimport\event\langpack_removed::event_with_langcode('broken langcode');
     }
index 8bb57ac..a352f7c 100644 (file)
@@ -103,6 +103,15 @@ class manager {
             'debug'    => empty($CFG->debugimap) ? null : fopen('php://stderr', 'w'),
         );
 
+        if (strpos($configuration['hostspec'], ':')) {
+            $hostdata = explode(':', $configuration['hostspec']);
+            if (count($hostdata) === 2) {
+                // A hostname in the format hostname:port has been provided.
+                $configuration['hostspec'] = $hostdata[0];
+                $configuration['port'] = $hostdata[1];
+            }
+        }
+
         $this->client = new \Horde_Imap_Client_Socket($configuration);
 
         try {
index ca7f003..7c4ae86 100644 (file)
@@ -89,7 +89,7 @@ class tool_monitor_generator_testcase extends advanced_testcase {
         $this->assertEquals(0, $subscription->cmid);
 
         // Make sure rule id is always required.
-        $this->setExpectedException('coding_exception');
+        $this->expectException('coding_exception');
         unset($record->ruleid);
         $monitorgenerator->create_subscription($record);
     }
index 3548c7f..b3511b5 100644 (file)
@@ -42,7 +42,10 @@ class tool_monitor_subscription_testcase extends advanced_testcase {
         $sub->id = 100;
         $sub->name = 'My test rule';
         $sub->courseid = 20;
-        $this->subscription = $this->getMock('\tool_monitor\subscription',null, array($sub));
+        $mockbuilder = $this->getMockBuilder('\tool_monitor\subscription');
+        $mockbuilder->setMethods(null);
+        $mockbuilder->setConstructorArgs(array($sub));
+        $this->subscription = $mockbuilder->getMock();
     }
 
     /**
@@ -56,10 +59,11 @@ class tool_monitor_subscription_testcase extends advanced_testcase {
 
     /**
      * Test for the magic __get method.
+     *
+     * @expectedException coding_exception
      */
     public function test_magic_get() {
         $this->assertEquals(20, $this->subscription->courseid);
-        $this->setExpectedException('coding_exception');
         $this->subscription->ruleid;
     }
 }
index 0b62e87..26dc556 100644 (file)
@@ -35,16 +35,21 @@ global $CFG;
  */
 class tool_uploadcourse_course_testcase extends advanced_testcase {
 
+    /**
+     * @expectedException coding_exception
+     */
     public function test_proceed_without_prepare() {
         $this->resetAfterTest(true);
         $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
         $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
         $data = array();
         $co = new tool_uploadcourse_course($mode, $updatemode, $data);
-        $this->setExpectedException('coding_exception');
         $co->proceed();
     }
 
+    /**
+     * @expectedException moodle_exception
+     */
     public function test_proceed_when_prepare_failed() {
         $this->resetAfterTest(true);
         $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
@@ -52,7 +57,6 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
         $data = array();
         $co = new tool_uploadcourse_course($mode, $updatemode, $data);
         $this->assertFalse($co->prepare());
-        $this->setExpectedException('moodle_exception');
         $co->proceed();
     }
 
@@ -64,7 +68,7 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
         $co = new tool_uploadcourse_course($mode, $updatemode, $data);
         $this->assertTrue($co->prepare());
         $co->proceed();
-        $this->setExpectedException('coding_exception');
+        $this->expectException('coding_exception');
         $co->proceed();
     }
 
index 1dd20dc..109c243 100644 (file)
@@ -160,6 +160,9 @@ class tool_uploadcourse_processor_testcase extends advanced_testcase {
         $this->assertEquals('ID123: Course 1', $c->shortname);
     }
 
+    /**
+     * @expectedException moodle_exception
+     */
     public function test_empty_csv() {
         $this->resetAfterTest(true);
 
@@ -171,10 +174,12 @@ class tool_uploadcourse_processor_testcase extends advanced_testcase {
         $cir->init();
 
         $options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW);
-        $this->setExpectedException('moodle_exception');
         $p = new tool_uploadcourse_processor($cir, $options, array());
     }
 
+    /**
+     * @expectedException moodle_exception
+     */
     public function test_not_enough_columns() {
         $this->resetAfterTest(true);
 
@@ -189,7 +194,6 @@ class tool_uploadcourse_processor_testcase extends advanced_testcase {
         $cir->init();
 
         $options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW);
-        $this->setExpectedException('moodle_exception');
         $p = new tool_uploadcourse_processor($cir, $options, array());
     }
 
index 3209287..88681b8 100644 (file)
@@ -88,18 +88,22 @@ class core_backup_moodle1_converter_testcase extends advanced_testcase {
         $this->assertInstanceOf('moodle1_converter', $converter);
     }
 
+    /**
+     * @expectedException moodle1_convert_storage_exception
+     */
     public function test_stash_storage_not_created() {
         $converter = convert_factory::get_converter('moodle1', $this->tempdir);
-        $this->setExpectedException('moodle1_convert_storage_exception');
         $converter->set_stash('tempinfo', 12);
     }
 
+    /**
+     * @expectedException moodle1_convert_empty_storage_exception
+     */
     public function test_stash_requiring_empty_stash() {
         $this->resetAfterTest(true);
         $converter = convert_factory::get_converter('moodle1', $this->tempdir);
         $converter->create_stash_storage();
         $converter->set_stash('tempinfo', 12);
-        $this->setExpectedException('moodle1_convert_empty_storage_exception');
         try {
             $converter->get_stash('anothertempinfo');
 
@@ -432,6 +436,9 @@ class core_backup_moodle1_converter_testcase extends advanced_testcase {
         $this->assertSame(null, $data['nothing']);
     }
 
+    /**
+     * @expectedException convert_path_exception
+     */
     public function test_grouped_data_on_nongrouped_convert_path() {
         // prepare some grouped data
         $data = array(
@@ -457,10 +464,12 @@ class core_backup_moodle1_converter_testcase extends advanced_testcase {
         $path = new convert_path('beer_style', '/ROOT/BEER_STYLES/BEER_STYLE');
 
         // an attempt to apply recipes throws exception because we do not expect grouped data
-        $this->setExpectedException('convert_path_exception');
         $data = $path->apply_recipes($data);
     }
 
+    /**
+     * @expectedException convert_path_exception
+     */
     public function test_grouped_convert_path_with_recipes() {
         // prepare some grouped data
         $data = array(
@@ -488,7 +497,6 @@ class core_backup_moodle1_converter_testcase extends advanced_testcase {
         $this->assertEquals('Heineken', $data['beers'][1]['beer']['name']);
 
         // an attempt to provide explicit recipes on grouped elements throws exception
-        $this->setExpectedException('convert_path_exception');
         $path = new convert_path(
             'beer_style', '/ROOT/BEER_STYLES/BEER_STYLE',
             array(
@@ -573,7 +581,7 @@ as it is parsed from the backup file. <br /><br /><img border="0" width="110" vs
         $inforef->add_ref('file', 45);
         $inforef->add_refs('file', array(46, 47));
         // todo test the write_refs() via some dummy xml_writer
-        $this->setExpectedException('coding_exception');
+        $this->expectException('coding_exception');
         $inforef->add_ref('unknown_referenced_item_name', 76);
     }
 }
index 39bf2d7..7f9ea28 100644 (file)
@@ -787,7 +787,7 @@ class progressive_parser_test extends advanced_testcase {
  *        - equal to "value" attribute of the tag (if present)
  *        - else, equal to tag name
  *
- * We pass the whole UnitTestCase object to the processor in order to be
+ * We pass the whole advanced_testcase object to the processor in order to be
  * able to perform the tests in the straight in the process
  */
 class mock_auto_parser_processor extends progressive_parser_processor {
index dc5041a..b254068 100644 (file)
@@ -131,6 +131,8 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
 
     /**
      * Test delete_calendar_events
+     *
+     * @expectedException moodle_exception
      */
     public function test_delete_calendar_events() {
         global $DB, $USER;
@@ -247,7 +249,7 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
         $groupevent = $this->create_calendar_event('group', $USER->id, 'group', 0, time(), $record);
 
         $this->setGuestUser();
-        $this->setExpectedException('moodle_exception');
+
         $events = array(
             array('eventid' => $siteevent->id, 'repeat' => 0),
             array('eventid' => $courseevent->id, 'repeat' => 0),
index cfc5bb3..2fc3c02 100644 (file)
@@ -45,6 +45,9 @@ class core_calendar_ical_testcase extends advanced_testcase {
         require_once($CFG->dirroot . '/calendar/lib.php');
     }
 
+    /**
+     * @expectedException coding_exception
+     */
     public function test_calendar_update_subscription() {
         $this->resetAfterTest(true);
 
@@ -71,7 +74,6 @@ class core_calendar_ical_testcase extends advanced_testcase {
 
         $subscription = new stdClass();
         $subscription->name = 'awesome4';
-        $this->setExpectedException('coding_exception');
         calendar_update_subscription($subscription);
     }
 
index 5232ab7..a68d615 100644 (file)
@@ -86,22 +86,24 @@ class core_calendar_rrule_manager_testcase extends advanced_testcase {
 
     /**
      * Test exception is thrown for invalid property.
+     *
+     * @expectedException moodle_exception
      */
     public function test_parse_rrule_validation() {
 
         $rrule = "RANDOM=PROPERTY;";
-        $this->setExpectedException('moodle_exception');
         $mang = new core_tests_calendar_rrule_manager($rrule);
         $mang->parse_rrule();
     }
 
     /**
      * Test exception is thrown for invalid frequency.
+     *
+     * @expectedException moodle_exception
      */
     public function test_freq_validation() {
 
         $rrule = "FREQ=RANDOMLY;";
-        $this->setExpectedException('moodle_exception');
         $mang = new core_tests_calendar_rrule_manager($rrule);
         $mang->parse_rrule();
     }
index 7403355..04b37b1 100644 (file)
@@ -64,6 +64,10 @@ class core_cohort_cohortlib_testcase extends advanced_testcase {
         $this->assertSame($newcohort->timecreated, $newcohort->timemodified);
     }
 
+    /**
+     * @expectedException        coding_exception
+     * @expectedExceptionMessage Missing cohort name in cohort_add_cohort().
+     */
     public function test_cohort_add_cohort_missing_name() {
         $cohort = new stdClass();
         $cohort->contextid = context_system::instance()->id;
@@ -72,7 +76,6 @@ class core_cohort_cohortlib_testcase extends advanced_testcase {
         $cohort->description = 'test cohort desc';
         $cohort->descriptionformat = FORMAT_HTML;
 
-        $this->setExpectedException('coding_exception', 'Missing cohort name in cohort_add_cohort().');
         cohort_add_cohort($cohort);
     }
 
index 3ca5fa2..f55eb1f 100644 (file)
@@ -34,6 +34,8 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
     /**
      * Test create_cohorts
+     *
+     * @expectedException required_capability_exception
      */
     public function test_create_cohorts() {
         global $USER, $CFG, $DB;
@@ -97,12 +99,13 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability.
         $this->unassignUserCapability('moodle/cohort:manage', $contextid, $roleid);
-        $this->setExpectedException('required_capability_exception');
         $createdcohorts = core_cohort_external::create_cohorts(array($cohort3));
     }
 
     /**
      * Test delete_cohorts
+     *
+     * @expectedException required_capability_exception
      */
     public function test_delete_cohorts() {
         global $USER, $CFG, $DB;
@@ -129,7 +132,6 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
         $cohort1 = self::getDataGenerator()->create_cohort();
         $cohort2 = self::getDataGenerator()->create_cohort();
         $this->unassignUserCapability('moodle/cohort:manage', $contextid, $roleid);
-        $this->setExpectedException('required_capability_exception');
         core_cohort_external::delete_cohorts(array($cohort1->id, $cohort2->id));
     }
 
@@ -183,6 +185,8 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
     /**
      * Test update_cohorts
+     *
+     * @expectedException required_capability_exception
      */
     public function test_update_cohorts() {
         global $USER, $CFG, $DB;
@@ -224,7 +228,6 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability.
         $this->unassignUserCapability('moodle/cohort:manage', $context->id, $roleid);
-        $this->setExpectedException('required_capability_exception');
         core_cohort_external::update_cohorts(array($cohort1));
     }
 
@@ -260,6 +263,8 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
     /**
      * Test update_cohorts without permission on the dest category.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_update_cohorts_missing_dest() {
         global $USER, $CFG, $DB;
@@ -295,12 +300,13 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
         // Call the external function.
         // Should fail because we don't have permission on the dest category
-        $this->setExpectedException('required_capability_exception');
         core_cohort_external::update_cohorts(array($cohortupdate));
     }
 
     /**
      * Test update_cohorts without permission on the src category.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_update_cohorts_missing_src() {
         global $USER, $CFG, $DB;
@@ -336,12 +342,13 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
         // Call the external function.
         // Should fail because we don't have permission on the src category
-        $this->setExpectedException('required_capability_exception');
         core_cohort_external::update_cohorts(array($cohortupdate));
     }
 
     /**
      * Test add_cohort_members
+     *
+     * @expectedException required_capability_exception
      */
     public function test_add_cohort_members() {
         global $DB;
@@ -387,12 +394,13 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
             'usertype' => array('type' => 'id', 'value' => '2')
             );
         $this->unassignUserCapability('moodle/cohort:assign', $contextid, $roleid);
-        $this->setExpectedException('required_capability_exception');
         $addcohortmembers = core_cohort_external::add_cohort_members(array($cohort2));
     }
 
     /**
      * Test delete_cohort_members
+     *
+     * @expectedException required_capability_exception
      */
     public function test_delete_cohort_members() {
         global $DB;
@@ -444,7 +452,6 @@ class core_cohort_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability.
         $this->unassignUserCapability('moodle/cohort:assign', $context->id, $roleid);
-        $this->setExpectedException('required_capability_exception');
         core_cohort_external::delete_cohort_members(array($cohortdel1, $cohortdel2));
     }
 }
index cc96253..cb815aa 100644 (file)
@@ -166,6 +166,8 @@ class core_competency_api_testcase extends advanced_testcase {
 
     /**
      * Test updating a template.
+     *
+     * @expectedException coding_exception
      */
     public function test_update_template() {
         $cat = $this->getDataGenerator()->create_category();
@@ -184,7 +186,6 @@ class core_competency_api_testcase extends advanced_testcase {
         $this->assertEquals('success', $template->get_shortname());
 
         // Trying to change the context.
-        $this->setExpectedException('coding_exception');
         api::update_template((object) array('id' => $template->get_id(), 'contextid' => context_coursecat::instance($cat->id)));
     }
 
@@ -510,6 +511,9 @@ class core_competency_api_testcase extends advanced_testcase {
         }
     }
 
+    /**
+     * @expectedException coding_exception
+     */
     public function test_create_plan_from_template() {
         $this->resetAfterTest(true);
         $this->setAdminUser();
@@ -531,7 +535,6 @@ class core_competency_api_testcase extends advanced_testcase {
         $this->assertFalse($plan);
 
         // Check that api::create_plan cannot be used.
-        $this->setExpectedException('coding_exception');
         unset($record->id);
         $plan = api::create_plan($record);
     }
@@ -753,6 +756,8 @@ class core_competency_api_testcase extends advanced_testcase {
 
     /**
      * Test that the method to complete a plan.
+     *
+     * @expectedException coding_exception
      */
     public function test_complete_plan() {
         global $DB;
@@ -833,7 +838,6 @@ class core_competency_api_testcase extends advanced_testcase {
         }
 
         // Completing a plan that is completed throws an exception.
-        $this->setExpectedException('coding_exception');
         api::complete_plan($plan);
     }
 
@@ -4430,6 +4434,9 @@ class core_competency_api_testcase extends advanced_testcase {
         $this->assertTrue(evidence::record_exists($ev2->get_id()));
     }
 
+    /**
+     * @expectedException required_capability_exception
+     */
     public function test_delete_evidence_without_permissions() {
         $this->resetAfterTest();
         $dg = $this->getDataGenerator();
@@ -4442,7 +4449,6 @@ class core_competency_api_testcase extends advanced_testcase {
         $ev1 = $ccg->create_evidence(['usercompetencyid' => $uc1->get_id()]);
 
         $this->setUser($u1);
-        $this->setExpectedException('required_capability_exception');
 
         api::delete_evidence($ev1);
     }
index 1897e81..31f5e48 100644 (file)
@@ -120,7 +120,7 @@ class core_competency_course_competency_settings_testcase extends advanced_testc
         $this->assertEquals(2, $usercompcourse->get_grade());
 
         $this->setUser($u3);
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         api::update_course_competency_settings($c1->id, (object) array('pushratingstouserplans' => false));
     }
 
index 95223a3..4554c29 100644 (file)
@@ -1360,6 +1360,9 @@ class core_competency_event_testcase extends advanced_testcase {
 
     /**
      * Test evidence_created event by linking an invalid user competency to an evidence.
+     *
+     * @expectedException        coding_exception
+     * @expectedExceptionMessage The user competency linked with this evidence is invalid.
      */
     public function test_evidence_created_with_invalid_user_competency() {
         $this->resetAfterTest(true);
@@ -1385,7 +1388,6 @@ class core_competency_event_testcase extends advanced_testcase {
             'commentincontext', 'core', null, $recommend, null, 1);
 
         // We expect this to fail and throw a coding exception.
-        $this->setExpectedException('coding_exception', 'The user competency linked with this evidence is invalid.');
         \core\event\competency_evidence_created::create_from_evidence($evidence, $otheruc, $recommend)->trigger();
     }
 
index eb4830b..101e1b4 100644 (file)
@@ -82,18 +82,22 @@ class core_competency_exporter_testcase extends advanced_testcase {
         $this->assertArrayNotHasKey('otherstrings', $structure->keys);
     }
 
+    /**
+     * @expectedException coding_exception
+     */
     public function test_invalid_data() {
         global $PAGE;
-        $this->setExpectedException('coding_exception');
         $exporter = new core_competency_testable_exporter($this->invaliddata, $this->validrelated);
         $output = $PAGE->get_renderer('tool_lp');
 
         $result = $exporter->export($output);
     }
 
+    /**
+     * @expectedException coding_exception
+     */
     public function test_invalid_related() {
         global $PAGE;
-        $this->setExpectedException('coding_exception');
         $exporter = new core_competency_testable_exporter($this->validdata, $this->invalidrelated);
         $output = $PAGE->get_renderer('tool_lp');
 
index 6be6bf0..0b989bf 100644 (file)
@@ -303,9 +303,10 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we can't create a competency framework with only read permissions.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_create_competency_frameworks_with_read_permissions() {
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->user);
 
         $result = $this->create_competency_framework(1, true);
@@ -313,9 +314,10 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we can't create a competency framework with only read permissions.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_create_competency_frameworks_with_read_permissions_in_category() {
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->catuser);
         $result = $this->create_competency_framework(1, false);
     }
@@ -367,10 +369,11 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we cannot create a competency framework with nasty data.
+     *
+     * @expectedException invalid_parameter_exception
      */
     public function test_create_competency_frameworks_with_nasty_data() {
         $this->setUser($this->creator);
-        $this->setExpectedException('invalid_parameter_exception');
         $framework = array(
             'shortname' => 'short<a href="">',
             'idnumber' => 'id;"number',
@@ -543,9 +546,10 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we can delete a competency framework with read permissions.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_delete_competency_frameworks_with_read_permissions() {
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->creator);
         $result = $this->create_competency_framework(1, true);
 
@@ -624,9 +628,10 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we can update a competency framework with read permissions.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_update_competency_frameworks_with_read_permissions() {
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->creator);
         $result = $this->create_competency_framework(1, true);
 
@@ -757,9 +762,10 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we can't create a competency with only read permissions.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_create_competency_with_read_permissions() {
-        $this->setExpectedException('required_capability_exception');
         $framework = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_framework();
         $this->setUser($this->user);
         $competency = $this->create_competency(1, $framework->get_id());
@@ -818,11 +824,12 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we cannot create a competency with nasty data.
+     *
+     * @expectedException invalid_parameter_exception
      */
     public function test_create_competency_with_nasty_data() {
         $this->setUser($this->creator);
         $framework = $this->create_competency_framework(1, true);
-        $this->setExpectedException('invalid_parameter_exception');
         $competency = array(
             'shortname' => 'shortname<a href="">',
             'idnumber' => 'id;"number',
@@ -995,9 +1002,10 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we can delete a competency with read permissions.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_delete_competency_with_read_permissions() {
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->creator);
         $framework = $this->create_competency_framework(1, true);
         $result = $this->create_competency(1, $framework->id);
@@ -1048,9 +1056,10 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
     /**
      * Test we can update a competency with read permissions.
+     *
+     * @expectedException required_capability_exception
      */
     public function test_update_competency_with_read_permissions() {
-        $this->setExpectedException('required_capability_exception');
         $this->setUser($this->creator);
         $framework = $this->create_competency_framework(1, true);
         $result = $this->create_competency(1, $framework->id);
@@ -1717,7 +1726,7 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
         $this->assertEquals($competency1->id, $r2->id);
         $this->assertEquals($competency2->id, $r3->id);
 
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         $this->setUser($this->user);
         external::reorder_template_competency($template->id, $competency1->id, $competency2->id);
     }
@@ -2694,7 +2703,7 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
 
         $this->setUser($this->user);
 
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         $evidence = external::grade_competency_in_plan($plan->get_id(), $c1->get_id(), 1);
     }
 
@@ -2738,7 +2747,7 @@ class core_competency_external_testcase extends externallib_advanced_testcase {
         $this->assertFalse((bool)$settings->get_pushratingstouserplans());
         $this->setUser($compnoob);
 
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         $result = external::update_course_competency_settings($course->id, array('pushratingstouserplans' => true));
     }
 
index b9dc0fd..fc8966c 100644 (file)
@@ -178,12 +178,15 @@ class core_competency_persistent_testcase extends advanced_testcase {
         $this->assertEquals($data, $p->to_record());
     }
 
+    /**
+     * @expectedException coding_exception
+     */
     public function test_from_record_invalid_param() {
         $p = new core_competency_testable_persistent();
         $data = (object) array(
             'invalidparam' => 'abc'
         );
-        $this->setExpectedException('coding_exception');
+
         $p->from_record($data);
     }
 
index 865a5e2..6e9972f 100644 (file)
@@ -526,6 +526,10 @@ class core_competency_plan_testcase extends advanced_testcase {
         $this->assertCount(0, $plans);
     }
 
+    /**
+     * @expectedException        coding_exception
+     * @expectedExceptionMessage The competency does not belong to this template:
+     */
     public function test_get_competency() {
         $this->resetAfterTest();
         $this->setAdminUser();
@@ -567,7 +571,6 @@ class core_competency_plan_testcase extends advanced_testcase {
         $this->assertEquals($c4->to_record(), $p4->get_competency($c4->get_id())->to_record());
 
         // Getting the competency 4 from the non-completed plan based on a template p4, will throw an exception.
-        $this->setExpectedException('coding_exception', 'The competency does not belong to this template: ');
         $p3->get_competency($c4->get_id());
     }
 }
index 73e59f1..ce55027 100644 (file)
@@ -5,7 +5,7 @@
     "type": "project",
     "homepage": "https://moodle.org",
     "require-dev": {
-        "phpunit/phpunit": "4.8.*",
+        "phpunit/phpunit": "5.4.*",
         "phpunit/dbUnit": "1.4.*",
         "moodlehq/behat-extension": "3.32.1"
     }
index 4eda2d9..6fe8310 100644 (file)
@@ -4,8 +4,8 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "949f8a407958a19e2dba7929b3dc0576",
-    "content-hash": "bd742592f8ed4700884f6c651226c961",
+    "hash": "7f0c2a252624902575a3ed1bdc237644",
+    "content-hash": "bcc157487e77ec6ad4163f1661abac97",
     "packages": [],
     "packages-dev": [
         {
         },
         {
             "name": "fabpot/goutte",
-            "version": "v2.0.4",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FriendsOfPHP/Goutte.git",
-                "reference": "0ad3ee6dc2d0aaa832a80041a1e09bf394e99802"
+                "reference": "3cbc6ed222422a28400e470050f14928a153207e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/0ad3ee6dc2d0aaa832a80041a1e09bf394e99802",
-                "reference": "0ad3ee6dc2d0aaa832a80041a1e09bf394e99802",
+                "url": "https://api.github.com/repos/FriendsOfPHP/Goutte/zipball/3cbc6ed222422a28400e470050f14928a153207e",
+                "reference": "3cbc6ed222422a28400e470050f14928a153207e",
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/guzzle": ">=4,<6",
-                "php": ">=5.4.0",
-                "symfony/browser-kit": "~2.1",
-                "symfony/css-selector": "~2.1",
-                "symfony/dom-crawler": "~2.1"
+                "guzzlehttp/guzzle": "^6.0",
+                "php": ">=5.5.0",
+                "symfony/browser-kit": "~2.1|~3.0",
+                "symfony/css-selector": "~2.1|~3.0",
+                "symfony/dom-crawler": "~2.1|~3.0"
             },
             "type": "application",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             "keywords": [
                 "scraper"
             ],
-            "time": "2015-05-05 21:14:57"
+            "time": "2015-11-05 12:58:44"
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "5.3.0",
+            "version": "6.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "f3c8c22471cb55475105c14769644a49c3262b93"
+                "reference": "d094e337976dff9d8e2424e8485872194e768662"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f3c8c22471cb55475105c14769644a49c3262b93",
-                "reference": "f3c8c22471cb55475105c14769644a49c3262b93",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662",
+                "reference": "d094e337976dff9d8e2424e8485872194e768662",
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/ringphp": "^1.1",
-                "php": ">=5.4.0"
+                "guzzlehttp/promises": "~1.0",
+                "guzzlehttp/psr7": "~1.1",
+                "php": ">=5.5.0"
             },
             "require-dev": {
                 "ext-curl": "*",
-                "phpunit/phpunit": "^4.0",
-                "psr/log": "^1.0"
+                "phpunit/phpunit": "~4.0",
+                "psr/log": "~1.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.0-dev"
+                    "dev-master": "6.2-dev"
                 }
             },
             "autoload": {
+                "files": [
+                    "src/functions_include.php"
+                ],
                 "psr-4": {
                     "GuzzleHttp\\": "src/"
                 }
                     "homepage": "https://github.com/mtdowling"
                 }
             ],
-            "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
+            "description": "Guzzle is a PHP HTTP client library",
             "homepage": "http://guzzlephp.org/",
             "keywords": [
                 "client",
                 "rest",
                 "web service"
             ],
-            "time": "2015-05-20 03:47:55"
+            "time": "2016-03-21 20:02:09"
         },
         {
-            "name": "guzzlehttp/ringphp",
-            "version": "1.1.0",
+            "name": "guzzlehttp/promises",
+            "version": "1.2.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/guzzle/RingPHP.git",
-                "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b"
+                "url": "https://github.com/guzzle/promises.git",
+                "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
-                "reference": "dbbb91d7f6c191e5e405e900e3102ac7f261bc0b",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579",
+                "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579",
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/streams": "~3.0",
-                "php": ">=5.4.0",
-                "react/promise": "~2.0"
+                "php": ">=5.5.0"
             },
             "require-dev": {
-                "ext-curl": "*",
                 "phpunit/phpunit": "~4.0"
             },
-            "suggest": {
-                "ext-curl": "Guzzle will use specific adapters if cURL is present"
-            },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.1-dev"
+                    "dev-master": "1.0-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "GuzzleHttp\\Ring\\": "src/"
-                }
+                    "GuzzleHttp\\Promise\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                     "homepage": "https://github.com/mtdowling"
                 }
             ],
-            "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.",
-            "time": "2015-05-20 03:37:09"
+            "description": "Guzzle promises library",
+            "keywords": [
+                "promise"
+            ],
+            "time": "2016-05-18 16:56:05"
         },
         {
-            "name": "guzzlehttp/streams",
-            "version": "3.0.0",
+            "name": "guzzlehttp/psr7",
+            "version": "1.3.1",
             "source": {
                 "type": "git",
-                "url": "https://github.com/guzzle/streams.git",
-                "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5"
+                "url": "https://github.com/guzzle/psr7.git",
+                "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
-                "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
+                "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.4.0"
+                "php": ">=5.4.0",
+                "psr/http-message": "~1.0"
+            },
+            "provide": {
+                "psr/http-message-implementation": "1.0"
             },
             "require-dev": {
                 "phpunit/phpunit": "~4.0"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-master": "1.4-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "GuzzleHttp\\Stream\\": "src/"
-                }
+                    "GuzzleHttp\\Psr7\\": "src/"
+                },
+                "files": [
+                    "src/functions_include.php"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                     "homepage": "https://github.com/mtdowling"
                 }
             ],
-            "description": "Provides a simple abstraction over streams of data",
-            "homepage": "http://guzzlephp.org/",
+            "description": "PSR-7 message implementation",
             "keywords": [
-                "Guzzle",
-                "stream"
+                "http",
+                "message",
+                "stream",
+                "uri"
             ],
-            "time": "2014-10-12 19:18:40"
+            "time": "2016-06-24 23:00:38"
         },
         {
             "name": "instaclick/php-webdriver",
             ],
             "time": "2016-06-20 07:56:08"
         },
+        {
+            "name": "myclabs/deep-copy",
+            "version": "1.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/myclabs/DeepCopy.git",
+                "reference": "a8773992b362b58498eed24bf85005f363c34771"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/a8773992b362b58498eed24bf85005f363c34771",
+                "reference": "a8773992b362b58498eed24bf85005f363c34771",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.4.0"
+            },
+            "require-dev": {
+                "doctrine/collections": "1.*",
+                "phpunit/phpunit": "~4.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "DeepCopy\\": "src/DeepCopy/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Create deep copies (clones) of your objects",
+            "homepage": "https://github.com/myclabs/DeepCopy",
+            "keywords": [
+                "clone",
+                "copy",
+                "duplicate",
+                "object",
+                "object graph"
+            ],
+            "time": "2015-11-20 12:04:31"
+        },
+        {
+            "name": "phpdocumentor/reflection-common",
+            "version": "1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
+                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.6"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": [
+                        "src"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Jaap van Otterdijk",
+                    "email": "opensource@ijaap.nl"
+                }
+            ],
+            "description": "Common reflection classes used by phpdocumentor to reflect the code structure",
+            "homepage": "http://www.phpdoc.org",
+            "keywords": [
+                "FQSEN",
+                "phpDocumentor",
+                "phpdoc",
+                "reflection",
+                "static analysis"
+            ],
+            "time": "2015-12-27 11:43:31"
+        },
         {
             "name": "phpdocumentor/reflection-docblock",
-            "version": "2.0.4",
+            "version": "3.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
+                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
-                "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
+                "reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
+                "php": ">=5.5",
+                "phpdocumentor/reflection-common": "^1.0@dev",
+                "phpdocumentor/type-resolver": "^0.2.0",
+                "webmozart/assert": "^1.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.0"
+                "mockery/mockery": "^0.9.4",
+                "phpunit/phpunit": "^4.4"
             },
-            "suggest": {
-                "dflydev/markdown": "~1.0",
-                "erusev/parsedown": "~1.0"
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": [
+                        "src/"
+                    ]
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mike van Riel",
+                    "email": "me@mikevanriel.com"
+                }
+            ],
+            "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+            "time": "2016-06-10 09:48:41"
+        },
+        {
+            "name": "phpdocumentor/type-resolver",
+            "version": "0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpDocumentor/TypeResolver.git",
+                "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
+                "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.5",
+                "phpdocumentor/reflection-common": "^1.0"
+            },
+            "require-dev": {
+                "mockery/mockery": "^0.9.4",
+                "phpunit/phpunit": "^5.2||^4.8.24"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0.x-dev"
+                    "dev-master": "1.0.x-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
-                    "phpDocumentor": [
+                "psr-4": {
+                    "phpDocumentor\\Reflection\\": [
                         "src/"
                     ]
                 }
             "authors": [
                 {
                     "name": "Mike van Riel",
-                    "email": "mike.vanriel@naenius.com"
+                    "email": "me@mikevanriel.com"
                 }
             ],
-            "time": "2015-02-03 12:10:50"
+            "time": "2016-06-10 07:14:17"
         },
         {
             "name": "phpspec/prophecy",
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "2.2.4",
+            "version": "4.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
+                "reference": "900370c81280cc0d942ffbc5912d80464eaee7e9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
-                "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/900370c81280cc0d942ffbc5912d80464eaee7e9",
+                "reference": "900370c81280cc0d942ffbc5912d80464eaee7e9",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3",
+                "php": "^5.6 || ^7.0",
                 "phpunit/php-file-iterator": "~1.3",
                 "phpunit/php-text-template": "~1.2",
-                "phpunit/php-token-stream": "~1.3",
+                "phpunit/php-token-stream": "^1.4.2",
+                "sebastian/code-unit-reverse-lookup": "~1.0",
                 "sebastian/environment": "^1.3.2",
-                "sebastian/version": "~1.0"
+                "sebastian/version": "~1.0|~2.0"
             },
             "require-dev": {
                 "ext-xdebug": ">=2.1.4",
-                "phpunit/phpunit": "~4"
+                "phpunit/phpunit": "^5.4"
             },
             "suggest": {
                 "ext-dom": "*",
-                "ext-xdebug": ">=2.2.1",
+                "ext-xdebug": ">=2.4.0",
                 "ext-xmlwriter": "*"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.2.x-dev"
+                    "dev-master": "4.0.x-dev"
                 }
             },
             "autoload": {
                 "testing",
                 "xunit"
             ],
-            "time": "2015-10-06 15:47:00"
+            "time": "2016-06-03 05:03:56"
         },
         {
             "name": "phpunit/php-file-iterator",
         },
         {
             "name": "phpunit/phpunit",
-            "version": "4.8.26",
+            "version": "5.4.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74"
+                "reference": "2f1fc94b77ea6418bd6a06c64a1dac0645fbce59"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74",
-                "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2f1fc94b77ea6418bd6a06c64a1dac0645fbce59",
+                "reference": "2f1fc94b77ea6418bd6a06c64a1dac0645fbce59",
                 "shasum": ""
             },
             "require": {
                 "ext-pcre": "*",
                 "ext-reflection": "*",
                 "ext-spl": "*",
-                "php": ">=5.3.3",
+                "myclabs/deep-copy": "~1.3",
+                "php": "^5.6 || ^7.0",
                 "phpspec/prophecy": "^1.3.1",
-                "phpunit/php-code-coverage": "~2.1",
+                "phpunit/php-code-coverage": "^4.0",
                 "phpunit/php-file-iterator": "~1.4",
                 "phpunit/php-text-template": "~1.2",
                 "phpunit/php-timer": "^1.0.6",
-                "phpunit/phpunit-mock-objects": "~2.3",
+                "phpunit/phpunit-mock-objects": "^3.2",
                 "sebastian/comparator": "~1.1",
                 "sebastian/diff": "~1.2",
-                "sebastian/environment": "~1.3",
+                "sebastian/environment": "^1.3 || ^2.0",
                 "sebastian/exporter": "~1.2",
                 "sebastian/global-state": "~1.0",
-                "sebastian/version": "~1.0",
+                "sebastian/object-enumerator": "~1.0",
+                "sebastian/resource-operations": "~1.0",
+                "sebastian/version": "~1.0|~2.0",
                 "symfony/yaml": "~2.1|~3.0"
             },
+            "conflict": {
+                "phpdocumentor/reflection-docblock": "3.0.2"
+            },
             "suggest": {
                 "phpunit/php-invoker": "~1.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.8.x-dev"
+                    "dev-master": "5.4.x-dev"
                 }
             },
             "autoload": {
                 "testing",
                 "xunit"
             ],
-            "time": "2016-05-17 03:09:28"
+            "time": "2016-06-16 06:01:15"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
-            "version": "2.3.8",
+            "version": "3.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
+                "reference": "b13d0d9426ced06958bd32104653526a6c998a52"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
-                "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/b13d0d9426ced06958bd32104653526a6c998a52",
+                "reference": "b13d0d9426ced06958bd32104653526a6c998a52",
                 "shasum": ""
             },
             "require": {
                 "doctrine/instantiator": "^1.0.2",
-                "php": ">=5.3.3",
-                "phpunit/php-text-template": "~1.2",
-                "sebastian/exporter": "~1.2"
+                "php": "^5.6 || ^7.0",
+                "phpunit/php-text-template": "^1.2",
+                "sebastian/exporter": "^1.2"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<5.4.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.4"
+                "phpunit/phpunit": "^5.4"
             },
             "suggest": {
                 "ext-soap": "*"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.3.x-dev"
+                    "dev-master": "3.2.x-dev"
                 }
             },
             "autoload": {
                 "mock",
                 "xunit"
             ],
-            "time": "2015-10-02 06:51:40"
+            "time": "2016-06-12 07:37:26"
         },
         {
-            "name": "react/promise",
-            "version": "v2.4.1",
+            "name": "psr/http-message",
+            "version": "1.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/reactphp/promise.git",
-                "reference": "8025426794f1944de806618671d4fa476dc7626f"
+                "url": "https://github.com/php-fig/http-message.git",
+                "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/reactphp/promise/zipball/8025426794f1944de806618671d4fa476dc7626f",
-                "reference": "8025426794f1944de806618671d4fa476dc7626f",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
+                "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.4.0"
+                "php": ">=5.3.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-master": "1.0.x-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "React\\Promise\\": "src/"
-                },
-                "files": [
-                    "src/functions_include.php"
-                ]
+                    "Psr\\Http\\Message\\": "src/"
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             ],
             "authors": [
                 {
-                    "name": "Jan Sorgalla",
-                    "email": "jsorgalla@gmail.com"
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP messages",
+            "keywords": [
+                "http",
+                "http-message",
+                "psr",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "time": "2015-05-04 20:22:00"
+        },
+        {
+            "name": "sebastian/code-unit-reverse-lookup",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+                "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe",
+                "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~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": "A lightweight implementation of CommonJS Promises/A for PHP",
-            "time": "2016-05-03 17:50:52"
+            "description": "Looks up which function or method a line of code belongs to",
+            "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+            "time": "2016-02-13 06:45:14"
         },
         {
             "name": "sebastian/comparator",
             ],
             "time": "2015-10-12 03:26:01"
         },
+        {
+            "name": "sebastian/object-enumerator",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+                "reference": "d4ca2fb70344987502567bc50081c03e6192fb26"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26",
+                "reference": "d4ca2fb70344987502567bc50081c03e6192fb26",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.6",
+                "sebastian/recursion-context": "~1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "~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": "Traverses array structures and object graphs to enumerate all referenced objects",
+            "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+            "time": "2016-01-28 13:25:10"
+        },
         {
             "name": "sebastian/recursion-context",
             "version": "1.0.2",
             "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
             "time": "2015-11-11 19:50:13"
         },
+        {
+            "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",
+            "time": "2015-07-28 20:34:47"
+        },
         {
             "name": "sebastian/version",
-            "version": "1.0.6",
+            "version": "2.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
+                "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
-                "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
+                "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
                 "shasum": ""
             },
+            "require": {
+                "php": ">=5.6"
+            },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
             "autoload": {
                 "classmap": [
                     "src/"
             ],
             "description": "Library that helps with managing the version number of Git-hosted PHP projects",
             "homepage": "https://github.com/sebastianbergmann/version",
-            "time": "2015-06-21 13:59:46"
+            "time": "2016-02-04 12:56:52"
         },
         {
             "name": "symfony/browser-kit",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/browser-kit.git",
-                "reference": "2508ecbfc98b007bc1b670cef40ff821b827c61c"
+                "reference": "dcf41ed026b0499254385b5c88f03247b2ba010b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/browser-kit/zipball/2508ecbfc98b007bc1b670cef40ff821b827c61c",
-                "reference": "2508ecbfc98b007bc1b670cef40ff821b827c61c",
+                "url": "https://api.github.com/repos/symfony/browser-kit/zipball/dcf41ed026b0499254385b5c88f03247b2ba010b",
+                "reference": "dcf41ed026b0499254385b5c88f03247b2ba010b",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9",
-                "symfony/dom-crawler": "~2.1|~3.0.0"
+                "php": ">=5.5.9",
+                "symfony/dom-crawler": "~2.8|~3.0"
             },
             "require-dev": {
-                "symfony/css-selector": "~2.0,>=2.0.5|~3.0.0",
-                "symfony/process": "~2.3.34|~2.7,>=2.7.6|~3.0.0"
+                "symfony/css-selector": "~2.8|~3.0",
+                "symfony/process": "~2.8|~3.0"
             },
             "suggest": {
                 "symfony/process": ""
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony BrowserKit Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 15:06:25"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/class-loader",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/class-loader.git",
-                "reference": "f1cf312c81c7b4f0f11431e6fd37b66890f5e27b"
+                "reference": "0d0ac77c336eb73f35bebdf3e1f3695ac741bbc9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/class-loader/zipball/f1cf312c81c7b4f0f11431e6fd37b66890f5e27b",
-                "reference": "f1cf312c81c7b4f0f11431e6fd37b66890f5e27b",
+                "url": "https://api.github.com/repos/symfony/class-loader/zipball/0d0ac77c336eb73f35bebdf3e1f3695ac741bbc9",
+                "reference": "0d0ac77c336eb73f35bebdf3e1f3695ac741bbc9",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9",
-                "symfony/polyfill-apcu": "~1.1"
+                "php": ">=5.5.9"
             },
             "require-dev": {
-                "symfony/finder": "~2.0,>=2.0.5|~3.0.0"
+                "symfony/finder": "~2.8|~3.0",
+                "symfony/polyfill-apcu": "~1.1"
+            },
+            "suggest": {
+                "symfony/polyfill-apcu": "For using ApcClassLoader on HHVM"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony ClassLoader Component",
             "homepage": "https://symfony.com",
-            "time": "2016-03-30 10:37:34"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/config",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/config.git",
-                "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05"
+                "reference": "bcf5aebabc95b56e370e13d78565f74c7d8726dc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/config/zipball/a2edd59c2163c65747fc3f35d132b5a39266bd05",
-                "reference": "a2edd59c2163c65747fc3f35d132b5a39266bd05",
+                "url": "https://api.github.com/repos/symfony/config/zipball/bcf5aebabc95b56e370e13d78565f74c7d8726dc",
+                "reference": "bcf5aebabc95b56e370e13d78565f74c7d8726dc",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9",
-                "symfony/filesystem": "~2.3|~3.0.0"
+                "php": ">=5.5.9",
+                "symfony/filesystem": "~2.8|~3.0"
             },
             "suggest": {
                 "symfony/yaml": "To use the yaml reference dumper"
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Config Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/console",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3"
+                "reference": "747154aa69b0f83cd02fc9aa554836dee417631a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
-                "reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
+                "url": "https://api.github.com/repos/symfony/console/zipball/747154aa69b0f83cd02fc9aa554836dee417631a",
+                "reference": "747154aa69b0f83cd02fc9aa554836dee417631a",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9",
+                "php": ">=5.5.9",
                 "symfony/polyfill-mbstring": "~1.0"
             },
             "require-dev": {
                 "psr/log": "~1.0",
-                "symfony/event-dispatcher": "~2.1|~3.0.0",
-                "symfony/process": "~2.1|~3.0.0"
+                "symfony/event-dispatcher": "~2.8|~3.0",
+                "symfony/process": "~2.8|~3.0"
             },
             "suggest": {
                 "psr/log": "For using the console logger",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Console Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 15:06:25"
+            "time": "2016-06-29 07:02:31"
         },
         {
             "name": "symfony/css-selector",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/css-selector.git",
-                "reference": "9a0b2649328297fb6acd0c823789d92efcbd36ad"
+                "reference": "2851e1932d77ce727776154d659b232d061e816a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/css-selector/zipball/9a0b2649328297fb6acd0c823789d92efcbd36ad",
-                "reference": "9a0b2649328297fb6acd0c823789d92efcbd36ad",
+                "url": "https://api.github.com/repos/symfony/css-selector/zipball/2851e1932d77ce727776154d659b232d061e816a",
+                "reference": "2851e1932d77ce727776154d659b232d061e816a",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9"
+                "php": ">=5.5.9"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony CssSelector Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13"
+                "reference": "b7272b65f2f46cbe77def7d33916f2613669c508"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2d05009d890cf1139988ff059b5b2e0eb280ed13",
-                "reference": "2d05009d890cf1139988ff059b5b2e0eb280ed13",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/b7272b65f2f46cbe77def7d33916f2613669c508",
+                "reference": "b7272b65f2f46cbe77def7d33916f2613669c508",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9"
-            },
-            "conflict": {
-                "symfony/expression-language": "<2.6"
+                "php": ">=5.5.9"
             },
             "require-dev": {
-                "symfony/config": "~2.2|~3.0.0",
-                "symfony/expression-language": "~2.6|~3.0.0",
-                "symfony/yaml": "~2.1|~3.0.0"
+                "symfony/config": "~2.8|~3.0",
+                "symfony/expression-language": "~2.8|~3.0",
+                "symfony/yaml": "~2.8|~3.0"
             },
             "suggest": {
                 "symfony/config": "",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony DependencyInjection Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:42:25"
         },
         {
             "name": "symfony/dom-crawler",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dom-crawler.git",
-                "reference": "f282b08f6bbbc72e7af2e9e0c2f896221053f791"
+                "reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/f282b08f6bbbc72e7af2e9e0c2f896221053f791",
-                "reference": "f282b08f6bbbc72e7af2e9e0c2f896221053f791",
+                "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0",
+                "reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9",
+                "php": ">=5.5.9",
                 "symfony/polyfill-mbstring": "~1.0"
             },
             "require-dev": {
-                "symfony/css-selector": "~2.8|~3.0.0"
+                "symfony/css-selector": "~2.8|~3.0"
             },
             "suggest": {
                 "symfony/css-selector": ""
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony DomCrawler Component",
             "homepage": "https://symfony.com",
-            "time": "2016-04-12 18:01:21"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "2a6b8713f8bdb582058cfda463527f195b066110"
+                "reference": "7f9839ede2070f53e7e2f0849b9bd14748c434c5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/2a6b8713f8bdb582058cfda463527f195b066110",
-                "reference": "2a6b8713f8bdb582058cfda463527f195b066110",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7f9839ede2070f53e7e2f0849b9bd14748c434c5",
+                "reference": "7f9839ede2070f53e7e2f0849b9bd14748c434c5",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9"
+                "php": ">=5.5.9"
             },
             "require-dev": {
                 "psr/log": "~1.0",
-                "symfony/config": "~2.0,>=2.0.5|~3.0.0",
-                "symfony/dependency-injection": "~2.6|~3.0.0",
-                "symfony/expression-language": "~2.6|~3.0.0",
-                "symfony/stopwatch": "~2.3|~3.0.0"
+                "symfony/config": "~2.8|~3.0",
+                "symfony/dependency-injection": "~2.8|~3.0",
+                "symfony/expression-language": "~2.8|~3.0",
+                "symfony/stopwatch": "~2.8|~3.0"
             },
             "suggest": {
                 "symfony/dependency-injection": "",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "dee379131dceed90a429e951546b33edfe7dccbb"
+                "reference": "322da5f0910d8aa0b25fa65ffccaba68dbddb890"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb",
-                "reference": "dee379131dceed90a429e951546b33edfe7dccbb",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/322da5f0910d8aa0b25fa65ffccaba68dbddb890",
+                "reference": "322da5f0910d8aa0b25fa65ffccaba68dbddb890",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9"
+                "php": ">=5.5.9"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "https://symfony.com",
-            "time": "2016-04-12 18:01:21"
-        },
-        {
-            "name": "symfony/polyfill-apcu",
-            "version": "v1.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-apcu.git",
-                "reference": "6d58bceaeea2c2d3eb62503839b18646e161cd6b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/6d58bceaeea2c2d3eb62503839b18646e161cd6b",
-                "reference": "6d58bceaeea2c2d3eb62503839b18646e161cd6b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.2-dev"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "apcu",
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2016-05-18 14:26:46"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/polyfill-mbstring",
         },
         {
             "name": "symfony/process",
-            "version": "v2.8.7",
+            "version": "v2.8.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c"
+                "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c",
-                "reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c",
+                "url": "https://api.github.com/repos/symfony/process/zipball/89f33c16796415ccfd8bb3cf8d520cbb79899bfe",
+                "reference": "89f33c16796415ccfd8bb3cf8d520cbb79899bfe",
                 "shasum": ""
             },
             "require": {
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:29:29"
         },
         {
             "name": "symfony/translation",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation.git",
-                "reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1"
+                "reference": "d63a94528530c3ea5ff46924c8001cec4a398609"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation/zipball/8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1",
-                "reference": "8a1648d2e165ba87c759ba57d7f4c13d95fdf4a1",
+                "url": "https://api.github.com/repos/symfony/translation/zipball/d63a94528530c3ea5ff46924c8001cec4a398609",
+                "reference": "d63a94528530c3ea5ff46924c8001cec4a398609",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9",
+                "php": ">=5.5.9",
                 "symfony/polyfill-mbstring": "~1.0"
             },
             "conflict": {
-                "symfony/config": "<2.7"
+                "symfony/config": "<2.8"
             },
             "require-dev": {
                 "psr/log": "~1.0",
-                "symfony/config": "~2.8",
-                "symfony/intl": "~2.4|~3.0.0",
-                "symfony/yaml": "~2.2|~3.0.0"
+                "symfony/config": "~2.8|~3.0",
+                "symfony/intl": "~2.8|~3.0",
+                "symfony/yaml": "~2.8|~3.0"
             },
             "suggest": {
                 "psr/log": "To use logging capability in translator",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Translation Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:41:56"
         },
         {
             "name": "symfony/yaml",
-            "version": "v2.8.7",
+            "version": "v3.1.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
-                "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34"
+                "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34",
-                "reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de",
+                "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.9"
+                "php": ">=5.5.9"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.8-dev"
+                    "dev-master": "3.1-dev"
                 }
             },
             "autoload": {
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2016-06-06 11:11:27"
+            "time": "2016-06-29 05:41:56"
+        },
+        {
+            "name": "webmozart/assert",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/webmozart/assert.git",
+                "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
+                "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.6"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0-dev"
+                }
+            },
+            "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"
+            ],
+            "time": "2015-08-24 13:29:44"
         }
     ],
     "aliases": [],
index fb1814a..4c863da 100644 (file)
@@ -120,7 +120,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability
         $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid);
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         $createdsubcats = core_course_external::create_categories($subcategories);
 
     }
@@ -163,7 +163,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
 
          // Call without required capability
         $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid);
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         $createdsubcats = core_course_external::delete_categories(
                 array(array('id' => $category3->id)));
     }
@@ -261,7 +261,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability (it will fail cause of the search on idnumber).
         $this->unassignUserCapability('moodle/category:manage', $context->id, $roleid);
-        $this->setExpectedException('moodle_exception');
+        $this->expectException('moodle_exception');
         $categories = core_course_external::get_categories(array(
             array('key' => 'id', 'value' => $category1->id),
             array('key' => 'idnumber', 'value' => $category1->idnumber),
@@ -327,7 +327,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability.
         $this->unassignUserCapability('moodle/category:manage', $contextid, $roleid);
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         core_course_external::update_categories($categories);
     }
 
@@ -457,7 +457,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability
         $this->unassignUserCapability('moodle/course:create', $contextid, $roleid);
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         $createdsubcats = core_course_external::create_courses($courses);
     }
 
@@ -515,7 +515,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
 
          // Fail when the user is not allow to access the course (enrolled) or is not admin.
         $this->setGuestUser();
-        $this->setExpectedException('require_login_exception');
+        $this->expectException('require_login_exception');
 
         $result = core_course_external::delete_courses(array($course3->id));
         $result = external_api::clean_returnvalue(core_course_external::delete_courses_returns(), $result);
@@ -690,7 +690,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
         $this->assertEquals($coursedata2['fullname'], $results['courses'][0]['fullname']);
 
         // Search by block (use news_items default block). Should fail (only admins allowed).
-        $this->setExpectedException('required_capability_exception');
+        $this->expectException('required_capability_exception');
         $results = core_course_external::search_courses('blocklist', $blockid);
 
     }
@@ -724,6 +724,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
         $context = context_course::instance($course->id);
         $roleid = $this->assignUserCapability('moodle/course:view', $context->id);
         $this->assignUserCapability('moodle/course:update', $context->id, $roleid);
+        $this->assignUserCapability('mod/data:view', $context->id, $roleid);
 
         $conditions = array('course' => $course->id, 'section' => 2);
         $DB->set_field('course_sections', 'summary', 'Text with iframe <iframe src="https://moodle.org"></iframe>', $conditions);
@@ -1518,7 +1519,8 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
         $course1  = self::getDataGenerator()->create_course();
         $course2  = self::getDataGenerator()->create_course();
 
-        $this->setExpectedException('moodle_exception', get_string('invalidextparam', 'webservice', -1));
+        $this->expectException('moodle_exception');
+        $this->expectExceptionMessage(get_string('invalidextparam', 'webservice', -1));
         // Import from course1 to course2, with invalid option
         core_course_external::import_course($course1->id, $course2->id, -1);;
     }
index a7d35ad..7695e3c 100644 (file)
@@ -316,7 +316,8 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
                 }
             } else if (isset($expectations['exception'])) {
                 $exception = $expectations['exception'];
-                $this->setExpectedException($exception['type'], $exception['message']);
+                $this->expectException($exception['type']);
+                $this->expectExceptionMessage($exception['message']);
             } else {
                 // Failed, only canview and exception are supported.
                 $this->markTestIncomplete('Incomplete, only canview and exception are supported');
@@ -565,6 +566,8 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
     /**
      * Test get_enrolled_users from core_enrol_external with capability to
      * viewparticipants removed.
+     *
+     * @expectedException moodle_exception
      */
     public function test_get_enrolled_users_without_capability() {
         $capability = 'moodle/course:viewparticipants';
@@ -572,7 +575,6 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability.
         $this->unassignUserCapability($capability, $data->context->id, $data->roleid);
-        $this->setExpectedException('moodle_exception');
         $categories = core_enrol_external::get_enrolled_users($data->course->id);
     }
 
index 2a8c4a8..4009101 100644 (file)
@@ -84,7 +84,7 @@ class core_enrol_role_external_testcase extends externallib_advanced_testcase {
 
         // Call without required capability.
         $this->unassignUserCapability('moodle/role:assign', $context->id, $roleid);
-        $this->setExpectedException('moodle_exception');
+        $this->expectException('moodle_exception');
         $categories = core_role_external::assign_roles(
             array('roleid' => 3, 'userid' => $USER->id, 'contextid' => $context->id));
     }
@@ -138,7 +138,7 @@ class core_enrol_role_external_testcase extends externallib_advanced_testcase {
 
         // Call without required capability.
         $this->unassignUserCapability('moodle/role:assign', $context->id, $roleid);
-        $this->setExpectedException('moodle_exception');
+        $this->expectException('moodle_exception');
         $categories = core_role_external::unassign_roles(
             array('roleid' => 3, 'userid' => $USER->id, 'contextid' => $context->id));
     }
index c464856..4f19777 100644 (file)
@@ -95,7 +95,7 @@ class core_files_externallib_testcase extends advanced_testcase {
         $this->assertNotEmpty($file);
 
         // Make sure the same file cannot be created again.
-        $this->setExpectedException("moodle_exception");
+        $this->expectException("moodle_exception");
         core_files_external::upload($contextid, $component, $filearea, $itemid, $filepath,
                 $filename, $filecontent, $contextlevel, $instanceid);
     }
@@ -120,7 +120,7 @@ class core_files_externallib_testcase extends advanced_testcase {
         $instanceid = null;
 
         // Make sure exception is thrown.
-        $this->setExpectedException("coding_exception");
+        $this->expectException("coding_exception");
         core_files_external::upload($contextid, $component, $filearea, $itemid,
                 $filepath, $filename, $filecontent, $contextlevel, $instanceid);
     }
index 0e806e8..b490724 100644 (file)
@@ -67,6 +67,8 @@ class core_grade_grading_manager_testcase extends advanced_testcase {
 
     /**
      * Unit test to set and get grading areas
+     *
+     * @expectedException moodle_exception
      */
     public function test_set_and_get_grading_area() {
         global $DB;
@@ -103,7 +105,6 @@ class core_grade_grading_manager_testcase extends advanced_testcase {
         $this->assertEquals('rubric', $gradingman->get_active_method());
 
         // attempting to set an invalid method
-        $this->setExpectedException('moodle_exception');
         $gradingman->set_active_method('no_one_should_ever_try_to_implement_a_method_with_this_silly_name');
     }
 
index 5474379..97a6cf9 100644 (file)
@@ -36,6 +36,8 @@ class core_group_externallib_testcase extends externallib_advanced_testcase {
 
     /**
      * Test create_groups
+     *
+     * @expectedException required_capability_exception
      */
     public function test_create_groups() {
         global $DB;
@@ -111,12 +113,13 @@ class core_group_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability
         $this->unassignUserCapability('moodle/course:managegroups', $context->id, $roleid);
-        $this->setExpectedException('required_capability_exception');
         $froups = core_group_external::create_groups(array($group4));
     }
 
     /**
      * Test get_groups
+     *
+     * @expectedException required_capability_exception
      */
     public function test_get_groups() {
         global $DB;
@@ -175,12 +178,13 @@ class core_group_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability
         $this->unassignUserCapability('moodle/course:managegroups', $context->id, $roleid);
-        $this->setExpectedException('required_capability_exception');
         $groups = core_group_external::get_groups(array($group1->id, $group2->id));
     }
 
     /**
      * Test delete_groups
+     *
+     * @expectedException required_capability_exception
      */
     public function test_delete_groups() {
         global $DB;
@@ -223,7 +227,6 @@ class core_group_externallib_testcase extends externallib_advanced_testcase {
 
         // Call without required capability
         $this->unassignUserCapability('moodle/course:managegroups', $context->id, $roleid);
-        $this->setExpectedException('required_capability_exception');
         $froups = core_group_external::delete_groups(array($group3->id));
     }
 
index aa19259..9e1ee63 100644 (file)
@@ -743,6 +743,9 @@ $string['eventcoursesectionupdated'] = 'Course section updated';
 $string['eventcoursemoduleinstancelistviewed'] = 'Course module instance list viewed';
 $string['eventcourseuserreportviewed'] = 'Course user report viewed';
 $string['eventcourseviewed'] = 'Course viewed';
+$string['eventdashboardreset'] = 'Dashboard reset';
+$string['eventdashboardsreset'] = 'Dashboards reset';
+$string['eventdashboardviewed'] = 'Dashboard viewed';
 $string['eventemailfailed'] = 'Email failed to send';
 $string['eventname'] = 'Event name';
 $string['eventrecentactivityviewed'] = 'Recent activity viewed';
@@ -1680,6 +1683,7 @@ $string['showallcourses'] = 'Show all courses';
 $string['showallusers'] = 'Show all users';
 $string['showblockcourse'] = 'Show list of courses containing block';
 $string['showcategory'] = 'Show {$a}';
+$string['showchartdata'] = 'Show chart data';
 $string['showcomments'] = 'Show/hide comments';
 $string['showcommentsnonjs'] = 'Show comments';
 $string['showdescription'] = 'Display description on course page';
index bfe296c..f9e4da9 100644 (file)
@@ -47,7 +47,8 @@ $string['documentsinindex'] = 'Documents in index';
 $string['duration'] = 'Duration';
 $string['emptydatabaseerror'] = 'Database table is not present, or contains no index records.';
 $string['enginenotfound'] = 'Engine {$a} not found.';
-$string['enginenotinstalled'] = '{$a} not installed.';
+$string['enginenotinstalled'] = 'Engine {$a} not installed.';
+$string['enginenotselected'] = 'You have not selected any search engine.';
 $string['engineserverstatus'] = 'The search engine is not available. Please contact your administrator.';
 $string['enteryoursearchquery'] = 'Enter your search query';
 $string['errors'] = 'Errors';
diff --git a/lib/amd/build/chart_axis.min.js b/lib/amd/build/chart_axis.min.js
new file mode 100644 (file)
index 0000000..22ebd64
Binary files /dev/null and b/lib/amd/build/chart_axis.min.js differ
diff --git a/lib/amd/build/chart_bar.min.js b/lib/amd/build/chart_bar.min.js
new file mode 100644 (file)
index 0000000..05364fd
Binary files /dev/null and b/lib/amd/build/chart_bar.min.js differ
diff --git a/lib/amd/build/chart_base.min.js b/lib/amd/build/chart_base.min.js
new file mode 100644 (file)
index 0000000..f78a3a3
Binary files /dev/null and b/lib/amd/build/chart_base.min.js differ
diff --git a/lib/amd/build/chart_builder.min.js b/lib/amd/build/chart_builder.min.js
new file mode 100644 (file)
index 0000000..c746f31
Binary files /dev/null and b/lib/amd/build/chart_builder.min.js differ
diff --git a/lib/amd/build/chart_line.min.js b/lib/amd/build/chart_line.min.js
new file mode 100644 (file)
index 0000000..042acb2
Binary files /dev/null and b/lib/amd/build/chart_line.min.js differ
diff --git a/lib/amd/build/chart_output.min.js b/lib/amd/build/chart_output.min.js
new file mode 100644 (file)
index 0000000..65c0f11
Binary files /dev/null and b/lib/amd/build/chart_output.min.js differ
diff --git a/lib/amd/build/chart_output_base.min.js b/lib/amd/build/chart_output_base.min.js
new file mode 100644 (file)
index 0000000..8bdebe6
Binary files /dev/null and b/lib/amd/build/chart_output_base.min.js differ
diff --git a/lib/amd/build/chart_output_chartjs.min.js b/lib/amd/build/chart_output_chartjs.min.js
new file mode 100644 (file)
index 0000000..fdc8e84
Binary files /dev/null and b/lib/amd/build/chart_output_chartjs.min.js differ
diff --git a/lib/amd/build/chart_output_htmltable.min.js b/lib/amd/build/chart_output_htmltable.min.js
new file mode 100644 (file)
index 0000000..cea5152
Binary files /dev/null and b/lib/amd/build/chart_output_htmltable.min.js differ
diff --git a/lib/amd/build/chart_pie.min.js b/lib/amd/build/chart_pie.min.js
new file mode 100644 (file)
index 0000000..aab6464
Binary files /dev/null and b/lib/amd/build/chart_pie.min.js differ
diff --git a/lib/amd/build/chart_series.min.js b/lib/amd/build/chart_series.min.js
new file mode 100644 (file)
index 0000000..c913cdb
Binary files /dev/null and b/lib/amd/build/chart_series.min.js differ
diff --git a/lib/amd/build/chartjs-lazy.min.js b/lib/amd/build/chartjs-lazy.min.js
new file mode 100644 (file)
index 0000000..0361ea9
Binary files /dev/null and b/lib/amd/build/chartjs-lazy.min.js differ
diff --git a/lib/amd/build/chartjs.min.js b/lib/amd/build/chartjs.min.js
new file mode 100644 (file)
index 0000000..c085a29
Binary files /dev/null and b/lib/amd/build/chartjs.min.js differ
index 86a6407..39b9bb5 100644 (file)
Binary files a/lib/amd/build/event.min.js and b/lib/amd/build/event.min.js differ
diff --git a/lib/amd/src/chart_axis.js b/lib/amd/src/chart_axis.js
new file mode 100644 (file)
index 0000000..1ec5234
--- /dev/null
@@ -0,0 +1,299 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart axis.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_axis
+ */
+define([], function() {
+
+    /**
+     * Chart axis class.
+     *
+     * This is used to represent an axis, whether X or Y.
+     *
+     * @alias module:core/chart_axis
+     * @class
+     */
+    function Axis() {
+        // Please eslint no-empty-function.
+    }
+
+    /**
+     * Default axis position.
+     * @const {Null}
+     */
+    Axis.prototype.POS_DEFAULT = null;
+
+    /**
+     * Bottom axis position.
+     * @const {String}
+     */
+    Axis.prototype.POS_BOTTOM = 'bottom';
+
+    /**
+     * Left axis position.
+     * @const {String}
+     */
+    Axis.prototype.POS_LEFT = 'left';
+
+    /**
+     * Right axis position.
+     * @const {String}
+     */
+    Axis.prototype.POS_RIGHT = 'right';
+
+    /**
+     * Top axis position.
+     * @const {String}
+     */
+    Axis.prototype.POS_TOP = 'top';
+
+    /**
+     * Label of the axis.
+     * @type {String}
+     * @protected
+     */
+    Axis.prototype._label = null;
+
+    /**
+     * Labels of the ticks.
+     * @type {String[]}
+     * @protected
+     */
+    Axis.prototype._labels = null;
+
+    /**
+     * Maximum value of the axis.
+     * @type {Number}
+     * @protected
+     */
+    Axis.prototype._max = null;
+
+    /**
+     * Minimum value of the axis.
+     * @type {Number}
+     * @protected
+     */
+    Axis.prototype._min = null;
+
+    /**
+     * Position of the axis.
+     * @type {String}
+     * @protected
+     */
+    Axis.prototype._position = null;
+
+    /**
+     * Steps on the axis.
+     * @type {Number}
+     * @protected
+     */
+    Axis.prototype._stepSize = null;
+
+    /**
+     * Create a new instance of an axis from serialised data.
+     *
+     * @static
+     * @method create
+     * @param {Object} obj The data of the axis.
+     * @return {module:core/chart_axis}
+     */
+    Axis.prototype.create = function(obj) {
+        var s = new Axis();
+        s.setPosition(obj.position);
+        s.setLabel(obj.label);
+        s.setStepSize(obj.stepSize);
+        s.setMax(obj.max);
+        s.setMin(obj.min);
+        s.setLabels(obj.labels);
+        return s;
+    };
+
+    /**
+     * Get the label of the axis.
+     *
+     * @method getLabel
+     * @return {String}
+     */
+    Axis.prototype.getLabel = function() {
+        return this._label;
+    };
+
+    /**
+     * Get the labels of the ticks of the axis.
+     *
+     * @method getLabels
+     * @return {String[]}
+     */
+    Axis.prototype.getLabels = function() {
+        return this._labels;
+    };
+
+    /**
+     * Get the maximum value of the axis.
+     *
+     * @method getMax
+     * @return {Number}
+     */
+    Axis.prototype.getMax = function() {
+        return this._max;
+    };
+
+    /**
+     * Get the minimum value of the axis.
+     *
+     * @method getMin
+     * @return {Number}
+     */
+    Axis.prototype.getMin = function() {
+        return this._min;
+    };
+
+    /**
+     * Get the position of the axis.
+     *
+     * @method getPosition
+     * @return {String}
+     */
+    Axis.prototype.getPosition = function() {
+        return this._position;
+    };
+
+    /**
+     * Get the step size of the axis.
+     *
+     * @method getStepSize
+     * @return {Number}
+     */
+    Axis.prototype.getStepSize = function() {
+        return this._stepSize;
+    };
+
+    /**
+     * Set the label of the axis.
+     *
+     * @method setLabel
+     * @param {String} label The label.
+     */
+    Axis.prototype.setLabel = function(label) {
+        this._label = label || null;
+    };
+
+    /**
+     * Set the labels of the values on the axis.
+     *
+     * This automatically sets the [_stepSize]{@link module:core/chart_axis#_stepSize},
+     * [_min]{@link module:core/chart_axis#_min} and [_max]{@link module:core/chart_axis#_max}
+     * to define a scale from 0 to the number of labels when none of the previously
+     * mentioned values have been modified.
+     *
+     * You can use other values so long that your values in a series are mapped
+     * to the values represented by your _min, _max and _stepSize.
+     *
+     * @method setLabels
+     * @param {String[]} labels The labels.
+     */
+    Axis.prototype.setLabels = function(labels) {
+        this._labels = labels || null;
+
+        // By default we set the grid according to the labels.
+        if (this._labels !== null
+                && this._stepSize === null
+                && (this._min === null || this._min === 0)
+                && this._max === null) {
+            this.setStepSize(1);
+            this.setMin(0);
+            this.setMax(labels.length - 1);
+        }
+    };
+
+    /**
+     * Set the maximum value on the axis.
+     *
+     * When this is not set (or set to null) it is left for the output
+     * library to best guess what should be used.
+     *
+     * @method setMax
+     * @param {Number} max The value.
+     */
+    Axis.prototype.setMax = function(max) {
+        this._max = typeof max !== 'undefined' ? max : null;
+    };
+
+    /**
+     * Set the minimum value on the axis.
+     *
+     * When this is not set (or set to null) it is left for the output
+     * library to best guess what should be used.
+     *
+     * @method setMin
+     * @param {Number} min The value.
+     */
+    Axis.prototype.setMin = function(min) {
+        this._min = typeof min !== 'undefined' ? min : null;
+    };
+
+    /**
+     * Set the position of the axis.
+     *
+     * This does not validate whether or not the constant used is valid
+     * as the axis itself is not aware whether it represents the X or Y axis.
+     *
+     * The output library has to have a fallback in case the values are incorrect.
+     * When this is not set to {@link module:core/chart_axis#POS_DEFAULT} it is up
+     * to the output library to choose what position fits best.
+     *
+     * @method setPosition
+     * @param {String} position The value.
+     */
+    Axis.prototype.setPosition = function(position) {
+        if (position != this.POS_DEFAULT
+                && position != this.POS_BOTTOM
+                && position != this.POS_LEFT
+                && position != this.POS_RIGHT
+                && position != this.POS_TOP) {
+            throw new Error('Invalid axis position.');
+        }
+        this._position = position;
+    };
+
+    /**
+     * Set the stepSize on the axis.
+     *
+     * This is used to determine where ticks are displayed on the axis between min and max.
+     *
+     * @method setStepSize
+     * @param {Number} stepSize The value.
+     */
+    Axis.prototype.setStepSize = function(stepSize) {
+        if (typeof stepSize === 'undefined' || stepSize === null) {
+            stepSize = null;
+        } else if (isNaN(Number(stepSize))) {
+            throw new Error('Value for stepSize is not a number.');
+        } else {
+            stepSize = Number(stepSize);
+        }
+
+        this._stepSize = stepSize;
+    };
+
+    return Axis;
+
+});
diff --git a/lib/amd/src/chart_bar.js b/lib/amd/src/chart_bar.js
new file mode 100644 (file)
index 0000000..13c5596
--- /dev/null
@@ -0,0 +1,89 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart bar.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_bar
+ */
+define(['core/chart_base'], function(Base) {
+
+    /**
+     * Bar chart.
+     *
+     * @alias module:core/chart_bar
+     * @extends {module:core/chart_base}
+     * @class
+     */
+    function Bar() {
+        Base.prototype.constructor.apply(this, arguments);
+    }
+    Bar.prototype = Object.create(Base.prototype);
+
+    /**
+     * Whether the bars should be displayed horizontally or not.
+     *
+     * @type {Bool}
+     * @protected
+     */
+    Bar.prototype._horizontal = false;
+
+    /** @override */
+    Bar.prototype.TYPE = 'bar';
+
+    /** @override */
+    Bar.prototype.create = function(Klass, data) {
+        var chart = Base.prototype.create.apply(this, arguments);
+        chart.setHorizontal(data.horizontal);
+        return chart;
+    };
+
+    /** @override */
+    Bar.prototype._setDefaults = function() {
+        Base.prototype._setDefaults.apply(this, arguments);
+        var axis = this.getYAxis(0, true);
+        axis.setMin(0);
+    };
+
+    /**
+     * Get whether the bars should be displayed horizontally or not.
+     *
+     * @returns {Bool}
+     */
+    Bar.prototype.getHorizontal = function() {
+        return this._horizontal;
+    };
+
+    /**
+     * Set whether the bars should be displayed horizontally or not.
+     *
+     * It sets the X Axis to zero if the min value is null.
+     *
+     * @param {Bool} horizontal True if the bars should be displayed horizontally, false otherwise.
+     */
+    Bar.prototype.setHorizontal = function(horizontal) {
+        var axis = this.getXAxis(0, true);
+        if (axis.getMin() === null) {
+            axis.setMin(0);
+        }
+        this._horizontal = Boolean(horizontal);
+    };
+
+    return Bar;
+
+});
diff --git a/lib/amd/src/chart_base.js b/lib/amd/src/chart_base.js
new file mode 100644 (file)
index 0000000..58bfe40
--- /dev/null
@@ -0,0 +1,359 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart base.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_base
+ */
+define(['core/chart_series', 'core/chart_axis'], function(Series, Axis) {
+
+    /**
+     * Chart base.
+     *
+     * The constructor of a chart must never take any argument.
+     *
+     * {@link module:core/chart_base#_setDefault} to set the defaults on instantiation.
+     *
+     * @alias module:core/chart_base
+     * @class
+     */
+    function Base() {
+        this._series = [];
+        this._labels = [];
+        this._xaxes = [];
+        this._yaxes = [];
+
+        this._setDefaults();
+    }
+
+    /**
+     * The series constituting this chart.
+     *
+     * @protected
+     * @type {module:core/chart_series[]}
+     */
+    Base.prototype._series = null;
+
+    /**
+     * The labels of the X axis when categorised.
+     *
+     * @protected
+     * @type {String[]}
+     */
+    Base.prototype._labels = null;
+
+    /**
+     * The title of the chart.
+     *
+     * @protected
+     * @type {String}
+     */
+    Base.prototype._title = null;
+
+    /**
+     * The X axes.
+     *
+     * @protected
+     * @type {module:core/chart_axis[]}
+     */
+    Base.prototype._xaxes = null;
+
+    /**
+     * The Y axes.
+     *
+     * @protected
+     * @type {module:core/chart_axis[]}
+     */
+    Base.prototype._yaxes = null;
+
+    /**
+     * Colours to pick from when automatically assigning them.
+     *
+     * @const
+     * @type {String[]}
+     */
+    Base.prototype.COLORSET = ['#f3c300', '#875692', '#f38400', '#a1caf1', '#be0032', '#c2b280', '#7f180d', '#008856',
+            '#e68fac', '#0067a5'];
+
+    /**
+     * The type of chart.
+     *
+     * @abstract
+     * @type {String}
+     * @const
+     */
+    Base.prototype.TYPE = null;
+
+    /**
+     * Add a series to the chart.
+     *
+     * This will automatically assign a color to the series if it does not have one.
+     *
+     * @param {module:core/chart_series} series The series to add.
+     */
+    Base.prototype.addSeries = function(series) {
+        this._validateSeries(series);
+        this._series.push(series);
+
+        // Give a default color from the set.
+        if (series.getColor() === null) {
+            series.setColor(Base.prototype.COLORSET[this._series.length % Base.prototype.COLORSET.length]);
+        }
+    };
+
+    /**
+     * Create a new instance of a chart from serialised data.
+     *
+     * the serialised attributes they offer and support.
+     *
+     * @static
+     * @method create
+     * @param {module:core/chart_base} Klass The class oject representing the type of chart to instantiate.
+     * @param {Object} data The data of the chart.
+     * @return {module:core/chart_base}
+     */
+    Base.prototype.create = function(Klass, data) {
+        // TODO Not convinced about the usage of Klass here but I can't figure out a way
+        // to have a reference to the class in the sub classes, in PHP I'd do new self().
+        var Chart = new Klass();
+
+        Chart.setLabels(data.labels);
+        Chart.setTitle(data.title);
+        data.series.forEach(function(seriesData) {
+            Chart.addSeries(Series.prototype.create(seriesData));
+        });
+        data.axes.x.forEach(function(axisData, i) {
+            Chart.setXAxis(Axis.prototype.create(axisData), i);
+        });
+        data.axes.y.forEach(function(axisData, i) {
+            Chart.setYAxis(Axis.prototype.create(axisData), i);
+        });
+        return Chart;
+    };
+
+    /**
+     * Get an axis.
+     *
+     * @private
+     * @param {String} xy Accepts the values 'x' or 'y'.
+     * @param {Number} [index=0] The index of the axis of its type.
+     * @param {Bool} [createIfNotExists=false] When true, create an instance if it does not exist.
+     * @return {module:core/chart_axis}
+     */
+    Base.prototype.__getAxis = function(xy, index, createIfNotExists) {
+        var axes = xy === 'x' ? this._xaxes : this._yaxes,
+            setAxis = (xy === 'x' ? this.setXAxis : this.setYAxis).bind(this),
+            axis;
+
+        index = typeof index === 'undefined' ? 0 : index;
+        createIfNotExists = typeof createIfNotExists === 'undefined' ? false : createIfNotExists;
+        axis = axes[index];
+
+        if (typeof axis === 'undefined') {
+            if (!createIfNotExists) {
+                throw new Error('Unknown axis.');
+            }
+            axis = new Axis();
+            setAxis(axis, index);
+        }
+
+        return axis;
+    };
+
+    /**
+     * Get the labels of the X axis.
+     *
+     * @return {String[]}
+     */
+    Base.prototype.getLabels = function() {
+        return this._labels;
+    };
+
+    /**
+     * Get the series.
+     *
+     * @return {module:core/chart_series[]}
+     */
+    Base.prototype.getSeries = function() {
+        return this._series;
+    };
+
+    /**
+     * Get the title of the chart.
+     *
+     * @return {String}
+     */
+    Base.prototype.getTitle = function() {
+        return this._title;
+    };
+
+    /**
+     * Get the type of chart.
+     *
+     * @see module:core/chart_base#TYPE
+     * @return {String}
+     */
+    Base.prototype.getType = function() {
+        if (!this.TYPE) {
+            throw new Error('The TYPE property has not been set.');
+        }
+        return this.TYPE;
+    };
+
+    /**
+     * Get the X axes.
+     *
+     * @return {module:core/chart_axis[]}
+     */
+    Base.prototype.getXAxes = function() {
+        return this._xaxes;
+    };
+
+    /**
+     * Get an X axis.
+     *
+     * @param {Number} [index=0] The index of the axis.
+     * @param {Bool} [createIfNotExists=false] Create the instance of it does not exist at index.
+     * @return {module:core/chart_axis}
+     */
+    Base.prototype.getXAxis = function(index, createIfNotExists) {
+        return this.__getAxis('x', index, createIfNotExists);
+    };
+
+    /**
+     * Get the Y axes.
+     *
+     * @return {module:core/chart_axis[]}
+     */
+    Base.prototype.getYAxes = function() {
+        return this._yaxes;
+    };
+
+    /**
+     * Get an Y axis.
+     *
+     * @param {Number} [index=0] The index of the axis.
+     * @param {Bool} [createIfNotExists=false] Create the instance of it does not exist at index.
+     * @return {module:core/chart_axis}
+     */
+    Base.prototype.getYAxis = function(index, createIfNotExists) {
+        return this.__getAxis('y', index, createIfNotExists);
+    };
+
+    /**
+     * Set the defaults for this chart type.
+     *
+     * Child classes can extend this to set defaults values on instantiation.
+     *
+     * emphasize and self-document the defaults values set by the chart type.
+     *
+     * @protected
+     */
+    Base.prototype._setDefaults = function() {
+        // For the children to extend.
+    };
+
+    /**
+     * Set the labels of the X axis.
+     *
+     * This requires for each series to contain strictly as many values as there
+     * are labels.
+     *
+     * @param {String[]} labels The labels.
+     */
+    Base.prototype.setLabels = function(labels) {
+        if (labels.length && this._series.length && this._series[0].length != labels.length) {
+            throw new Error('Series must match label values.');
+        }
+        this._labels = labels;
+    };
+
+    /**
+     * Set the title of the chart.
+     *
+     * @param {String} title The title.
+     */
+    Base.prototype.setTitle = function(title) {
+        this._title = title;
+    };
+
+    /**
+     * Set an X axis.
+     *
+     * Note that this will override any predefined axis without warning.
+     *
+     * @param {module:core/chart_axis} axis The axis.
+     * @param {Number} [index=0] The index of the axis.
+     */
+    Base.prototype.setXAxis = function(axis, index) {
+        index = typeof index === 'undefined' ? 0 : index;
+        this._validateAxis('x', axis, index);
+        this._xaxes[index] = axis;
+    };
+
+    /**
+     * Set a Y axis.
+     *
+     * Note that this will override any predefined axis without warning.
+     *
+     * @param {module:core/chart_axis} axis The axis.
+     * @param {Number} [index=0] The index of the axis.
+     */
+    Base.prototype.setYAxis = function(axis, index) {
+        index = typeof index === 'undefined' ? 0 : index;
+        this._validateAxis('y', axis, index);
+        this._yaxes[index] = axis;
+    };
+
+    /**
+     * Validate an axis.
+     *
+     * @protected
+     * @param {String} xy X or Y axis.
+     * @param {module:core/chart_axis} axis The axis to validate.
+     * @param {Number} [index=0] The index of the axis.
+     */
+    Base.prototype._validateAxis = function(xy, axis, index) {
+        index = typeof index === 'undefined' ? 0 : index;
+        if (index > 0) {
+            var axes = xy == 'x' ? this._xaxes : this._yaxes;
+            if (typeof axes[index - 1] === 'undefined') {
+                throw new Error('Missing ' + xy + ' axis at index lower than ' + index);
+            }
+        }
+    };
+
+    /**
+     * Validate a series.
+     *
+     * @protected
+     * @param {module:core/chart_series} series The series to validate.
+     */
+    Base.prototype._validateSeries = function(series) {
+        if (this._series.length && this._series[0].getCount() != series.getCount()) {
+            throw new Error('Series do not have an equal number of values.');
+
+        } else if (this._labels.length && this._labels.length != series.getCount()) {
+            throw new Error('Series must match label values.');
+        }
+    };
+
+    return Base;
+
+});
diff --git a/lib/amd/src/chart_builder.js b/lib/amd/src/chart_builder.js
new file mode 100644 (file)
index 0000000..5978c89
--- /dev/null
@@ -0,0 +1,53 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart builder.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery'], function($) {
+
+    /**
+     * Chart builder.
+     *
+     * @exports core/chart_builder
+     */
+    var module = {
+
+        /**
+         * Make a chart instance.
+         *
+         * This takes data, most likely generated in PHP, and creates a chart instance from it
+         * deferring most of the logic to {@link module:core/chart_base.create}.
+         *
+         * @param {Object} data The data.
+         * @return {Promise} A promise resolved with the chart instance.
+         */
+        make: function(data) {
+            var deferred = $.Deferred();
+            require(['core/chart_' + data.type], function(Klass) {
+                var instance = Klass.prototype.create(Klass, data);
+                deferred.resolve(instance);
+            });
+            return deferred.promise();
+        }
+    };
+
+    return module;
+
+});
diff --git a/lib/amd/src/chart_line.js b/lib/amd/src/chart_line.js
new file mode 100644 (file)
index 0000000..07ccb9b
--- /dev/null
@@ -0,0 +1,80 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart line.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_line
+ */
+define(['core/chart_base'], function(Base) {
+
+    /**
+     * Line chart.
+     *
+     * @alias module:core/chart_line
+     * @extends {module:core/chart_base}
+     * @class
+     */
+    function Line() {
+        Base.prototype.constructor.apply(this, arguments);
+    }
+    Line.prototype = Object.create(Base.prototype);
+
+    /** @override */
+    Line.prototype.TYPE = 'line';
+
+    /**
+     * Whether the line should be smooth or not.
+     *
+     * By default the chart lines are not smooth.
+     *
+     * @type {Bool}
+     * @protected
+     */
+    Line.prototype._smooth = false;
+
+    /** @override */
+    Line.prototype.create = function(Klass, data) {
+        var chart = Base.prototype.create.apply(this, arguments);
+        chart.setSmooth(data.smooth);
+        return chart;
+    };
+
+    /**
+     * Get whether the line should be smooth or not.
+     *
+     * @method getSmooth
+     * @returns {Bool}
+     */
+    Line.prototype.getSmooth = function() {
+        return this._smooth;
+    };
+
+    /**
+     * Set whether the line should be smooth or not.
+     *
+     * @method setSmooth
+     * @param {Bool} smooth True if the line chart should be smooth, false otherwise.
+     */
+    Line.prototype.setSmooth = function(smooth) {
+        this._smooth = Boolean(smooth);
+    };
+
+    return Line;
+
+});
diff --git a/lib/amd/src/chart_output.js b/lib/amd/src/chart_output.js
new file mode 100644 (file)
index 0000000..6848841
--- /dev/null
@@ -0,0 +1,35 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart output.
+ *
+ * Proxy to the default output module.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['core/chart_output_chartjs'], function(Output) {
+
+    /**
+     * @exports module:core/chart_output
+     * @extends {module:core/chart_output_chartjs}
+     */
+    var defaultModule = Output;
+
+    return defaultModule;
+
+});
diff --git a/lib/amd/src/chart_output_base.js b/lib/amd/src/chart_output_base.js
new file mode 100644 (file)
index 0000000..ac256e7
--- /dev/null
@@ -0,0 +1,66 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart output base.
+ *
+ * This takes a chart object and draws it.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_output_base
+ */
+define(['jquery'], function($) {
+
+    /**
+     * Chart output base.
+     *
+     * The constructor of an output class must instantly generate and display the
+     * chart. It is also the responsability of the output module to check that
+     * the node received is of the appropriate type, if not a new node can be
+     * added within.
+     *
+     * The output module has total control over the content of the node and can
+     * clear it or output anything to it at will. A node should not be shared by
+     * two simultaneous output modules.
+     *
+     * @class
+     * @alias module:core/chart_output_base
+     * @param {Node} node The node to output with/in.
+     * @param {Chart} chart A chart object.
+     */
+    function Base(node, chart) {
+        this._node = $(node);
+        this._chart = chart;
+    }
+
+    /**
+     * Update method.
+     *
+     * This is the public method through which an output instance in informed
+     * that the chart instance has been updated and they need to update the
+     * chart rendering.
+     *
+     * @abstract
+     * @return {Void}
+     */
+    Base.prototype.update = function() {
+        throw new Error('Not supported.');
+    };
+
+    return Base;
+
+});
diff --git a/lib/amd/src/chart_output_chartjs.js b/lib/amd/src/chart_output_chartjs.js
new file mode 100644 (file)
index 0000000..b0075f2
--- /dev/null
@@ -0,0 +1,312 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart output for chart.js.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_output_chartjs
+ */
+define([
+    'jquery',
+    'core/chartjs',
+    'core/chart_axis',
+    'core/chart_bar',
+    'core/chart_output_base',
+    'core/chart_line',
+    'core/chart_pie',
+    'core/chart_series'
+], function($, Chartjs, Axis, Bar, Base, Line, Pie, Series) {
+
+    /**
+     * Makes an axis ID.
+     *
+     * @param {String} xy Accepts 'x' and 'y'.
+     * @param {Number} index The axis index.
+     * @return {String}
+     */
+    var makeAxisId = function(xy, index) {
+        return 'axis-' + xy + '-' + index;
+    };
+
+    /**
+     * Chart output for Chart.js.
+     *
+     * @class
+     * @alias module:core/chart_output_chartjs
+     * @extends {module:core/chart_output_base}
+     */
+    function Output() {
+        Base.prototype.constructor.apply(this, arguments);
+
+        // Make sure that we've got a canvas tag.
+        this._canvas = this._node;
+        if (this._canvas.prop('tagName') != 'CANVAS') {
+            this._canvas = $('<canvas>');
+            this._node.append(this._canvas);
+        }
+
+        this._build();
+    }
+    Output.prototype = Object.create(Base.prototype);
+
+    /**
+     * Reference to the chart config object.
+     *
+     * @type {Object}
+     * @protected
+     */
+    Output.prototype._config = null;
+
+    /**
+     * Reference to the instance of chart.js.
+     *
+     * @type {Object}
+     * @protected
+     */
+    Output.prototype._chartjs = null;
+
+    /**
+     * Reference to the canvas node.
+     *
+     * @type {Jquery}
+     * @protected
+     */
+    Output.prototype._canvas = null;
+
+    /**
+     * Builds the config and the chart.
+     *
+     * @protected
+     */
+    Output.prototype._build = function() {
+        this._config = this._makeConfig();
+        this._chartjs = new Chartjs(this._canvas[0], this._config);
+    };
+
+    /**
+     * Get the chart type.
+     *
+     * It also handles the bar charts positioning, deciding if the bars should be displayed horizontally.
+     * Otherwise, get the chart TYPE value.
+     *
+     * @returns {String} the chart type.
+     * @protected
+     */
+    Output.prototype._getChartType = function() {
+        var type = this._chart.getType();
+
+        // Bars can be displayed vertically and horizontally, defining horizontalBar type.
+        if (this._chart.getType() === Bar.prototype.TYPE && this._chart.getHorizontal() === true) {
+            type = 'horizontalBar';
+        }
+
+        return type;
+    };
+
+    /**
+     * Make the axis config.
+     *
+     * @protected
+     * @param {module:core/chart_axis} axis The axis.
+     * @param {String} xy Accepts 'x' or 'y'.
+     * @param {Number} index The axis index.
+     * @return {Object} The axis config.
+     */
+    Output.prototype._makeAxisConfig = function(axis, xy, index) {
+        var scaleData = {
+            id: makeAxisId(xy, index)
+        };
+
+        if (axis.getPosition() !== Axis.prototype.POS_DEFAULT) {
+            scaleData.position = axis.getPosition();
+        }
+
+        if (axis.getLabel() !== null) {
+            scaleData.scaleLabel = {
+                display: true,
+                labelString: axis.getLabel()
+            };
+        }
+
+        if (axis.getStepSize() !== null) {
+            scaleData.ticks = scaleData.ticks || {};
+            scaleData.ticks.stepSize = axis.getStepSize();
+        }
+
+        if (axis.getMax() !== null) {
+            scaleData.ticks = scaleData.ticks || {};
+            scaleData.ticks.max = axis.getMax();
+        }
+
+        if (axis.getMin() !== null) {
+            scaleData.ticks = scaleData.ticks || {};
+            scaleData.ticks.min = axis.getMin();
+        }
+
+        return scaleData;
+    };
+
+    /**
+     * Make the config config.
+     *
+     * @protected
+     * @param {module:core/chart_axis} axis The axis.
+     * @return {Object} The axis config.
+     */
+    Output.prototype._makeConfig = function() {
+        var config = {
+            type: this._getChartType(),
+            data: {
+                labels: this._chart.getLabels(),
+                datasets: this._makeDatasetsConfig()
+            },
+            options: {
+                title: {
+                    display: this._chart.getTitle() !== null,
+                    text: this._chart.getTitle()
+                }
+            }
+        };
+
+        this._chart.getXAxes().forEach(function(axis, i) {
+            var axisLabels = axis.getLabels();
+
+            config.options.scales = config.options.scales || {};
+            config.options.scales.xAxes = config.options.scales.xAxes || [];
+            config.options.scales.xAxes[i] = this._makeAxisConfig(axis, 'x', i);
+
+            if (axisLabels !== null) {
+                config.options.scales.xAxes[i].ticks.callback = function(value, index) {
+                    return axisLabels[index] || '';
+                };
+            }
+        }.bind(this));
+
+        this._chart.getYAxes().forEach(function(axis, i) {
+            var axisLabels = axis.getLabels();
+
+            config.options.scales = config.options.scales || {};
+            config.options.scales.yAxes = config.options.scales.yAxes || [];
+            config.options.scales.yAxes[i] = this._makeAxisConfig(axis, 'y', i);
+
+            if (axisLabels !== null) {
+                config.options.scales.yAxes[i].ticks.callback = function(value) {
+                    return axisLabels[parseInt(value, 10)] || '';
+                };
+            }
+        }.bind(this));
+
+        config.options.tooltips = {
+            callbacks: {
+                label: this._makeTooltip.bind(this)
+            }
+        };
+
+        return config;
+    };
+
+    /**
+     * Get the datasets configurations.
+     *
+     * @protected
+     * @return {Object[]}
+     */
+    Output.prototype._makeDatasetsConfig = function() {
+        var sets = this._chart.getSeries().map(function(series) {
+            var colors = series.hasColoredValues() ? series.getColors() : series.getColor();
+            var dataset = {
+                label: series.getLabel(),
+                data: series.getValues(),
+                type: series.getType(),
+                fill: false,
+                backgroundColor: colors,
+                // Pie charts look better without borders.
+                borderColor: this._chart.getType() == Pie.prototype.TYPE ? null : colors,
+                lineTension: this._isSmooth(series) ? 0.3 : 0
+            };
+
+            if (series.getXAxis() !== null) {
+                dataset.xAxisID = makeAxisId('x', series.getXAxis());
+            }
+            if (series.getYAxis() !== null) {
+                dataset.yAxisID = makeAxisId('y', series.getYAxis());
+            }
+
+            return dataset;
+        }.bind(this));
+        return sets;
+    };
+
+    /**
+     * Get the chart data, add labels and rebuild the tooltip.
+     *
+     * @param {Object[]} tooltipItem The tooltip item data.
+     * @param {Object[]} data The chart data.
+     * @returns {String}
+     * @protected
+     */
+    Output.prototype._makeTooltip = function(tooltipItem, data) {
+
+        // Get series and chart data to rebuild the tooltip and add labels.
+        var series = this._chart.getSeries()[tooltipItem.datasetIndex];
+        var serieLabel = series.getLabel();
+        var serieLabels = series.getLabels();
+        var chartData = data.datasets[tooltipItem.datasetIndex].data;
+        var tooltipData = chartData[tooltipItem.index];
+
+        // Build default tooltip.
+        var tooltip = serieLabel + ': ' + tooltipData;
+
+        // Add serie labels to the tooltip if any.
+        if (serieLabels !== null) {
+            tooltip += ' ' + serieLabels[tooltipItem.index];
+        }
+
+        return tooltip;
+    };
+
+    /**
+     * Verify if the chart line is smooth or not.
+     *
+     * @protected
+     * @param {module:core/chart_series} series The series.
+     * @returns {Bool}
+     */
+    Output.prototype._isSmooth = function(series) {
+        var smooth = false;
+        if (this._chart.getType() === Line.prototype.TYPE) {
+            smooth = series.getSmooth();
+            if (smooth === null) {
+                smooth = this._chart.getSmooth();
+            }
+        } else if (series.getType() === Series.prototype.TYPE_LINE) {
+            smooth = series.getSmooth();
+        }
+
+        return smooth;
+    };
+
+    /** @override */
+    Output.prototype.update = function() {
+        $.extend(true, this._config, this._makeConfig());
+        this._chartjs.update();
+    };
+
+    return Output;
+
+});
diff --git a/lib/amd/src/chart_output_htmltable.js b/lib/amd/src/chart_output_htmltable.js
new file mode 100644 (file)
index 0000000..ab55bbd
--- /dev/null
@@ -0,0 +1,122 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart output for HTML table.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_output_htmltable
+ */
+define([
+    'jquery',
+    'core/chart_output_base',
+], function($, Base) {
+
+    /**
+     * Render a chart as an HTML table.
+     *
+     * @class
+     * @extends {module:core/chart_output_base}
+     * @alias module:core/chart_output_htmltable
+     */
+    function Output() {
+        Base.prototype.constructor.apply(this, arguments);
+        this._build();
+    }
+    Output.prototype = Object.create(Base.prototype);
+
+    /**
+     * Attach the table to the document.
+     *
+     * @protected
+     */
+    Output.prototype._build = function() {
+        this._node.empty();
+        this._node.append(this._makeTable());
+    };
+
+    /**
+     * Builds the table node.
+     *
+     * @protected
+     * @return {Jquery}
+     */
+    Output.prototype._makeTable = function() {
+        var tbl = $('<table>'),
+            c = this._chart,
+            node,
+            value,
+            labels = c.getLabels(),
+            hasLabel = labels.length > 0,
+            series = c.getSeries(),
+            seriesLabels,
+            rowCount = series[0].getCount();
+
+        // Identify the table.
+        tbl.addClass('chart-output-htmltable');
+
+        // Set the caption.
+        if (c.getTitle() !== null) {
+            tbl.append($('<caption>').text(c.getTitle()));
+        }
+
+        // Write the column headers.
+        node = $('<tr>');
+        if (hasLabel) {
+            node.append($('<td>'));
+        }
+        series.forEach(function(serie) {
+            node.append(
+                $('<th>')
+                .text(serie.getLabel())
+                .attr('scope', 'col')
+            );
+        });
+        tbl.append(node);
+
+        // Write rows.
+        for (var rowId = 0; rowId < rowCount; rowId++) {
+            node = $('<tr>');
+            if (labels.length > 0) {
+                node.append(
+                    $('<th>')
+                    .text(labels[rowId])
+                    .attr('scope', 'row')
+                );
+            }
+            for (var serieId = 0; serieId < series.length; serieId++) {
+                value = series[serieId].getValues()[rowId];
+                seriesLabels = series[serieId].getLabels();
+                if (seriesLabels !== null) {
+                    value += ' ' + series[serieId].getLabels()[rowId];
+                }
+                node.append($('<td>').text(value));
+            }
+            tbl.append(node);
+        }
+
+        return tbl;
+    };
+
+    /** @override */
+    Output.prototype.update = function() {
+        this._build();
+    };
+
+    return Output;
+
+});
diff --git a/lib/amd/src/chart_pie.js b/lib/amd/src/chart_pie.js
new file mode 100644 (file)
index 0000000..632e109
--- /dev/null
@@ -0,0 +1,74 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart pie.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_pie
+ */
+define(['core/chart_base'], function(Base) {
+
+    /**
+     * Pie chart.
+     *
+     * @class
+     * @alias module:core/chart_pie
+     * @extends {module:core/chart_base}
+     */
+    function Pie() {
+        Base.prototype.constructor.apply(this, arguments);
+    }
+    Pie.prototype = Object.create(Base.prototype);
+
+    /** @override */
+    Pie.prototype.TYPE = 'pie';
+
+    /**
+     * Overridden to add appropriate colors to the series.
+     *
+     * @override
+     */
+    Pie.prototype.addSeries = function(series) {
+        if (series.getColor() === null) {
+            var colors = [];
+            for (var i = 0; i < series.getCount(); i++) {
+                colors.push(this.COLORSET[i % Base.prototype.COLORSET.length]);
+            }
+            series.setColors(colors);
+        }
+        return Base.prototype.addSeries.apply(this, arguments);
+    };
+
+    /**
+     * Validate a series.
+     *
+     * Overrides parent implementation to validate that there is only
+     * one series per chart instance.
+     *
+     * @override
+     */
+    Pie.prototype._validateSeries = function() {
+        if (this._series.length >= 1) {
+            throw new Error('Pie charts only support one serie.');
+        }
+        return Base.prototype._validateSeries.apply(this, arguments);
+    };
+
+    return Pie;
+
+});
diff --git a/lib/amd/src/chart_series.js b/lib/amd/src/chart_series.js
new file mode 100644 (file)
index 0000000..90cb281
--- /dev/null
@@ -0,0 +1,344 @@
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Chart series.
+ *
+ * @package    core
+ * @copyright  2016 Frédéric Massart - FMCorz.net
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @module     core/chart_series
+ */
+define([], function() {
+
+    /**
+     * Chart data series.
+     *
+     * @class
+     * @alias module:core/chart_series
+     * @param {String} label The series label.
+     * @param {Number[]} values The values.
+     */
+    function Series(label, values) {
+        if (typeof label !== 'string') {
+            throw new Error('Invalid label for series.');
+
+        } else if (typeof values !== 'object') {
+            throw new Error('Values for a series must be an array.');
+
+        } else if (values.length < 1) {
+            throw new Error('Invalid values received for series.');
+        }
+
+        this._colors = [];
+        this._label = label;
+        this._values = values;
+    }
+
+    /**
+     * The default type of series.
+     *
+     * @type {Null}
+     * @const
+     */
+    Series.prototype.TYPE_DEFAULT = null;
+
+    /**
+     * Type of series 'line'.
+     *
+     * @type {String}
+     * @const
+     */
+    Series.prototype.TYPE_LINE = 'line';
+
+    /**
+     * The colors of the series.
+     *
+     * @type {String[]}
+     * @protected
+     */
+    Series.prototype._colors = null;
+
+    /**
+     * The label of the series.
+     *
+     * @type {String}
+     * @protected
+     */
+    Series.prototype._label = null;
+
+    /**
+     * The labels for the values of the series.
+     *
+     * @type {String[]}
+     * @protected
+     */
+     Series.prototype._labels = null;
+
+    /**
+     * Whether the line of the serie should be smooth or not.
+     *
+     * @type {Bool}
+     * @protected
+     */
+    Series.prototype._smooth = false;
+
+    /**
+     * The type of the series.
+     *
+     * @type {String}
+     * @protected
+     */
+    Series.prototype._type = Series.prototype.TYPE_DEFAULT;
+
+    /**
+     * The values in the series.
+     *
+     * @type {Number[]}
+     * @protected
+     */
+    Series.prototype._values = null;
+
+    /**
+     * The index of the X axis.
+     *
+     * @type {Number[]}
+     * @protected
+     */
+    Series.prototype._xaxis = null;
+
+    /**
+     * The index of the Y axis.
+     *
+     * @type {Number[]}
+     * @protected
+     */
+    Series.prototype._yaxis = null;
+
+    /**
+     * Create a new instance of a series from serialised data.
+     *
+     * @static
+     * @method create
+     * @param {Object} obj The data of the series.
+     * @return {module:core/chart_series}
+     */
+    Series.prototype.create = function(obj) {
+        var s = new Series(obj.label, obj.values);
+        s.setType(obj.type);
+        s.setXAxis(obj.axes.x);
+        s.setYAxis(obj.axes.y);
+        s.setLabels(obj.labels);
+
+        // Colors are exported as an array with 1, or n values.
+        if (obj.colors && obj.colors.length > 1) {
+            s.setColors(obj.colors);
+        } else {
+            s.setColor(obj.colors[0]);
+        }
+
+        s.setSmooth(obj.smooth);
+        return s;
+    };
+
+    /**
+     * Get the color.
+     *
+     * @return {String}
+     */
+    Series.prototype.getColor = function() {
+        return this._colors[0] || null;
+    };
+
+    /**
+     * Get the colors for each value in the series.
+     *
+     * @return {String[]}
+     */
+    Series.prototype.getColors = function() {
+        return this._colors;
+    };
+
+    /**
+     * Get the number of values in the series.
+     *
+     * @return {Number}
+     */
+    Series.prototype.getCount = function() {
+        return this._values.length;
+    };
+
+    /**
+     * Get the series label.
+     *
+     * @return {String}
+     */
+    Series.prototype.getLabel = function() {
+        return this._label;
+    };
+
+    /**
+     * Get labels for the values of the series.
+     *
+     * @return {String[]}
+     */
+    Series.prototype.getLabels = function() {
+        return this._labels;
+    };
+
+    /**
+     * Get whether the line of the serie should be smooth or not.
+     *
+     * @returns {Bool}
+     */
+    Series.prototype.getSmooth = function() {
+        return this._smooth;
+    };
+
+    /**
+     * Get the series type.
+     *
+     * @return {String}
+     */
+    Series.prototype.getType = function() {
+        return this._type;
+    };
+
+    /**
+     * Get the series values.
+     *
+     * @return {Number[]}
+     */
+    Series.prototype.getValues = function() {
+        return this._values;
+    };
+
+    /**
+     * Get the index of the X axis.
+     *
+     * @return {Number}
+     */
+    Series.prototype.getXAxis = function() {
+        return this._xaxis;
+    };
+
+    /**
+     * Get the index of the Y axis.
+     *
+     * @return {Number}
+     */
+    Series.prototype.getYAxis = function() {
+        return this._yaxis;
+    };
+
+    /**
+     * Whether there is a color per value.
+     *
+     * @return {Bool}
+     */
+    Series.prototype.hasColoredValues = function() {
+        return this._colors.length == this.getCount();
+    };
+
+    /**
+     * Set the series color.
+     *
+     * @param {String} color A CSS-compatible color.
+     */
+    Series.prototype.setColor = function(color) {
+        this._colors = [color];
+    };
+
+    /**
+     * Set a color for each value in the series.
+     *
+     * @param {String[]} colors CSS-compatible colors.
+     */
+    Series.prototype.setColors = function(colors) {
+        if (colors && colors.length != this.getCount()) {
+            throw new Error('When setting multiple colors there must be one per value.');
+        }
+        this._colors = colors || [];
+    };
+
+    /**
+     * Set the labels for the values of the series.
+     *
+     * @param {String[]} labels the labels of the series values.
+     */
+    Series.prototype.setLabels = function(labels) {
+        this._validateLabels(labels);
+        labels = typeof labels === 'undefined' ? null : labels;
+        this._labels = labels;
+    };
+
+    /**
+     * Set Whether the line of the serie should be smooth or not.
+     *
+     * Only applicable for line chart or a line series, if null it assumes the chart default (not smooth).
+     *
+     * @param {Bool} smooth True if the lines should be smooth, false for tensioned lines.
+     */
+    Series.prototype.setSmooth = function(smooth) {
+        smooth = typeof smooth === 'undefined' ? null : smooth;
+        this._smooth = smooth;
+    };
+
+    /**
+     * Set the type of the series.
+     *
+     * @param {String} type A type constant value.
+     */
+    Series.prototype.setType = function(type) {
+        if (type != this.TYPE_DEFAULT && type != this.TYPE_LINE) {
+            throw new Error('Invalid serie type.');
+        }
+        this._type = type || null;
+    };
+
+    /**
+     * Set the index of the X axis.
+     *
+     * @param {Number} index The index.
+     */
+    Series.prototype.setXAxis = function(index) {
+        this._xaxis = index || null;
+    };
+
+
+    /**
+     * Set the index of the Y axis.
+     *
+     * @param {Number} index The index.
+     */
+    Series.prototype.setYAxis = function(index) {
+        this._yaxis = index || null;
+    };
+
+    /**
+     * Validate series labels.
+     *
+     * @protected
+     * @param {String[]} labels The labels of the serie.
+     */
+    Series.prototype._validateLabels = function(labels) {
+        if (labels && labels.length > 0 && labels.length != this.getCount()) {
+            throw new Error('Series labels must match series values.');
+        }
+    };
+
+    return Series;
+
+});
diff --git a/lib/amd/src/chartjs-lazy.js b/lib/amd/src/chartjs-lazy.js
new file mode 100644 (file)
index 0000000..f0261ae
--- /dev/null
@@ -0,0 +1,10253 @@
+/*!\r
+ * Chart.js\r
+ * http://chartjs.org/\r
+ * Version: 2.1.6\r
+ *\r
+ * Copyright 2016 Nick Downie\r
+ * Released under the MIT license\r
+ * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md\r
+ */\r
+\r
+/**\r
+ * Description of import into Moodle:\r
+ *\r
+ * - Download from http://www.chartjs.org/docs/#getting-started-download-chart-js.\r
+ * - Copy Chart.js to lib/amd/src/chartjs.js.\r
+ * - Add these instructions to the file.\r
+ * - Add the jshint ignore rules.\r
+ */\r
+\r
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){\r
+\r
+},{}],2:[function(require,module,exports){\r
+/* MIT license */\r
+var colorNames = require(6);\r
+\r
+module.exports = {\r
+   getRgba: getRgba,\r
+   getHsla: getHsla,\r
+   getRgb: getRgb,\r
+   getHsl: getHsl,\r
+   getHwb: getHwb,\r
+   getAlpha: getAlpha,\r
+\r
+   hexString: hexString,\r
+   rgbString: rgbString,\r
+   rgbaString: rgbaString,\r
+   percentString: percentString,\r
+   percentaString: percentaString,\r
+   hslString: hslString,\r
+   hslaString: hslaString,\r
+   hwbString: hwbString,\r
+   keyword: keyword\r
+}\r
+\r
+function getRgba(string) {\r
+   if (!string) {\r
+      return;\r
+   }\r
+   var abbr =  /^#([a-fA-F0-9]{3})$/,\r
+       hex =  /^#([a-fA-F0-9]{6})$/,\r
+       rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,\r
+       per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,\r
+       keyword = /(\w+)/;\r
+\r
+   var rgb = [0, 0, 0],\r
+       a = 1,\r
+       match = string.match(abbr);\r
+   if (match) {\r
+      match = match[1];\r
+      for (var i = 0; i < rgb.length; i++) {\r
+         rgb[i] = parseInt(match[i] + match[i], 16);\r
+      }\r
+   }\r
+   else if (match = string.match(hex)) {\r
+      match = match[1];\r
+      for (var i = 0; i < rgb.length; i++) {\r
+         rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);\r
+      }\r
+   }\r
+   else if (match = string.match(rgba)) {\r
+      for (var i = 0; i < rgb.length; i++) {\r
+         rgb[i] = parseInt(match[i + 1]);\r
+      }\r
+      a = parseFloat(match[4]);\r
+   }\r
+   else if (match = string.match(per)) {\r
+      for (var i = 0; i < rgb.length; i++) {\r
+         rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);\r
+      }\r
+      a = parseFloat(match[4]);\r
+   }\r
+   else if (match = string.match(keyword)) {\r
+      if (match[1] == "transparent") {\r
+         return [0, 0, 0, 0];\r
+      }\r
+      rgb = colorNames[match[1]];\r
+      if (!rgb) {\r
+         return;\r
+      }\r
+   }\r
+\r
+   for (var i = 0; i < rgb.length; i++) {\r
+      rgb[i] = scale(rgb[i], 0, 255);\r
+   }\r
+   if (!a && a != 0) {\r
+      a = 1;\r
+   }\r
+   else {\r
+      a = scale(a, 0, 1);\r
+   }\r
+   rgb[3] = a;\r
+   return rgb;\r
+}\r
+\r
+function getHsla(string) {\r
+   if (!string) {\r
+      return;\r
+   }\r
+   var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;\r
+   var match = string.match(hsl);\r
+   if (match) {\r
+      var alpha = parseFloat(match[4]);\r
+      var h = scale(parseInt(match[1]), 0, 360),\r
+          s = scale(parseFloat(match[2]), 0, 100),\r
+          l = scale(parseFloat(match[3]), 0, 100),\r
+          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);\r
+      return [h, s, l, a];\r
+   }\r
+}\r
+\r
+function getHwb(string) {\r
+   if (!string) {\r
+      return;\r
+   }\r
+   var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;\r
+   var match = string.match(hwb);\r
+   if (match) {\r
+    var alpha = parseFloat(match[4]);\r
+      var h = scale(parseInt(match[1]), 0, 360),\r
+          w = scale(parseFloat(match[2]), 0, 100),\r
+          b = scale(parseFloat(match[3]), 0, 100),\r
+          a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);\r
+      return [h, w, b, a];\r
+   }\r
+}\r
+\r
+function getRgb(string) {\r
+   var rgba = getRgba(string);\r
+   return rgba && rgba.slice(0, 3);\r
+}\r
+\r
+function getHsl(string) {\r
+  var hsla = getHsla(string);\r
+  return hsla && hsla.slice(0, 3);\r
+}\r
+\r
+function getAlpha(string) {\r
+   var vals = getRgba(string);\r
+   if (vals) {\r
+      return vals[3];\r
+   }\r
+   else if (vals = getHsla(string)) {\r
+      return vals[3];\r
+   }\r
+   else if (vals = getHwb(string)) {\r
+      return vals[3];\r
+   }\r
+}\r
+\r
+// generators\r
+function hexString(rgb) {\r
+   return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])\r
+              + hexDouble(rgb[2]);\r
+}\r
+\r
+function rgbString(rgba, alpha) {\r
+   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {\r
+      return rgbaString(rgba, alpha);\r
+   }\r
+   return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";\r
+}\r
+\r
+function rgbaString(rgba, alpha) {\r
+   if (alpha === undefined) {\r
+      alpha = (rgba[3] !== undefined ? rgba[3] : 1);\r
+   }\r
+   return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]\r
+           + ", " + alpha + ")";\r
+}\r
+\r
+function percentString(rgba, alpha) {\r
+   if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {\r
+      return percentaString(rgba, alpha);\r
+   }\r
+   var r = Math.round(rgba[0]/255 * 100),\r
+       g = Math.round(rgba[1]/255 * 100),\r
+       b = Math.round(rgba[2]/255 * 100);\r
+\r
+   return "rgb(" + r + "%, " + g + "%, " + b + "%)";\r
+}\r
+\r
+function percentaString(rgba, alpha) {\r
+   var r = Math.round(rgba[0]/255 * 100),\r
+       g = Math.round(rgba[1]/255 * 100),\r
+       b = Math.round(rgba[2]/255 * 100);\r
+   return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";\r
+}\r
+\r
+function hslString(hsla, alpha) {\r
+   if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {\r
+      return hslaString(hsla, alpha);\r
+   }\r
+   return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";\r
+}\r
+\r
+function hslaString(hsla, alpha) {\r
+   if (alpha === undefined) {\r
+      alpha = (hsla[3] !== undefined ? hsla[3] : 1);\r
+   }\r
+   return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "\r
+           + alpha + ")";\r
+}\r
+\r
+// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax\r
+// (hwb have alpha optional & 1 is default value)\r
+function hwbString(hwb, alpha) {\r
+   if (alpha === undefined) {\r
+      alpha = (hwb[3] !== undefined ? hwb[3] : 1);\r
+   }\r
+   return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"\r
+           + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";\r
+}\r
+\r
+function keyword(rgb) {\r
+  return reverseNames[rgb.slice(0, 3)];\r
+}\r
+\r
+// helpers\r
+function scale(num, min, max) {\r
+   return Math.min(Math.max(min, num), max);\r
+}\r
+\r
+function hexDouble(num) {\r
+  var str = num.toString(16).toUpperCase();\r
+  return (str.length < 2) ? "0" + str : str;\r
+}\r
+\r
+\r
+//create a list of reverse color names\r
+var reverseNames = {};\r
+for (var name in colorNames) {\r
+   reverseNames[colorNames[name]] = name;\r
+}\r
+\r
+},{"6":6}],3:[function(require,module,exports){\r
+/* MIT license */\r
+var convert = require(5);\r
+var string = require(2);\r
+\r
+var Color = function (obj) {\r
+       if (obj instanceof Color) {\r
+               return obj;\r
+       }\r
+       if (!(this instanceof Color)) {\r
+               return new Color(obj);\r
+       }\r
+\r
+       this.values = {\r
+               rgb: [0, 0, 0],\r
+               hsl: [0, 0, 0],\r
+               hsv: [0, 0, 0],\r
+               hwb: [0, 0, 0],\r
+               cmyk: [0, 0, 0, 0],\r
+               alpha: 1\r
+       };\r
+\r
+       // parse Color() argument\r
+       var vals;\r
+       if (typeof obj === 'string') {\r
+               vals = string.getRgba(obj);\r
+               if (vals) {\r
+                       this.setValues('rgb', vals);\r
+               } else if (vals = string.getHsla(obj)) {\r
+                       this.setValues('hsl', vals);\r
+               } else if (vals = string.getHwb(obj)) {\r
+                       this.setValues('hwb', vals);\r
+               } else {\r
+                       throw new Error('Unable to parse color from string "' + obj + '"');\r
+               }\r
+       } else if (typeof obj === 'object') {\r
+               vals = obj;\r
+               if (vals.r !== undefined || vals.red !== undefined) {\r
+                       this.setValues('rgb', vals);\r
+               } else if (vals.l !== undefined || vals.lightness !== undefined) {\r
+                       this.setValues('hsl', vals);\r
+               } else if (vals.v !== undefined || vals.value !== undefined) {\r
+                       this.setValues('hsv', vals);\r
+               } else if (vals.w !== undefined || vals.whiteness !== undefined) {\r
+                       this.setValues('hwb', vals);\r
+               } else if (vals.c !== undefined || vals.cyan !== undefined) {\r
+                       this.setValues('cmyk', vals);\r
+               } else {\r
+                       throw new Error('Unable to parse color from object ' + JSON.stringify(obj));\r
+               }\r
+       }\r
+};\r
+\r
+Color.prototype = {\r
+       rgb: function () {\r
+               return this.setSpace('rgb', arguments);\r
+       },\r
+       hsl: function () {\r
+               return this.setSpace('hsl', arguments);\r
+       },\r
+       hsv: function () {\r
+               return this.setSpace('hsv', arguments);\r
+       },\r
+       hwb: function () {\r
+               return this.setSpace('hwb', arguments);\r
+       },\r
+       cmyk: function () {\r
+               return this.setSpace('cmyk', arguments);\r
+       },\r
+\r
+       rgbArray: function () {\r
+               return this.values.rgb;\r
+       },\r
+       hslArray: function () {\r
+               return this.values.hsl;\r
+       },\r
+       hsvArray: function () {\r
+               return this.values.hsv;\r
+       },\r
+       hwbArray: function () {\r
+               var values = this.values;\r
+               if (values.alpha !== 1) {\r
+                       return values.hwb.concat([values.alpha]);\r
+               }\r
+               return values.hwb;\r
+       },\r
+       cmykArray: function () {\r
+               return this.values.cmyk;\r
+       },\r
+       rgbaArray: function () {\r
+               var values = this.values;\r
+               return values.rgb.concat([values.alpha]);\r
+       },\r
+       hslaArray: function () {\r
+               var values = this.values;\r
+               return values.hsl.concat([values.alpha]);\r
+       },\r
+       alpha: function (val) {\r
+               if (val === undefined) {\r
+                       return this.values.alpha;\r
+               }\r
+               this.setValues('alpha', val);\r
+               return this;\r
+       },\r
+\r
+       red: function (val) {\r
+               return this.setChannel('rgb', 0, val);\r
+       },\r
+       green: function (val) {\r
+               return this.setChannel('rgb', 1, val);\r
+       },\r
+       blue: function (val) {\r
+               return this.setChannel('rgb', 2, val);\r
+       },\r
+       hue: function (val) {\r
+               if (val) {\r
+                       val %= 360;\r
+                       val = val < 0 ? 360 + val : val;\r
+               }\r
+               return this.setChannel('hsl', 0, val);\r
+       },\r
+       saturation: function (val) {\r
+               return this.setChannel('hsl', 1, val);\r
+       },\r
+       lightness: function (val) {\r
+               return this.setChannel('hsl', 2, val);\r
+       },\r
+       saturationv: function (val) {\r
+               return this.setChannel('hsv', 1, val);\r
+       },\r
+       whiteness: function (val) {\r
+               return this.setChannel('hwb', 1, val);\r
+       },\r
+       blackness: function (val) {\r
+               return this.setChannel('hwb', 2, val);\r
+       },\r
+       value: function (val) {\r
+               return this.setChannel('hsv', 2, val);\r
+       },\r
+       cyan: function (val) {\r
+               return this.setChannel('cmyk', 0, val);\r
+       },\r
+       magenta: function (val) {\r
+               return this.setChannel('cmyk', 1, val);\r
+       },\r
+       yellow: function (val) {\r
+               return this.setChannel('cmyk', 2, val);\r
+       },\r
+       black: function (val) {\r
+               return this.setChannel('cmyk', 3, val);\r
+       },\r
+\r
+       hexString: function () {\r
+               return string.hexString(this.values.rgb);\r
+       },\r
+       rgbString: function () {\r
+               return string.rgbString(this.values.rgb, this.values.alpha);\r
+       },\r
+       rgbaString: function () {\r
+               return string.rgbaString(this.values.rgb, this.values.alpha);\r
+       },\r
+       percentString: function () {\r
+               return string.percentString(this.values.rgb, this.values.alpha);\r
+       },\r
+       hslString: function () {\r
+               return string.hslString(this.values.hsl, this.values.alpha);\r
+       },\r
+       hslaString: function () {\r
+               return string.hslaString(this.values.hsl, this.values.alpha);\r
+       },\r
+       hwbString: function () {\r
+               return string.hwbString(this.values.hwb, this.values.alpha);\r
+       },\r
+       keyword: function () {\r
+               return string.keyword(this.values.rgb, this.values.alpha);\r
+       },\r
+\r
+       rgbNumber: function () {\r
+               var rgb = this.values.rgb;\r
+               return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];\r
+       },\r
+\r
+       luminosity: function () {\r
+               // http://www.w3.org/TR/WCAG20/#relativeluminancedef\r
+               var rgb = this.values.rgb;\r
+               var lum = [];\r
+               for (var i = 0; i < rgb.length; i++) {\r
+                       var chan = rgb[i] / 255;\r
+                       lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);\r
+               }\r
+               return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];\r
+       },\r
+\r
+       contrast: function (color2) {\r
+               // http://www.w3.org/TR/WCAG20/#contrast-ratiodef\r
+               var lum1 = this.luminosity();\r
+               var lum2 = color2.luminosity();\r
+               if (lum1 > lum2) {\r
+                       return (lum1 + 0.05) / (lum2 + 0.05);\r
+               }\r
+               return (lum2 + 0.05) / (lum1 + 0.05);\r
+       },\r
+\r
+       level: function (color2) {\r
+               var contrastRatio = this.contrast(color2);\r
+               if (contrastRatio >= 7.1) {\r
+                       return 'AAA';\r
+               }\r
+\r
+               return (contrastRatio >= 4.5) ? 'AA' : '';\r
+       },\r
+\r
+       dark: function () {\r
+               // YIQ equation from http://24ways.org/2010/calculating-color-contrast\r
+               var rgb = this.values.rgb;\r
+               var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;\r
+               return yiq < 128;\r
+       },\r
+\r
+       light: function () {\r
+               return !this.dark();\r
+       },\r
+\r
+       negate: function () {\r
+               var rgb = [];\r
+               for (var i = 0; i < 3; i++) {\r
+                       rgb[i] = 255 - this.values.rgb[i];\r
+               }\r
+               this.setValues('rgb', rgb);\r
+               return this;\r
+       },\r
+\r
+       lighten: function (ratio) {\r
+               var hsl = this.values.hsl;\r
+               hsl[2] += hsl[2] * ratio;\r
+               this.setValues('hsl', hsl);\r
+               return this;\r
+       },\r
+\r
+       darken: function (ratio) {\r
+               var hsl = this.values.hsl;\r
+               hsl[2] -= hsl[2] * ratio;\r
+               this.setValues('hsl', hsl);\r
+               return this;\r
+       },\r
+\r
+       saturate: function (ratio) {\r
+               var hsl = this.values.hsl;\r
+               hsl[1] += hsl[1] * ratio;\r
+               this.setValues('hsl', hsl);\r
+               return this;\r
+       },\r
+\r
+       desaturate: function (ratio) {\r
+               var hsl = this.values.hsl;\r
+               hsl[1] -= hsl[1] * ratio;\r
+               this.setValues('hsl', hsl);\r
+               return this;\r
+       },\r
+\r
+       whiten: function (ratio) {\r
+               var hwb = this.values.hwb;\r
+               hwb[1] += hwb[1] * ratio;\r
+               this.setValues('hwb', hwb);\r
+               return this;\r
+       },\r
+\r
+       blacken: function (ratio) {\r
+               var hwb = this.values.hwb;\r
+               hwb[2] += hwb[2] * ratio;\r
+               this.setValues('hwb', hwb);\r
+               return this;\r
+       },\r
+\r
+       greyscale: function () {\r
+               var rgb = this.values.rgb;\r
+               // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale\r
+               var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;\r
+               this.setValues('rgb', [val, val, val]);\r
+               return this;\r
+       },\r
+\r
+       clearer: function (ratio) {\r
+               var alpha = this.values.alpha;\r
+               this.setValues('alpha', alpha - (alpha * ratio));\r
+               return this;\r
+       },\r
+\r
+       opaquer: function (ratio) {\r
+               var alpha = this.values.alpha;\r
+               this.setValues('alpha', alpha + (alpha * ratio));\r
+               return this;\r
+       },\r
+\r
+       rotate: function (degrees) {\r
+               var hsl = this.values.hsl;\r
+               var hue = (hsl[0] + degrees) % 360;\r
+               hsl[0] = hue < 0 ? 360 + hue : hue;\r
+               this.setValues('hsl', hsl);\r
+               return this;\r
+       },\r
+\r
+       /**\r
+        * Ported from sass implementation in C\r
+        * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209\r
+        */\r
+       mix: function (mixinColor, weight) {\r
+               var color1 = this;\r
+               var color2 = mixinColor;\r
+               var p = weight === undefined ? 0.5 : weight;\r
+\r
+               var w = 2 * p - 1;\r
+               var a = color1.alpha() - color2.alpha();\r
+\r
+               var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;\r
+               var w2 = 1 - w1;\r
+\r
+               return this\r
+                       .rgb(\r
+                               w1 * color1.red() + w2 * color2.red(),\r
+                               w1 * color1.green() + w2 * color2.green(),\r
+                               w1 * color1.blue() + w2 * color2.blue()\r
+                       )\r
+                       .alpha(color1.alpha() * p + color2.alpha() * (1 - p));\r
+       },\r
+\r
+       toJSON: function () {\r
+               return this.rgb();\r
+       },\r
+\r
+       clone: function () {\r
+               // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,\r
+               // making the final build way to big to embed in Chart.js. So let's do it manually,\r
+               // assuming that values to clone are 1 dimension arrays containing only numbers,\r
+               // except 'alpha' which is a number.\r
+               var result = new Color();\r
+               var source = this.values;\r
+               var target = result.values;\r
+               var value, type;\r
+\r
+               for (var prop in source) {\r
+                       if (source.hasOwnProperty(prop)) {\r
+                               value = source[prop];\r
+                               type = ({}).toString.call(value);\r
+                               if (type === '[object Array]') {\r
+                                       target[prop] = value.slice(0);\r
+                               } else if (type === '[object Number]') {\r
+                                       target[prop] = value;\r
+                               } else {\r
+                                       console.error('unexpected color value:', value);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               return result;\r
+       }\r
+};\r
+\r
+Color.prototype.spaces = {\r
+       rgb: ['red', 'green', 'blue'],\r
+       hsl: ['hue', 'saturation', 'lightness'],\r
+       hsv: ['hue', 'saturation', 'value'],\r
+       hwb: ['hue', 'whiteness', 'blackness'],\r
+       cmyk: ['cyan', 'magenta', 'yellow', 'black']\r
+};\r
+\r
+Color.prototype.maxes = {\r
+       rgb: [255, 255, 255],\r
+       hsl: [360, 100, 100],\r
+       hsv: [360, 100, 100],\r
+       hwb: [360, 100, 100],\r
+       cmyk: [100, 100, 100, 100]\r
+};\r
+\r
+Color.prototype.getValues = function (space) {\r
+       var values = this.values;\r
+       var vals = {};\r
+\r
+       for (var i = 0; i < space.length; i++) {\r
+               vals[space.charAt(i)] = values[space][i];\r
+       }\r
+\r
+       if (values.alpha !== 1) {\r
+               vals.a = values.alpha;\r
+       }\r
+\r
+       // {r: 255, g: 255, b: 255, a: 0.4}\r
+       return vals;\r
+};\r
+\r
+Color.prototype.setValues = function (space, vals) {\r
+       var values = this.values;\r
+       var spaces = this.spaces;\r
+       var maxes = this.maxes;\r
+       var alpha = 1;\r
+       var i;\r
+\r
+       if (space === 'alpha') {\r
+               alpha = vals;\r
+       } else if (vals.length) {\r
+               // [10, 10, 10]\r
+               values[space] = vals.slice(0, space.length);\r
+               alpha = vals[space.length];\r
+       } else if (vals[space.charAt(0)] !== undefined) {\r
+               // {r: 10, g: 10, b: 10}\r
+               for (i = 0; i < space.length; i++) {\r
+                       values[space][i] = vals[space.charAt(i)];\r
+               }\r
+\r
+               alpha = vals.a;\r
+       } else if (vals[spaces[space][0]] !== undefined) {\r
+               // {red: 10, green: 10, blue: 10}\r
+               var chans = spaces[space];\r
+\r
+               for (i = 0; i < space.length; i++) {\r
+                       values[space][i] = vals[chans[i]];\r
+               }\r
+\r
+               alpha = vals.alpha;\r
+       }\r
+\r
+       values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));\r
+\r
+       if (space === 'alpha') {\r
+               return false;\r
+       }\r
+\r
+       var capped;\r
+\r
+       // cap values of the space prior converting all values\r
+       for (i = 0; i < space.length; i++) {\r
+               capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));\r
+               values[space][i] = Math.round(capped);\r
+       }\r
+\r
+       // convert to all the other color spaces\r
+       for (var sname in spaces) {\r
+               if (sname !== space) {\r
+                       values[sname] = convert[space][sname](values[space]);\r
+               }\r
+       }\r
+\r
+       return true;\r
+};\r
+\r
+Color.prototype.setSpace = function (space, args) {\r
+       var vals = args[0];\r
+\r
+       if (vals === undefined) {\r
+               // color.rgb()\r
+               return this.getValues(space);\r
+       }\r
+\r
+       // color.rgb(10, 10, 10)\r
+       if (typeof vals === 'number') {\r
+               vals = Array.prototype.slice.call(args);\r
+       }\r
+\r
+       this.setValues(space, vals);\r
+       return this;\r
+};\r
+\r
+Color.prototype.setChannel = function (space, index, val) {\r
+       var svalues = this.values[space];\r
+       if (val === undefined) {\r
+               // color.red()\r
+               return svalues[index];\r
+       } else if (val === svalues[index]) {\r
+               // color.red(color.red())\r
+               return this;\r
+       }\r
+\r
+       // color.red(100)\r
+       svalues[index] = val;\r
+       this.setValues(space, svalues);\r
+\r
+       return this;\r
+};\r
+\r
+if (typeof window !== 'undefined') {\r
+       window.Color = Color;\r
+}\r
+\r
+module.exports = Color;\r
+\r
+},{"2":2,"5":5}],4:[function(require,module,exports){\r
+/* MIT license */\r
+\r
+module.exports = {\r
+  rgb2hsl: rgb2hsl,\r
+  rgb2hsv: rgb2hsv,\r
+  rgb2hwb: rgb2hwb,\r
+  rgb2cmyk: rgb2cmyk,\r
+  rgb2keyword: rgb2keyword,\r
+  rgb2xyz: rgb2xyz,\r
+  rgb2lab: rgb2lab,\r
+  rgb2lch: rgb2lch,\r
+\r
+  hsl2rgb: hsl2rgb,\r
+  hsl2hsv: hsl2hsv,\r
+  hsl2hwb: hsl2hwb,\r
+  hsl2cmyk: hsl2cmyk,\r
+  hsl2keyword: hsl2keyword,\r
+\r
+  hsv2rgb: hsv2rgb,\r
+  hsv2hsl: hsv2hsl,\r
+  hsv2hwb: hsv2hwb,\r
+  hsv2cmyk: hsv2cmyk,\r
+  hsv2keyword: hsv2keyword,\r
+\r
+  hwb2rgb: hwb2rgb,\r
+  hwb2hsl: hwb2hsl,\r
+  hwb2hsv: hwb2hsv,\r
+  hwb2cmyk: hwb2cmyk,\r
+  hwb2keyword: hwb2keyword,\r
+\r
+  cmyk2rgb: cmyk2rgb,\r
+  cmyk2hsl: cmyk2hsl,\r
+  cmyk2hsv: cmyk2hsv,\r
+  cmyk2hwb: cmyk2hwb,\r
+  cmyk2keyword: cmyk2keyword,\r
+\r
+  keyword2rgb: keyword2rgb,\r
+  keyword2hsl: keyword2hsl,\r
+  keyword2hsv: keyword2hsv,\r
+  keyword2hwb: keyword2hwb,\r
+  keyword2cmyk: keyword2cmyk,\r
+  keyword2lab: keyword2lab,\r
+  keyword2xyz: keyword2xyz,\r
+\r
+  xyz2rgb: xyz2rgb,\r
+  xyz2lab: xyz2lab,\r
+  xyz2lch: xyz2lch,\r
+\r
+  lab2xyz: lab2xyz,\r
+  lab2rgb: lab2rgb,\r
+  lab2lch: lab2lch,\r
+\r
+  lch2lab: lch2lab,\r
+  lch2xyz: lch2xyz,\r
+  lch2rgb: lch2rgb\r
+}\r
+\r
+\r
+function rgb2hsl(rgb) {\r
+  var r = rgb[0]/255,\r
+      g = rgb[1]/255,\r
+      b = rgb[2]/255,\r
+      min = Math.min(r, g, b),\r
+      max = Math.max(r, g, b),\r
+      delta = max - min,\r
+      h, s, l;\r
+\r
+  if (max == min)\r
+    h = 0;\r
+  else if (r == max)\r
+    h = (g - b) / delta;\r
+  else if (g == max)\r
+    h = 2 + (b - r) / delta;\r
+  else if (b == max)\r
+    h = 4 + (r - g)/ delta;\r
+\r
+  h = Math.min(h * 60, 360);\r
+\r
+  if (h < 0)\r
+    h += 360;\r
+\r
+  l = (min + max) / 2;\r
+\r
+  if (max == min)\r
+    s = 0;\r
+  else if (l <= 0.5)\r
+    s = delta / (max + min);\r
+  else\r
+    s = delta / (2 - max - min);\r
+\r
+  return [h, s * 100, l * 100];\r
+}\r
+\r
+function rgb2hsv(rgb) {\r
+  var r = rgb[0],\r
+      g = rgb[1],\r
+      b = rgb[2],\r
+      min = Math.min(r, g, b),\r
+      max = Math.max(r, g, b),\r
+      delta = max - min,\r
+      h, s, v;\r
+\r
+  if (max == 0)\r
+    s = 0;\r
+  else\r
+    s = (delta/max * 1000)/10;\r
+\r
+  if (max == min)\r
+    h = 0;\r
+  else if (r == max)\r
+    h = (g - b) / delta;\r
+  else if (g == max)\r
+    h = 2 + (b - r) / delta;\r
+  else if (b == max)\r
+    h = 4 + (r - g) / delta;\r
+\r
+  h = Math.min(h * 60, 360);\r
+\r
+  if (h < 0)\r
+    h += 360;\r
+\r
+  v = ((max / 255) * 1000) / 10;\r
+\r
+  return [h, s, v];\r
+}\r
+\r
+function rgb2hwb(rgb) {\r
+  var r = rgb[0],\r
+      g = rgb[1],\r
+      b = rgb[2],\r
+      h = rgb2hsl(rgb)[0],\r
+      w = 1/255 * Math.min(r, Math.min(g, b)),\r
+      b = 1 - 1/255 * Math.max(r, Math.max(g, b));\r
+\r
+  return [h, w * 100, b * 100];\r
+}\r
+\r
+function rgb2cmyk(rgb) {\r
+  var r = rgb[0] / 255,\r
+      g = rgb[1] / 255,\r
+      b = rgb[2] / 255,\r
+      c, m, y, k;\r
+\r
+  k = Math.min(1 - r, 1 - g, 1 - b);\r
+  c = (1 - r - k) / (1 - k) || 0;\r
+  m = (1 - g - k) / (1 - k) || 0;\r
+  y = (1 - b - k) / (1 - k) || 0;\r
+  return [c * 100, m * 100, y * 100, k * 100];\r
+}\r
+\r
+function rgb2keyword(rgb) {\r
+  return reverseKeywords[JSON.stringify(rgb)];\r
+}\r
+\r
+function rgb2xyz(rgb) {\r
+  var r = rgb[0] / 255,\r
+      g = rgb[1] / 255,\r
+      b = rgb[2] / 255;\r
+\r
+  // assume sRGB\r
+  r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);\r
+  g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);\r
+  b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);\r
+\r
+  var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);\r
+  var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);\r
+  var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);\r
+\r
+  return [x * 100, y *100, z * 100];\r
+}\r
+\r
+function rgb2lab(rgb) {\r
+  var xyz = rgb2xyz(rgb),\r
+        x = xyz[0],\r
+        y = xyz[1],\r
+        z = xyz[2],\r
+        l, a, b;\r
+\r
+  x /= 95.047;\r
+  y /= 100;\r
+  z /= 108.883;\r
+\r
+  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);\r
+  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);\r
+  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);\r
+\r
+  l = (116 * y) - 16;\r
+  a = 500 * (x - y);\r
+  b = 200 * (y - z);\r
+\r
+  return [l, a, b];\r
+}\r
+\r
+function rgb2lch(args) {\r
+  return lab2lch(rgb2lab(args));\r
+}\r
+\r
+function hsl2rgb(hsl) {\r
+  var h = hsl[0] / 360,\r
+      s = hsl[1] / 100,\r
+      l = hsl[2] / 100,\r
+      t1, t2, t3, rgb, val;\r
+\r
+  if (s == 0) {\r
+    val = l * 255;\r
+    return [val, val, val];\r
+  }\r
+\r
+  if (l < 0.5)\r
+    t2 = l * (1 + s);\r
+  else\r
+    t2 = l + s - l * s;\r
+  t1 = 2 * l - t2;\r
+\r
+  rgb = [0, 0, 0];\r
+  for (var i = 0; i < 3; i++) {\r
+    t3 = h + 1 / 3 * - (i - 1);\r
+    t3 < 0 && t3++;\r
+    t3 > 1 && t3--;\r
+\r
+    if (6 * t3 < 1)\r
+      val = t1 + (t2 - t1) * 6 * t3;\r
+    else if (2 * t3 < 1)\r
+      val = t2;\r
+    else if (3 * t3 < 2)\r
+      val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;\r
+    else\r
+      val = t1;\r
+\r
+    rgb[i] = val * 255;\r
+  }\r
+\r
+  return rgb;\r
+}\r
+\r
+function hsl2hsv(hsl) {\r
+  var h = hsl[0],\r
+      s = hsl[1] / 100,\r
+      l = hsl[2] / 100,\r
+      sv, v;\r
+\r
+  if(l === 0) {\r
+      // no need to do calc on black\r
+      // also avoids divide by 0 error\r
+      return [0, 0, 0];\r
+  }\r
+\r
+  l *= 2;\r
+  s *= (l <= 1) ? l : 2 - l;\r
+  v = (l + s) / 2;\r
+  sv = (2 * s) / (l + s);\r
+  return [h, sv * 100, v * 100];\r
+}\r
+\r
+function hsl2hwb(args) {\r
+  return rgb2hwb(hsl2rgb(args));\r
+}\r
+\r
+function hsl2cmyk(args) {\r
+  return rgb2cmyk(hsl2rgb(args));\r
+}\r
+\r
+function hsl2keyword(args) {\r
+  return rgb2keyword(hsl2rgb(args));\r
+}\r
+\r
+\r
+function hsv2rgb(hsv) {\r
+  var h = hsv[0] / 60,\r
+      s = hsv[1] / 100,\r
+      v = hsv[2] / 100,\r
+      hi = Math.floor(h) % 6;\r
+\r
+  var f = h - Math.floor(h),\r
+      p = 255 * v * (1 - s),\r
+      q = 255 * v * (1 - (s * f)),\r
+      t = 255 * v * (1 - (s * (1 - f))),\r
+      v = 255 * v;\r
+\r
+  switch(hi) {\r
+    case 0:\r
+      return [v, t, p];\r
+    case 1:\r
+      return [q, v, p];\r
+    case 2:\r
+      return [p, v, t];\r
+    case 3:\r
+      return [p, q, v];\r
+    case 4:\r
+      return [t, p, v];\r
+    case 5:\r
+      return [v, p, q];\r
+  }\r
+}\r
+\r
+function hsv2hsl(hsv) {\r
+  var h = hsv[0],\r
+      s = hsv[1] / 100,\r
+      v = hsv[2] / 100,\r
+      sl, l;\r
+\r
+  l = (2 - s) * v;\r
+  sl = s * v;\r
+  sl /= (l <= 1) ? l : 2 - l;\r
+  sl = sl || 0;\r
+  l /= 2;\r
+  return [h, sl * 100, l * 100];\r
+}\r
+\r
+function hsv2hwb(args) {\r
+  return rgb2hwb(hsv2rgb(args))\r
+}\r
+\r
+function hsv2cmyk(args) {\r
+  return rgb2cmyk(hsv2rgb(args));\r
+}\r
+\r
+function hsv2keyword(args) {\r
+  return rgb2keyword(hsv2rgb(args));\r
+}\r
+\r
+// http://dev.w3.org/csswg/css-color/#hwb-to-rgb\r
+function hwb2rgb(hwb) {\r
+  var h = hwb[0] / 360,\r
+      wh = hwb[1] / 100,\r
+      bl = hwb[2] / 100,\r
+      ratio = wh + bl,\r
+      i, v, f, n;\r
+\r
+  // wh + bl cant be > 1\r
+  if (ratio > 1) {\r
+    wh /= ratio;\r
+    bl /= ratio;\r
+  }\r
+\r
+  i = Math.floor(6 * h);\r
+  v = 1 - bl;\r
+  f = 6 * h - i;\r
+  if ((i & 0x01) != 0) {\r
+    f = 1 - f;\r
+  }\r
+  n = wh + f * (v - wh);  // linear interpolation\r
+\r
+  switch (i) {\r
+    default:\r
+    case 6:\r
+    case 0: r = v; g = n; b = wh; break;\r
+    case 1: r = n; g = v; b = wh; break;\r
+    case 2: r = wh; g = v; b = n; break;\r
+    case 3: r = wh; g = n; b = v; break;\r
+    case 4: r = n; g = wh; b = v; break;\r
+    case 5: r = v; g = wh; b = n; break;\r
+  }\r
+\r
+  return [r * 255, g * 255, b * 255];\r
+}\r
+\r
+function hwb2hsl(args) {\r
+  return rgb2hsl(hwb2rgb(args));\r
+}\r
+\r
+function hwb2hsv(args) {\r
+  return rgb2hsv(hwb2rgb(args));\r
+}\r
+\r
+function hwb2cmyk(args) {\r
+  return rgb2cmyk(hwb2rgb(args));\r
+}\r
+\r
+function hwb2keyword(args) {\r
+  return rgb2keyword(hwb2rgb(args));\r
+}\r
+\r
+function cmyk2rgb(cmyk) {\r
+  var c = cmyk[0] / 100,\r
+      m = cmyk[1] / 100,\r
+      y = cmyk[2] / 100,\r
+      k = cmyk[3] / 100,\r
+      r, g, b;\r
+\r
+  r = 1 - Math.min(1, c * (1 - k) + k);\r
+  g = 1 - Math.min(1, m * (1 - k) + k);\r
+  b = 1 - Math.min(1, y * (1 - k) + k);\r
+  return [r * 255, g * 255, b * 255];\r
+}\r
+\r
+function cmyk2hsl(args) {\r
+  return rgb2hsl(cmyk2rgb(args));\r
+}\r
+\r
+function cmyk2hsv(args) {\r
+  return rgb2hsv(cmyk2rgb(args));\r
+}\r
+\r
+function cmyk2hwb(args) {\r
+  return rgb2hwb(cmyk2rgb(args));\r
+}\r
+\r
+function cmyk2keyword(args) {\r
+  return rgb2keyword(cmyk2rgb(args));\r
+}\r
+\r
+\r
+function xyz2rgb(xyz) {\r
+  var x = xyz[0] / 100,\r
+      y = xyz[1] / 100,\r
+      z = xyz[2] / 100,\r
+      r, g, b;\r
+\r
+  r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);\r
+  g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);\r
+  b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);\r
+\r
+  // assume sRGB\r
+  r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)\r
+    : r = (r * 12.92);\r
+\r
+  g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)\r
+    : g = (g * 12.92);\r
+\r
+  b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)\r
+    : b = (b * 12.92);\r
+\r
+  r = Math.min(Math.max(0, r), 1);\r
+  g = Math.min(Math.max(0, g), 1);\r
+  b = Math.min(Math.max(0, b), 1);\r
+\r
+  return [r * 255, g * 255, b * 255];\r
+}\r
+\r
+function xyz2lab(xyz) {\r
+  var x = xyz[0],\r
+      y = xyz[1],\r
+      z = xyz[2],\r
+      l, a, b;\r
+\r
+  x /= 95.047;\r
+  y /= 100;\r
+  z /= 108.883;\r
+\r
+  x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);\r
+  y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);\r
+  z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);\r
+\r
+  l = (116 * y) - 16;\r
+  a = 500 * (x - y);\r
+  b = 200 * (y - z);\r
+\r
+  return [l, a, b];\r
+}\r
+\r
+function xyz2lch(args) {\r
+  return lab2lch(xyz2lab(args));\r
+}\r
+\r
+function lab2xyz(lab) {\r
+  var l = lab[0],\r
+      a = lab[1],\r
+      b = lab[2],\r
+      x, y, z, y2;\r
+\r
+  if (l <= 8) {\r
+    y = (l * 100) / 903.3;\r
+    y2 = (7.787 * (y / 100)) + (16 / 116);\r
+  } else {\r
+    y = 100 * Math.pow((l + 16) / 116, 3);\r
+    y2 = Math.pow(y / 100, 1/3);\r
+  }\r
+\r
+  x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);\r
+\r
+  z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);\r
+\r
+  return [x, y, z];\r
+}\r
+\r
+function lab2lch(lab) {\r
+  var l = lab[0],\r
+      a = lab[1],\r
+      b = lab[2],\r
+      hr, h, c;\r
+\r
+  hr = Math.atan2(b, a);\r
+  h = hr * 360 / 2 / Math.PI;\r
+  if (h < 0) {\r
+    h += 360;\r
+  }\r
+  c = Math.sqrt(a * a + b * b);\r
+  return [l, c, h];\r
+}\r
+\r
+function lab2rgb(args) {\r
+  return xyz2rgb(lab2xyz(args));\r
+}\r
+\r
+function lch2lab(lch) {\r
+  var l = lch[0],\r
+      c = lch[1],\r
+      h = lch[2],\r
+      a, b, hr;\r
+\r
+  hr = h / 360 * 2 * Math.PI;\r
+  a = c * Math.cos(hr);\r
+  b = c * Math.sin(hr);\r
+  return [l, a, b];\r
+}\r
+\r
+function lch2xyz(args) {\r
+  return lab2xyz(lch2lab(args));\r
+}\r
+\r
+function lch2rgb(args) {\r
+  return lab2rgb(lch2lab(args));\r
+}\r
+\r
+function keyword2rgb(keyword) {\r
+  return cssKeywords[keyword];\r
+}\r
+\r
+function keyword2hsl(args) {\r
+  return rgb2hsl(keyword2rgb(args));\r
+}\r
+\r
+function keyword2hsv(args) {\r
+  return rgb2hsv(keyword2rgb(args));\r
+}\r
+\r
+function keyword2hwb(args) {\r
+  return rgb2hwb(keyword2rgb(args));\r
+}\r
+\r
+function keyword2cmyk(args) {\r
+  return rgb2cmyk(keyword2rgb(args));\r
+}\r
+\r
+function keyword2lab(args) {\r
+  return rgb2lab(keyword2rgb(args));\r
+}\r
+\r
+function keyword2xyz(args) {\r
+  return rgb2xyz(keyword2rgb(args));\r
+}\r
+\r
+var cssKeywords = {\r
+  aliceblue:  [240,248,255],\r
+  antiquewhite: [250,235,215],\r
+  aqua: [0,255,255],\r
+  aquamarine: [127,255,212],\r
+  azure:  [240,255,255],\r
+  beige:  [245,245,220],\r
+  bisque: [255,228,196],\r
+  black:  [0,0,0],\r
+  blanchedalmond: [255,235,205],\r
+  blue: [0,0,255],\r
+  blueviolet: [138,43,226],\r
+  brown:  [165,42,42],\r
+  burlywood:  [222,184,135],\r
+  cadetblue:  [95,158,160],\r
+  chartreuse: [127,255,0],\r
+  chocolate:  [210,105,30],\r
+  coral:  [255,127,80],\r
+  cornflowerblue: [100,149,237],\r
+  cornsilk: [255,248,220],\r
+  crimson:  [220,20,60],\r
+  cyan: [0,255,255],\r
+  darkblue: [0,0,139],\r
+  darkcyan: [0,139,139],\r
+  darkgoldenrod:  [184,134,11],\r
+  darkgray: [169,169,169],\r
+  darkgreen:  [0,100,0],\r
+  darkgrey: [169,169,169],\r
+  darkkhaki:  [189,183,107],\r
+  darkmagenta:  [139,0,139],\r
+  darkolivegreen: [85,107,47],\r
+  darkorange: [255,140,0],\r
+  darkorchid: [153,50,204],\r
+  darkred:  [139,0,0],\r
+  darksalmon: [233,150,122],\r
+  darkseagreen: [143,188,143],\r
+  darkslateblue:  [72,61,139],\r
+  darkslategray:  [47,79,79],\r
+  darkslategrey:  [47,79,79],\r
+  darkturquoise:  [0,206,209],\r
+  darkviolet: [148,0,211],\r
+  deeppink: [255,20,147],\r
+  deepskyblue:  [0,191,255],\r
+  dimgray:  [105,105,105],\r
+  dimgrey:  [105,105,105],\r
+  dodgerblue: [30,144,255],\r
+  firebrick:  [178,34,34],\r
+  floralwhite:  [255,250,240],\r
+  forestgreen:  [34,139,34],\r
+  fuchsia:  [255,0,255],\r
+  gainsboro:  [220,220,220],\r
+  ghostwhite: [248,248,255],\r
+  gold: [255,215,0],\r
+  goldenrod:  [218,165,32],\r
+  gray: [128,128,128],\r
+  green:  [0,128,0],\r
+  greenyellow:  [173,255,47],\r
+  grey: [128,128,128],\r
+  honeydew: [240,255,240],\r
+  hotpink:  [255,105,180],\r
+  indianred:  [205,92,92],\r
+  indigo: [75,0,130],\r
+  ivory:  [255,255,240],\r
+  khaki:  [240,230,140],\r
+  lavender: [230,230,250],\r
+  lavenderblush:  [255,240,245],\r
+  lawngreen:  [124,252,0],\r
+  lemonchiffon: [255,250,205],\r
+  lightblue:  [173,216,230],\r
+  lightcoral: [240,128,128],\r
+  lightcyan:  [224,255,255],\r
+  lightgoldenrodyellow: [250,250,210],\r
+  lightgray:  [211,211,211],\r
+  lightgreen: [144,238,144],\r
+  lightgrey:  [211,211,211],\r
+  lightpink:  [255,182,193],\r
+  lightsalmon:  [255,160,122],\r
+  lightseagreen:  [32,178,170],\r
+  lightskyblue: [135,206,250],\r
+  lightslategray: [119,136,153],\r
+  lightslategrey: [119,136,153],\r
+  lightsteelblue: [176,196,222],\r
+  lightyellow:  [255,255,224],\r
+  lime: [0,255,0],\r
+  limegreen:  [50,205,50],\r
+  linen:  [250,240,230],\r
+  magenta:  [255,0,255],\r
+  maroon: [128,0,0],\r
+  mediumaquamarine: [102,205,170],\r
+  mediumblue: [0,0,205],\r
+  mediumorchid: [186,85,211],\r
+  mediumpurple: [147,112,219],\r
+  mediumseagreen: [60,179,113],\r
+  mediumslateblue:  [123,104,238],\r
+  mediumspringgreen:  [0,250,154],\r
+  mediumturquoise:  [72,209,204],\r
+  mediumvioletred:  [199,21,133],\r
+  midnightblue: [25,25,112],\r
+  mintcream:  [245,255,250],\r
+  mistyrose:  [255,228,225],\r
+  moccasin: [255,228,181],\r
+  navajowhite:  [255,222,173],\r
+  navy: [0,0,128],\r
+  oldlace:  [253,245,230],\r
+  olive:  [128,128,0],\r
+  olivedrab:  [107,142,35],\r
+  orange: [255,165,0],\r
+  orangered:  [255,69,0],\r
+  orchid: [218,112,214],\r
+  palegoldenrod:  [238,232,170],\r
+  palegreen:  [152,251,152],\r
+  paleturquoise:  [175,238,238],\r
+  palevioletred:  [219,112,147],\r
+  papayawhip: [255,239,213],\r
+  peachpuff:  [255,218,185],\r
+  peru: [205,133,63],\r
+  pink: [255,192,203],\r
+  plum: [221,160,221],\r
+  powderblue: [176,224,230],\r
+  purple: [128,0,128],\r
+  rebeccapurple: [102, 51, 153],\r
+  red:  [255,0,0],\r
+  rosybrown:  [188,143,143],\r
+  royalblue:  [65,105,225],\r
+  saddlebrown:  [139,69,19],\r
+  salmon: [250,128,114],\r
+  sandybrown: [244,164,96],\r
+  seagreen: [46,139,87],\r
+  seashell: [255,245,238],\r
+  sienna: [160,82,45],\r
+  silver: [192,192,192],\r
+  skyblue:  [135,206,235],\r
+  slateblue:  [106,90,205],\r
+  slategray:  [112,128,144],\r
+  slategrey:  [112,128,144],\r
+  snow: [255,250,250],\r
+  springgreen:  [0,255,127],\r
+  steelblue:  [70,130,180],\r
+  tan:  [210,180,140],\r
+  teal: [0,128,128],\r
+  thistle:  [216,191,216],\r
+  tomato: [255,99,71],\r
+  turquoise:  [64,224,208],\r
+  violet: [238,130,238],\r
+  wheat:  [245,222,179],\r
+  white:  [255,255,255],\r
+  whitesmoke: [245,245,245],\r
+  yellow: [255,255,0],\r
+  yellowgreen:  [154,205,50]\r
+};\r
+\r
+var reverseKeywords = {};\r
+for (var key in cssKeywords) {\r
+  reverseKeywords[JSON.stringify(cssKeywords[key])] = key;\r
+}\r
+\r
+},{}],5:[function(require,module,exports){\r
+var conversions = require(4);\r
+\r
+var convert = function() {\r
+   return new Converter();\r
+}\r
+\r
+for (var func in conversions) {\r
+  // export Raw versions\r
+  convert[func + "Raw"] =  (function(func) {\r
+    // accept array or plain args\r
+    return function(arg) {\r
+      if (typeof arg == "number")\r
+        arg = Array.prototype.slice.call(arguments);\r
+      return conversions[func](arg);\r
+    }\r
+  })(func);\r
+\r
+  var pair = /(\w+)2(\w+)/.exec(func),\r
+      from = pair[1],\r
+      to = pair[2];\r
+\r
+  // export rgb2hsl and ["rgb"]["hsl"]\r
+  convert[from] = convert[from] || {};\r
+\r
+  convert[from][to] = convert[func] = (function(func) { \r
+    return function(arg) {\r
+      if (typeof arg == "number")\r
+        arg = Array.prototype.slice.call(arguments);\r
+      \r
+      var val = conversions[func](arg);\r
+      if (typeof val == "string" || val === undefined)\r
+        return val; // keyword\r
+\r
+      for (var i = 0; i < val.length; i++)\r
+        val[i] = Math.round(val[i]);\r
+      return val;\r
+    }\r
+  })(func);\r
+}\r
+\r
+\r
+/* Converter does lazy conversion and caching */\r
+var Converter = function() {\r
+   this.convs = {};\r
+};\r
+\r
+/* Either get the values for a space or\r
+  set the values for a space, depending on args */\r
+Converter.prototype.routeSpace = function(space, args) {\r
+   var values = args[0];\r
+   if (values === undefined) {\r
+      // color.rgb()\r
+      return this.getValues(space);\r
+   }\r
+   // color.rgb(10, 10, 10)\r
+   if (typeof values == "number") {\r
+      values = Array.prototype.slice.call(args);        \r
+   }\r
+\r
+   return this.setValues(space, values);\r
+};\r
+  \r
+/* Set the values for a space, invalidating cache */\r
+Converter.prototype.setValues = function(space, values) {\r
+   this.space = space;\r
+   this.convs = {};\r
+   this.convs[space] = values;\r
+   return this;\r
+};\r
+\r
+/* Get the values for a space. If there's already\r
+  a conversion for the space, fetch it, otherwise\r
+  compute it */\r
+Converter.prototype.getValues = function(space) {\r
+   var vals = this.convs[space];\r
+   if (!vals) {\r
+      var fspace = this.space,\r
+          from = this.convs[fspace];\r
+      vals = convert[fspace][space](from);\r
+\r
+      this.convs[space] = vals;\r
+   }\r
+  return vals;\r
+};\r
+\r
+["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {\r
+   Converter.prototype[space] = function(vals) {\r
+      return this.routeSpace(space, arguments);\r
+   }\r
+});\r
+\r
+module.exports = convert;\r
+},{"4":4}],6:[function(require,module,exports){\r
+module.exports = {\r
+       "aliceblue": [240, 248, 255],\r
+       "antiquewhite": [250, 235, 215],\r
+       "aqua": [0, 255, 255],\r
+       "aquamarine": [127, 255, 212],\r
+       "azure": [240, 255, 255],\r
+       "beige": [245, 245, 220],\r
+       "bisque": [255, 228, 196],\r
+       "black": [0, 0, 0],\r
+       "blanchedalmond": [255, 235, 205],\r
+       "blue": [0, 0, 255],\r
+       "blueviolet": [138, 43, 226],\r
+       "brown": [165, 42, 42],\r
+       "burlywood": [222, 184, 135],\r
+       "cadetblue": [95, 158, 160],\r
+       "chartreuse": [127, 255, 0],\r
+       "chocolate": [210, 105, 30],\r
+       "coral": [255, 127, 80],\r
+       "cornflowerblue": [100, 149, 237],\r
+       "cornsilk": [255, 248, 220],\r
+       "crimson": [220, 20, 60],\r
+       "cyan": [0, 255, 255],\r
+       "darkblue": [0, 0, 139],\r
+       "darkcyan": [0, 139, 139],\r
+       "darkgoldenrod": [184, 134, 11],\r
+       "darkgray": [169, 169, 169],\r
+       "darkgreen": [0, 100, 0],\r
+       "darkgrey": [169, 169, 169],\r
+       "darkkhaki": [189, 183, 107],\r
+       "darkmagenta": [139, 0, 139],\r
+       "darkolivegreen": [85, 107, 47],\r
+       "darkorange": [255, 140, 0],\r
+       "darkorchid": [153, 50, 204],\r
+       "darkred": [139, 0, 0],\r
+       "darksalmon": [233, 150, 122],\r
+       "darkseagreen": [143, 188, 143],\r
+       "darkslateblue": [72, 61, 139],\r
+       "darkslategray": [47, 79, 79],\r
+       "darkslategrey": [47, 79, 79],\r
+       "darkturquoise": [0, 206, 209],\r
+       "darkviolet": [148, 0, 211],\r
+       "deeppink": [255, 20, 147],\r
+       "deepskyblue": [0, 191, 255],\r
+       "dimgray": [105, 105, 105],\r
+       "dimgrey": [105, 105, 105],\r
+       "dodgerblue": [30, 144, 255],\r
+       "firebrick": [178, 34, 34],\r
+       "floralwhite": [255, 250, 240],\r
+       "forestgreen": [34, 139, 34],\r
+       "fuchsia": [255, 0, 255],\r
+       "gainsboro": [220, 220, 220],\r
+       "ghostwhite": [248, 248, 255],\r
+       "gold": [255, 215, 0],\r
+       "goldenrod": [218, 165, 32],\r
+       "gray": [128, 128, 128],\r
+       "green": [0, 128, 0],\r
+       "greenyellow": [173, 255, 47],\r
+       "grey": [128, 128, 128],\r
+       "honeydew": [240, 255, 240],\r
+       "hotpink": [255, 105, 180],\r
+       "indianred": [205, 92, 92],\r
+       "indigo": [75, 0, 130],\r
+       "ivory": [255, 255, 240],\r
+       "khaki": [240, 230, 140],\r
+       "lavender": [230, 230, 250],\r
+       "lavenderblush": [255, 240, 245],\r
+       "lawngreen": [124, 252, 0],\r
+       "lemonchiffon": [255, 250, 205],\r
+       "lightblue": [173, 216, 230],\r
+       "lightcoral": [240, 128, 128],\r
+       "lightcyan": [224, 255, 255],\r
+       "lightgoldenrodyellow": [250, 250, 210],\r
+       "lightgray": [211, 211, 211],\r
+       "lightgreen": [144, 238, 144],\r
+       "lightgrey": [211, 211, 211],\r
+       "lightpink": [255, 182, 193],\r
+       "lightsalmon": [255, 160, 122],\r
+       "lightseagreen": [32, 178, 170],\r
+       "lightskyblue": [135, 206, 250],\r
+       "lightslategray": [119, 136, 153],\r
+       "lightslategrey": [119, 136, 153],\r
+       "lightsteelblue": [176, 196, 222],\r
+       "lightyellow": [255, 255, 224],\r
+       "lime": [0, 255, 0],\r
+       "limegreen": [50, 205, 50],\r
+       "linen": [250, 240, 230],\r
+       "magenta": [255, 0, 255],\r
+       "maroon": [128, 0, 0],\r
+       "mediumaquamarine": [102, 205, 170],\r
+       "mediumblue": [0, 0, 205],\r
+       "mediumorchid": [186, 85, 211],\r
+       "mediumpurple": [147, 112, 219],\r
+       "mediumseagreen": [60, 179, 113],\r
+       "mediumslateblue": [123, 104, 238],\r
+       "mediumspringgreen": [0, 250, 154],\r
+       "mediumturquoise": [72, 209, 204],\r
+       "mediumvioletred": [199, 21, 133],\r
+       "midnightblue": [25, 25, 112],\r
+       "mintcream": [245, 255, 250],\r
+       "mistyrose": [255, 228, 225],\r
+       "moccasin": [255, 228, 181],\r
+       "navajowhite": [255, 222, 173],\r
+       "navy": [0, 0, 128],\r
+       "oldlace": [253, 245, 230],\r
+       "olive": [128, 128, 0],\r
+       "olivedrab": [107, 142, 35],\r
+       "orange": [255, 165, 0],\r
+       "orangered": [255, 69, 0],\r
+       "orchid": [218, 112, 214],\r
+       "palegoldenrod": [238, 232, 170],\r
+       "palegreen": [152, 251, 152],\r
+       "paleturquoise": [175, 238, 238],\r
+       "palevioletred": [219, 112, 147],\r
+       "papayawhip": [255, 239, 213],\r
+       "peachpuff": [255, 218, 185],\r
+       "peru": [205, 133, 63],\r
+       "pink": [255, 192, 203],\r
+       "plum": [221, 160, 221],\r
+       "powderblue": [176, 224, 230],\r
+       "purple": [128, 0, 128],\r
+       "rebeccapurple": [102, 51, 153],\r
+       "red": [255, 0, 0],\r
+       "rosybrown": [188, 143, 143],\r
+       "royalblue": [65, 105, 225],\r
+       "saddlebrown": [139, 69, 19],\r
+       "salmon": [250, 128, 114],\r
+       "sandybrown": [244, 164, 96],\r
+       "seagreen": [46, 139, 87],\r
+       "seashell": [255, 245, 238],\r
+       "sienna": [160, 82, 45],\r
+       "silver": [192, 192, 192],\r
+       "skyblue": [135, 206, 235],\r
+       "slateblue": [106, 90, 205],\r
+       "slategray": [112, 128, 144],\r
+       "slategrey": [112, 128, 144],\r
+       "snow": [255, 250, 250],\r
+       "springgreen": [0, 255, 127],\r
+       "steelblue": [70, 130, 180],\r
+       "tan": [210, 180, 140],\r
+       "teal": [0, 128, 128],\r
+       "thistle": [216, 191, 216],\r
+       "tomato": [255, 99, 71],\r
+       "turquoise": [64, 224, 208],\r
+       "violet": [238, 130, 238],\r
+       "wheat": [245, 222, 179],\r
+       "white": [255, 255, 255],\r
+       "whitesmoke": [245, 245, 245],\r
+       "yellow": [255, 255, 0],\r
+       "yellowgreen": [154, 205, 50]\r
+};\r
+},{}],7:[function(require,module,exports){\r
+/**\r
+ * @namespace Chart\r
+ */\r
+var Chart = require(26)();\r
+\r
+require(25)(Chart);\r
+require(24)(Chart);\r
+require(21)(Chart);\r
+require(22)(Chart);\r
+require(23)(Chart);\r
+require(27)(Chart);\r
+require(31)(Chart);\r
+require(29)(Chart);\r
+require(30)(Chart);\r
+require(32)(Chart);\r
+require(28)(Chart);\r
+require(33)(Chart);\r
+\r
+require(34)(Chart);\r
+require(35)(Chart);\r
+require(36)(Chart);\r
+require(37)(Chart);\r
+\r
+require(40)(Chart);\r
+require(38)(Chart);\r
+require(39)(Chart);\r
+require(41)(Chart);\r
+require(42)(Chart);\r
+require(43)(Chart);\r
+\r
+// Controllers must be loaded after elements\r
+// See Chart.core.datasetController.dataElementType\r
+require(15)(Chart);\r
+require(16)(Chart);\r
+require(17)(Chart);\r
+require(18)(Chart);\r
+require(19)(Chart);\r
+require(20)(Chart);\r
+\r
+require(8)(Chart);\r
+require(9)(Chart);\r
+require(10)(Chart);\r
+require(11)(Chart);\r
+require(12)(Chart);\r
+require(13)(Chart);\r
+require(14)(Chart);\r
+\r
+window.Chart = module.exports = Chart;\r
+\r
+},{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32&q