소스 검색

Merge branch 'master' of http://git.bocai108.com:10180/Ethan/Customer-Service

Jonlin 6 년 전
부모
커밋
f23b9a4676
100개의 변경된 파일5402개의 추가작업 그리고 245개의 파일을 삭제
  1. 64 36
      application/admin/controller/Report.php
  2. 72 0
      application/admin/model/Office.php
  3. 21 8
      application/admin/view/report/attendancereport.html
  4. 119 71
      application/admin/view/report/index.html
  5. 14 55
      application/common.php
  6. 1 1
      application/service/controller/Login.php
  7. 1 1
      composer.json
  8. 69 72
      vendor/GatewayWorker_linux/GatewayWorker/vendor/workerman/gateway-worker/src/Lib/Gateway.php
  9. 1 1
      vendor/GatewayWorker_windows/Applications/whisper/Events.php
  10. 67 0
      vendor/composer/autoload_files.php
  11. 4 0
      vendor/composer/autoload_psr4.php
  12. 18 0
      vendor/composer/autoload_real.php
  13. 90 0
      vendor/composer/autoload_static.php
  14. 315 0
      vendor/composer/installed.json
  15. 156 0
      vendor/markbaker/complex/README.md
  16. 53 0
      vendor/markbaker/complex/classes/Autoloader.php
  17. 38 0
      vendor/markbaker/complex/classes/Bootstrap.php
  18. 387 0
      vendor/markbaker/complex/classes/src/Complex.php
  19. 13 0
      vendor/markbaker/complex/classes/src/Exception.php
  20. 29 0
      vendor/markbaker/complex/classes/src/functions/abs.php
  21. 38 0
      vendor/markbaker/complex/classes/src/functions/acos.php
  22. 34 0
      vendor/markbaker/complex/classes/src/functions/acosh.php
  23. 25 0
      vendor/markbaker/complex/classes/src/functions/acot.php
  24. 25 0
      vendor/markbaker/complex/classes/src/functions/acoth.php
  25. 29 0
      vendor/markbaker/complex/classes/src/functions/acsc.php
  26. 29 0
      vendor/markbaker/complex/classes/src/functions/acsch.php
  27. 28 0
      vendor/markbaker/complex/classes/src/functions/argument.php
  28. 29 0
      vendor/markbaker/complex/classes/src/functions/asec.php
  29. 29 0
      vendor/markbaker/complex/classes/src/functions/asech.php
  30. 37 0
      vendor/markbaker/complex/classes/src/functions/asin.php
  31. 33 0
      vendor/markbaker/complex/classes/src/functions/asinh.php
  32. 45 0
      vendor/markbaker/complex/classes/src/functions/atan.php
  33. 38 0
      vendor/markbaker/complex/classes/src/functions/atanh.php
  34. 28 0
      vendor/markbaker/complex/classes/src/functions/conjugate.php
  35. 34 0
      vendor/markbaker/complex/classes/src/functions/cos.php
  36. 32 0
      vendor/markbaker/complex/classes/src/functions/cosh.php
  37. 29 0
      vendor/markbaker/complex/classes/src/functions/cot.php
  38. 24 0
      vendor/markbaker/complex/classes/src/functions/coth.php
  39. 29 0
      vendor/markbaker/complex/classes/src/functions/csc.php
  40. 29 0
      vendor/markbaker/complex/classes/src/functions/csch.php
  41. 34 0
      vendor/markbaker/complex/classes/src/functions/exp.php
  42. 29 0
      vendor/markbaker/complex/classes/src/functions/inverse.php
  43. 33 0
      vendor/markbaker/complex/classes/src/functions/ln.php
  44. 32 0
      vendor/markbaker/complex/classes/src/functions/log10.php
  45. 32 0
      vendor/markbaker/complex/classes/src/functions/log2.php
  46. 31 0
      vendor/markbaker/complex/classes/src/functions/negative.php
  47. 40 0
      vendor/markbaker/complex/classes/src/functions/pow.php
  48. 28 0
      vendor/markbaker/complex/classes/src/functions/rho.php
  49. 25 0
      vendor/markbaker/complex/classes/src/functions/sec.php
  50. 25 0
      vendor/markbaker/complex/classes/src/functions/sech.php
  51. 32 0
      vendor/markbaker/complex/classes/src/functions/sin.php
  52. 32 0
      vendor/markbaker/complex/classes/src/functions/sinh.php
  53. 29 0
      vendor/markbaker/complex/classes/src/functions/sqrt.php
  54. 40 0
      vendor/markbaker/complex/classes/src/functions/tan.php
  55. 35 0
      vendor/markbaker/complex/classes/src/functions/tanh.php
  56. 38 0
      vendor/markbaker/complex/classes/src/functions/theta.php
  57. 46 0
      vendor/markbaker/complex/classes/src/operations/add.php
  58. 56 0
      vendor/markbaker/complex/classes/src/operations/divideby.php
  59. 56 0
      vendor/markbaker/complex/classes/src/operations/divideinto.php
  60. 48 0
      vendor/markbaker/complex/classes/src/operations/multiply.php
  61. 46 0
      vendor/markbaker/complex/classes/src/operations/subtract.php
  62. 91 0
      vendor/markbaker/complex/composer.json
  63. 154 0
      vendor/markbaker/complex/examples/complexTest.php
  64. 52 0
      vendor/markbaker/complex/examples/testFunctions.php
  65. 34 0
      vendor/markbaker/complex/examples/testOperations.php
  66. 25 0
      vendor/markbaker/complex/license.md
  67. 165 0
      vendor/markbaker/matrix/README.md
  68. 62 0
      vendor/markbaker/matrix/buildPhar.php
  69. 53 0
      vendor/markbaker/matrix/classes/Autoloader.php
  70. 38 0
      vendor/markbaker/matrix/classes/Bootstrap.php
  71. 69 0
      vendor/markbaker/matrix/classes/src/Builder.php
  72. 13 0
      vendor/markbaker/matrix/classes/src/Exception.php
  73. 318 0
      vendor/markbaker/matrix/classes/src/Functions.php
  74. 403 0
      vendor/markbaker/matrix/classes/src/Matrix.php
  75. 68 0
      vendor/markbaker/matrix/classes/src/Operators/Addition.php
  76. 65 0
      vendor/markbaker/matrix/classes/src/Operators/DirectSum.php
  77. 38 0
      vendor/markbaker/matrix/classes/src/Operators/Division.php
  78. 77 0
      vendor/markbaker/matrix/classes/src/Operators/Multiplication.php
  79. 78 0
      vendor/markbaker/matrix/classes/src/Operators/Operator.php
  80. 68 0
      vendor/markbaker/matrix/classes/src/Operators/Subtraction.php
  81. 26 0
      vendor/markbaker/matrix/classes/src/functions/adjoint.php
  82. 26 0
      vendor/markbaker/matrix/classes/src/functions/antidiagonal.php
  83. 26 0
      vendor/markbaker/matrix/classes/src/functions/cofactors.php
  84. 26 0
      vendor/markbaker/matrix/classes/src/functions/determinant.php
  85. 26 0
      vendor/markbaker/matrix/classes/src/functions/diagonal.php
  86. 26 0
      vendor/markbaker/matrix/classes/src/functions/identity.php
  87. 26 0
      vendor/markbaker/matrix/classes/src/functions/inverse.php
  88. 26 0
      vendor/markbaker/matrix/classes/src/functions/minors.php
  89. 26 0
      vendor/markbaker/matrix/classes/src/functions/trace.php
  90. 26 0
      vendor/markbaker/matrix/classes/src/functions/transpose.php
  91. 39 0
      vendor/markbaker/matrix/classes/src/operations/add.php
  92. 39 0
      vendor/markbaker/matrix/classes/src/operations/directsum.php
  93. 38 0
      vendor/markbaker/matrix/classes/src/operations/divideby.php
  94. 39 0
      vendor/markbaker/matrix/classes/src/operations/divideinto.php
  95. 39 0
      vendor/markbaker/matrix/classes/src/operations/multiply.php
  96. 39 0
      vendor/markbaker/matrix/classes/src/operations/subtract.php
  97. 68 0
      vendor/markbaker/matrix/composer.json
  98. 19 0
      vendor/markbaker/matrix/examples/test.php
  99. 25 0
      vendor/markbaker/matrix/license.md
  100. 3 0
      vendor/phpoffice/phpspreadsheet/.gitattributes

+ 64 - 36
application/admin/controller/Report.php

@@ -8,6 +8,8 @@ use app\admin\model\Users as Usersmodel;
 use app\admin\model\Groups as GroupsModel;
 use app\admin\model\Servicetimelog as ServicetimelogModel;
 use app\admin\model\Kfstatetimes as KfstatetimesModel;
+use app\admin\model\Office;
+
 
 /**
  * 报表类
@@ -24,32 +26,41 @@ class Report extends Base
      */
     public function index()
     {
-        $param = input('param.');
-        $startTime = isset($param['start']) ? $param['start'] : date('Y-m-d', strtotime("-6 day"));
-        $endTime = isset($param['end']) ? $param['end'] : date('Y-m-d');
-        $timeInterval = $this->Date_segmentation($startTime, $endTime);
-        $queueData = [];
-        $chatData = [];
-        $serviceData = [];
-        $xData = [];
+        $param             = input('param.');
+        $startTime         = isset($param['start']) === true ? $param['start'] : date('Y-m-d', strtotime("-6 day"));
+        $endTime           = isset($param['end']) === true ? $param['end'] : date('Y-m-d');
+        $timeInterval      = $this->Date_segmentation($startTime, $endTime);
+        $queueData         = []; // 排队数据.
+        $chatData          = []; // 消息数据.
+        $serviceData       = []; // 会话数据.
+        $xData             = []; // x轴数据.
+        $system            = []; // 系统数据.
+        $evaluateGood      = 0;  // 好评数.
+        $evaluateSecondary = 0;  // 中评数.
+        $evaluateBad       = 0;  // 差评数.
+        $evaluateNo        = 0;  // 未评数.
         foreach ($timeInterval['days_list'] as $k => $value) {
-            $allCount = 0;
-            $evaluateGood = 0;
-            $evaluateSecondary = 0;
-            $evaluateBad = 0;
-            $evaluateNo = 0;
+            $allCount = 0;  // 会话总数.
             $dayBegin = strtotime($value);
-            $dayEnd = strtotime($value) + 24 * 60 * 60;
-            $chatLogCountWhere['start_time'] = ['between', [$dayBegin, $dayEnd]];
-            $join = [
+            $dayEnd   = (strtotime($value) + 24 * 60 * 60);
+            $chatLogCountWhere['start_time'] = [
+                'between',
+                [
+                    $dayBegin,
+                    $dayEnd,
+                ],
+            ];
+            $join  = [
                 'alarm b' => 'a.servicelog_id = b.servicelog_id',
             ];
-            $field = ['alarm_count', 'evaluate_id', 'system'];
-            $system = [];
-            $systemCount = [];
+            $field = [
+                'alarm_count',
+                'evaluate_id',
+                'system',
+            ];
             // 查询当天的工单.
             $serviceLog = model('serviceLog')->selectServiceLog($field, $join, $chatLogCountWhere);
-            foreach ($serviceLog as $ke => $va) {
+            foreach ($serviceLog as $va) {
                 $allCount += $va['alarm_count'];
                 if ($va['evaluate_id'] == 1) {
                     $evaluateGood++;
@@ -60,39 +71,45 @@ class Report extends Base
                 } elseif ($va['evaluate_id'] == 0) {
                     $evaluateNo++;
                 }
-                if (!isset($system[$va['system']])) {
+
+                if (isset($system[$va['system']]) === false) {
                     $system[$va['system']] = 1;
+
                 } else {
                     $system[$va['system']]++;
                 }
             }
+
             // 会话总数.
-            $xData[] = $value;
+            $xData[]      = $value;
             $chatData[$k] = $allCount;
             // 当天工单总数.
             $serviceData[$k] = model('serviceLog')->countServiceLog($chatLogCountWhere);
-        }
+        }//end foreach
+
         foreach ($system as $k => $v) {
             $systemCount[] = [
                 'value' => $v,
-                'name' => $k,
+                'name'  => $k,
             ];
         }
 
         $queueData = (new  Countmidtable())->getQueryDay($timeInterval['days_list']);
 
+        $defaultTime = "$startTime , $endTime";
 
         $this->assign([
-            'xData' => json_encode($xData),
-            'chatData' => json_encode($chatData),
+            'xData'       => json_encode($xData),
+            'chatData'    => json_encode($chatData),
             'serviceData' => json_encode($serviceData),
-            'queueData' => json_encode($queueData),
+            'queueData'   => json_encode($queueData),
             'systemCount' => json_encode($systemCount),
-            'evaluate' => json_encode([
-                'evaluateGood' => $evaluateGood,
+            'defaultTime' => json_encode($defaultTime),
+            'evaluate'    => json_encode([
+                'evaluateGood'      => $evaluateGood,
                 'evaluateSecondary' => $evaluateSecondary,
-                'evaluateBad' => $evaluateBad,
-                'evaluateNo' => $evaluateNo,
+                'evaluateBad'       => $evaluateBad,
+                'evaluateNo'        => $evaluateNo,
             ]),
         ]);
 
@@ -108,8 +125,10 @@ class Report extends Base
         $serday1 = date("Y-m-d", strtotime('-7 day'));
         $serday2 = date("Y-m-d", strtotime('-1 day'));
         $defday = $serday1 . ',' . $serday2;
+        $toExcel = input('param.toExcel', 0);
 
-        if (request()->isAjax()) {
+
+        if (request()->isAjax() || $toExcel) {
 
             $param = input('param.');
             $limit = $param['pageSize'];
@@ -140,9 +159,16 @@ class Report extends Base
             $model2 = new  KfstatetimesModel();
             $ret1 = $model1->getDayData($zoneArray1, $uidarr['uids']);
             $ret2 = $model2->getDayData($zoneArray1, $uidarr['uids']);
-            $retall = $this->reportDataFormat($ret1, $ret2, $uidarr['objs'], $zoneArray1, $limit, $offset);
-
-            return json($retall);
+            if (!$toExcel) {
+                $retall = $this->reportDataFormat($ret1, $ret2, $uidarr['objs'], $zoneArray1, $limit, $offset);
+                return json($retall);
+            } else {
+                $title = ['账号', '姓名', '日期', '首次登陆时间', '最后登出时间', '登陆时长', '休息时长', '隐身时长', '在线占比', '休息占比', '', '隐身占比'];
+                $titleKey = ['account', 'uname', 'day', 'of0', 'of1', 'all', '1', '2', '3', 's1p', 's2p', 's3p'];
+                $retall = $this->reportDataFormat($ret1, $ret2, $uidarr['objs'], $zoneArray1, $limit, $offset, true);
+                (new Office())->outdata('考勤数据导出', $retall, $title, $titleKey);
+                return true;
+            }
         }
 
         $this->assign('groups', $goups);
@@ -176,7 +202,7 @@ class Report extends Base
         }
 
         usort($all_last, function ($a, $b) {
-            return $a == $b ? 0 : ($a > $b ? 1 : -1);
+            return $a['uid'] == $b['uid'] ? 0 : ($a['uid'] > $b['uid'] ? 1 : -1);
         });
 
         foreach ($all_last as $key => $val) {
@@ -186,6 +212,8 @@ class Report extends Base
             $all_last[$key]['s1p'] = perDisplay($all_last[$key]['s1p']);
             $all_last[$key]['s2p'] = perDisplay($all_last[$key]['s2p']);
             $all_last[$key]['s3p'] = perDisplay($all_last[$key]['s3p']);
+            unset($all_last[$key]['uid']);
+            unset($all_last[$key]['0']);
         }
 
         //导出数据

+ 72 - 0
application/admin/model/Office.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * Created by PhpStorm.
+ * User: Administrator
+ * Date: 2019/7/15
+ * Time: 12:27
+ */
+
+namespace App\admin\model;
+
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
+
+class Office
+{
+
+    /**
+     * 导出excel表
+     * $data:要导出excel表的数据,接受一个二维数组
+     * $name:excel表的表名
+     * $head:excel表的表头,接受一个一维数组
+     * $key:$data中对应表头的键的数组,接受一个一维数组
+     * 备注:此函数缺点是,表头(对应列数)不能超过26;
+     *循环不够灵活,一个单元格中不方便存放两个数据库字段的值
+     */
+
+    public function outdata($name = '测试表', $data = [], $head = [], $keys = [])
+    {
+        $count = count($head);  //计算表头数量
+
+        $spreadsheet = new Spreadsheet();
+        $sheet = $spreadsheet->getActiveSheet();
+
+        for ($i = 65; $i < $count + 65; $i++) {     //数字转字母从65开始,循环设置表头:
+            $sheet->setCellValue(strtoupper(chr($i)) . '1', $head[$i - 65]);
+        }
+
+        /*--------------开始从数据库提取信息插入Excel表中------------------*/
+
+        foreach ($data as $key => $item) {             //循环设置单元格:
+            //$key+2,因为第一行是表头,所以写到表格时   从第二行开始写
+
+            for ($i = 65; $i < $count + 65; $i++) {     //数字转字母从65开始:
+                $sheet->setCellValue(strtoupper(chr($i)) . ($key + 2), $item[$keys[$i - 65]]);
+                $spreadsheet->getActiveSheet()->getColumnDimension(strtoupper(chr($i)))->setWidth(20); //固定列宽
+            }
+        }
+
+        header('Content-Type: application/vnd.ms-excel');
+        header('Content-Disposition: attachment;filename="' . $name . '.xlsx"');
+        header('Cache-Control: max-age=0');
+        $writer = new Xlsx($spreadsheet);
+        $writer->save('php://output');
+
+        //删除清空:
+        $spreadsheet->disconnectWorksheets();
+        unset($spreadsheet);
+        exit;
+    }
+
+}
+/**
+ *
+$excel = new Office();
+//设置表头:
+$head = ['订单编号', '商品总数', '收货人', '联系电话', '收货地址'];
+//数据中对应的字段,用于读取相应数据:
+$keys = ['order_sn', 'num', 'consignee', 'phone', 'detail'];
+$excel->outdata('订单表', $orders, $head, $keys);
+
+ *
+ * */

+ 21 - 8
application/admin/view/report/attendancereport.html

@@ -26,7 +26,8 @@
                 <div class="content clearfix m-b">
                     <div class="form-group">
                         <div class="layui-input-inline">
-                            <input type="text" class="layui-input" name="daterang" id="daterang" value="{$dzone}" placeholder="时间段"
+                            <input type="text" class="layui-input" name="daterang" id="daterang" value="{$dzone}"
+                                   placeholder="时间段"
                                    readonly="">
                         </div>
                     </div>
@@ -47,6 +48,11 @@
                         </button>
                     </div>
 
+                    <div class="form-group" style="margin-left:50px;">
+                        <button class="btn btn-primary" type="button" id="toExcel" name="toExcel" value="0"><strong>导出Excel</strong>
+                        </button>
+                    </div>
+
                 </div>
             </form>
             <!--搜索框结束-->
@@ -84,18 +90,18 @@
 <script type="text/javascript">
     var ReturnRes;
 
+    function getSearch() {
+        var Searchtxt = '';
+        Searchtxt = $("#daterang").val();
+        Searchtxt += "|" + $("#groupid").val();
+        return Searchtxt;
+    }
+
     function initTable() {
         //先销毁表格
         $('#cusTable').bootstrapTable('destroy');
 
         //初始化表格,动态从服务器加载数据
-        function getSearch() {
-            var Searchtxt = '';
-            Searchtxt = $("#daterang").val();
-            Searchtxt += "|" + $("#groupid").val();
-
-            return Searchtxt;
-        }
 
         $("#cusTable").bootstrapTable({
             method: "get",  //使用get请求到服务器获取数据
@@ -138,6 +144,13 @@
 
         //当点击查询按钮的时候执行
         $("#search").bind("click", initTable);
+
+        $("#toExcel").on("click", function () {
+            $("#toExcel").val(1);
+            var url = "{:url('report/attendancereport')}" + "?pageNumber=1&pageSize=100&toExcel=1&searchText=" + getSearch();
+            window.open(url);
+            return false;
+        });
     });
 
 

+ 119 - 71
application/admin/view/report/index.html

@@ -9,6 +9,7 @@
     <link href="https://cdn.staticfile.org/font-awesome/4.4.0/css/font-awesome.css?v=4.4.0" rel="stylesheet">
     <link href="https://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">
     <link href="__CSS__/style.min.css?v=4.1.0" rel="stylesheet">
+    <link href="__JS__/layui/css/layui.css" rel="stylesheet">
 </head>
 <body class="gray-bg">
 <div class="wrapper wrapper-content">
@@ -20,9 +21,25 @@
         <div class="col-sm-12">
             <div class="ibox float-e-margins">
                 <div class="ibox-title">
-                    <h5>今日数据分析</h5>
+                    <h5>会话总览</h5>
                 </div>
                 <div class="ibox-content">
+                    <!--搜索框开始-->
+                    <form id='commentForm' role="form" method="post" class="form-inline pull-right">
+                        <div class="content clearfix m-b">
+                            <div class="form-group">
+                                <label>时间区间:</label>
+                                <div class="layui-input-inline">
+                                    <input style="width: 180px;" type="text" class="layui-input" name="daterang" id="daterang" value={$defaultTime} placeholder="时间段"
+                                           readonly="">
+                                </div>
+                            </div>
+                            <div class="form-group">
+                                <button class="btn btn-primary" type="button" style="margin-top:5px" id="search"><strong>搜 索</strong>
+                                </button>
+                            </div>
+                        </div>
+                    </form>
                     <div class="ibox-content" style="height: 350px" id="bar">
 
                     </div>
@@ -40,19 +57,23 @@
         <div class="col-sm-12">
             <div class="ibox float-e-margins">
                 <div style="display: flex;">
-                    <div class="ibox-title" style="width: 50%;">
-                        <h5>今日数据分析</h5>
-                    </div>
-                    <div class="ibox-title" style="width: 50%;">
-                        <h5>今日数据分析</h5>
-                    </div>
-                </div>
-                <div class="ibox-content no-padding" style="display: flex;">
-                    <div class="ibox-content" style="width: 50%;height: 350px" id="pie_evaluate">
+                    <div style="width: 50%;">
+                        <div class="ibox-title">
+                            <h5>满意度</h5>
+                        </div>
+                        <div class="ibox-content" style="height: 350px" id="pie_evaluate">
 
+                        </div>
                     </div>
-                    <div class="ibox-content" style="width: 50%;height: 350px" id="pie_system">
+                    <div style="width: 50%; border-left: 1px solid #e7eaec;">
+                        <div class="ibox-title">
+                            <h5>访问来源</h5>
+                        </div>
+                        <div id="system_data" style="text-align: center; width: 100%; font-size: 16px;">
+                            <div class="ibox-content" style="height: 350px" id="pie_system">
 
+                            </div>
+                        </div>
                     </div>
                 </div>
             </div>
@@ -63,13 +84,14 @@
 <script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
 <script src="https://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
 <script src="/static/admin/js/plugins/echarts/echarts.min.js"></script>
+<script src="__JS__/layui/layui.all.js"></script>
 <script type="text/javascript">
     var xData = {$xData};
     var chatData = {$chatData};
     var serviceData = {$serviceData};
     var queueData = {$queueData};
     var evaluate = {$evaluate};
-    var systemCount = {$systemCount};
+    var systemCount = {$systemCount}.length  ? {$systemCount} : '';
     // 基于准备好的dom,初始化echarts实例
     var myChart_bar = echarts.init(document.getElementById('bar'));
     var pie_evaluate = echarts.init(document.getElementById('pie_evaluate'));
@@ -258,74 +280,100 @@
             }
         }]
     };
-    var option_PS = {
-        backgroundColor: '#fff',
 
-        tooltip: {
-            trigger: 'item',
-            formatter: "{b} : {c} ({d}%)"
-        },
+    // 使用刚指定的配置项和数据显示图表。
+    pie_evaluate.setOption(option_PE);
+    if (systemCount) {
+        var option_PS = {
+            backgroundColor: '#fff',
 
-        visualMap: {
-            show: false,
-            min: 500,
-            max: 600,
-            inRange: {
-                //colorLightness: [0, 1]
-            }
-        },
-        series: [{
-            name: '满意度',
-            type: 'pie',
-            radius: '50%',
-            center: ['50%', '50%'],
-            color: ['rgb(131,249,103)', '#FBFE27', '#FE5050', '#1DB7E5'], //'#FBFE27','rgb(11,228,96)','#FE5050'
-            data: systemCount.sort(function(a, b) {
-                return a.value - b.value
-            }),
-            roseType: 'radius',
+            tooltip: {
+                trigger: 'item',
+                formatter: "{b} : {c} ({d}%)"
+            },
 
-            label: {
-                normal: {
-                    formatter: ['{c|{c}次}', '{b|{b}}'].join('\n'),
-                    rich: {
-                        c: {
-                            color: 'rgb(241,246,104)',
-                            fontSize: 20,
-                            fontWeight:'bold',
-                            lineHeight: 5
+            visualMap: {
+                show: false,
+                min: 500,
+                max: 600,
+                inRange: {
+                    //colorLightness: [0, 1]
+                }
+            },
+            series: [{
+                name: '满意度',
+                type: 'pie',
+                radius: '50%',
+                center: ['50%', '50%'],
+                color: ['rgb(131,249,103)', '#FBFE27', '#FE5050', '#1DB7E5'], //'#FBFE27','rgb(11,228,96)','#FE5050'
+                data: systemCount.sort(function(a, b) {
+                    return a.value - b.value
+                }),
+                roseType: 'radius',
+
+                label: {
+                    normal: {
+                        formatter: ['{c|{c}次}', '{b|{b}}'].join('\n'),
+                        rich: {
+                            c: {
+                                color: 'rgb(241,246,104)',
+                                fontSize: 20,
+                                fontWeight:'bold',
+                                lineHeight: 5
+                            },
+                            b: {
+                                color: 'rgb(98,137,169)',
+                                fontSize: 15,
+                                height: 40
+                            },
                         },
-                        b: {
+                    }
+                },
+                labelLine: {
+                    normal: {
+                        lineStyle: {
                             color: 'rgb(98,137,169)',
-                            fontSize: 15,
-                            height: 40
                         },
-                    },
-                }
-            },
-            labelLine: {
-                normal: {
-                    lineStyle: {
-                        color: 'rgb(98,137,169)',
-                    },
-                    smooth: 0.2,
-                    length: 10,
-                    length2: 20,
+                        smooth: 0.2,
+                        length: 10,
+                        length2: 20,
 
+                    }
+                },
+                itemStyle: {
+                    normal: {
+                        shadowColor: 'rgba(0, 0, 0, 0.8)',
+                        shadowBlur: 50,
+                    }
                 }
-            },
-            itemStyle: {
-                normal: {
-                    shadowColor: 'rgba(0, 0, 0, 0.8)',
-                    shadowBlur: 50,
-                }
-            }
-        }]
-    };
+            }]
+        };
+        pie_system.setOption(option_PS);
+    } else {
+        let pie_system_html = "<div style='margin-top: 150px;'>暂无数据</div>";
+        $("#system_data").html(pie_system_html);
+    }
 
-    // 使用刚指定的配置项和数据显示图表。
-    pie_evaluate.setOption(option_PE);
-    pie_system.setOption(option_PS);
+    function search() {
+        let daterang = $("#daterang").val();
+        let data = daterang.split(",");
+        let start = data[0];
+        let end = data[1];
+        window.location.href = '/admin/report/index?start='+start+'&end='+end;
+    }
+    $(document).ready(function () {
+
+        //当点击查询按钮的时候执行
+        $("#search").bind("click", search);
+    });
+    layui.use('laydate', function () {
+        var laydate = layui.laydate;
+        laydate.render({
+            elem: '#daterang'
+            , range: ','
+        });
+
+    });
 </script>
 </body>
 </html>

+ 14 - 55
application/common.php

@@ -9,6 +9,20 @@
 // | Author: 流年 <liu21st@gmail.com>
 // +----------------------------------------------------------------------
 
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
+use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
+use PhpOffice\PhpSpreadsheet\Reader\Xls;
+use PhpOffice\PhpSpreadsheet\IOFactory;
+use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
+use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
+use PhpOffice\PhpSpreadsheet\Cell\DataType;
+use PhpOffice\PhpSpreadsheet\Style\Fill;
+use PhpOffice\PhpSpreadsheet\Style\Color;
+use PhpOffice\PhpSpreadsheet\Style\Alignment;
+use PhpOffice\PhpSpreadsheet\Style\Border;
+use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
+
+
 // 应用公共文件
 /**
  * 删除目录以及其下的文件
@@ -105,58 +119,3 @@ function perDisplay($dit, $xiaos = 2)
     return floatPointDigit(floor(100 * $dit), $xiaos) . '%';
 }
 
-/**
- * 导出excel表格
- *
- * @param   array $columName 第一行的列名称
- * @param   array $list 二维数组
- * @param   string $setTitle sheet名称
- * @return
- * @author  Tggui <tggui@vip.qq.com>
- */
-function exportExcel($columName, $list, $setTitle = 'Sheet1', $fileName = 'demo')
-{
-    if (empty($columName) || empty($list)) {
-        return '列名或者内容不能为空';
-    }
-
-    if (count($list[0]) != count($columName)) {
-        return '列名跟数据的列不一致';
-    }
-
-    //实例化PHPExcel类
-    $PHPExcel = new PHPExcel();
-    //获得当前sheet对象
-    $PHPSheet = $PHPExcel->getActiveSheet();
-    //定义sheet名称
-    $PHPSheet->setTitle($setTitle);
-
-    //excel的列 这么多够用了吧?不够自个加 AA AB AC ……
-    $letter = [
-        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
-        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
-    ];
-    //把列名写入第1行 A1 B1 C1 ...
-    for ($i = 0; $i < count($list[0]); $i++) {
-        $PHPSheet->setCellValue("$letter[$i]1", "$columName[$i]");
-    }
-    //内容第2行开始
-    foreach ($list as $key => $val) {
-        foreach (array_values($val) as $key2 => $val2) {
-            $PHPSheet->setCellValue($letter[$key2] . ($key + 2), $val2);
-        }
-    }
-    //生成2007版本的xlsx
-    $PHPWriter = PHPExcel_IOFactory::createWriter($PHPExcel, 'Excel2007');
-    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
-    header('Content-Disposition: attachment;filename=' . $fileName . '.xlsx');
-    header('Cache-Control: max-age=0');
-    $PHPWriter->save("php://output");
-}
-
-/*
- * 使用方法
-$titlname    =    ['订单号','消费用户','订单金额','订单数量','支付状态','订单时间'];
-exportExcel($titlname,'你的二维数组数据','Sheet1','文件名称');
-*/
-

+ 1 - 1
application/service/controller/Login.php

@@ -70,4 +70,4 @@ class Login extends Controller
 
         $this->redirect(url('login/index'));
     }
-}
+}

+ 1 - 1
composer.json

@@ -19,7 +19,7 @@
     "php": ">=5.4.0",
     "topthink/framework": "~5.0.0",
     "zoujingli/ip2region": "^1.0",
-    "phpoffice/phpexcel": "1.8.2"
+    "phpoffice/phpspreadsheet": "1.8.2"
   },
   "autoload": {
     "psr-4": {

+ 69 - 72
vendor/GatewayWorker_linux/GatewayWorker/vendor/workerman/gateway-worker/src/Lib/Gateway.php

@@ -53,7 +53,7 @@ class Gateway
      * @var bool
      */
     public static $persistentConnection = true;
-    
+
     /**
      * 向所有客户端连接(或者 client_id_array 指定的客户端连接)广播消息
      *
@@ -170,7 +170,7 @@ class Gateway
     {
         return (int)self::getClientIdByUid($uid);
     }
-    
+
     /**
      * 判断某个客户端连接是否在线
      *
@@ -261,7 +261,7 @@ class Gateway
     {
         return self::getAllClientSessions($group);
     }
-    
+
     /**
      * 获取所有连接数
      *
@@ -319,10 +319,10 @@ class Gateway
         }
         return $client_list;
     }
-    
+
     /**
      * 生成验证包,用于验证此客户端的合法性
-     * 
+     *
      * @return string
      */
     protected static function generateAuthBuffer()
@@ -407,16 +407,15 @@ class Gateway
     }
 
     /**
-     * 踢掉某个客户端,并以$message通知被踢掉客户端
+     * 关闭某个客户端
      *
      * @param int $client_id
-     * @param string $message
      * @return bool
      */
-    public static function closeClient($client_id, $message = null)
+    public static function closeClient($client_id)
     {
         if ($client_id === Context::$client_id) {
-            return self::closeCurrentClient($message);
+            return self::closeCurrentClient();
         } // 不是发给当前用户则使用存储中的地址
         else {
             $address_data = Context::clientIdToAddress($client_id);
@@ -424,60 +423,22 @@ class Gateway
                 return false;
             }
             $address      = long2ip($address_data['local_ip']) . ":{$address_data['local_port']}";
-            return self::kickAddress($address, $address_data['connection_id'], $message);
+            return self::kickAddress($address, $address_data['connection_id']);
         }
     }
 
     /**
-     * 踢掉当前客户端,并以$message通知被踢掉客户端
+     * 踢掉当前客户端
      *
-     * @param string $message
      * @return bool
      * @throws Exception
      */
-    public static function closeCurrentClient($message = null)
+    public static function closeCurrentClient()
     {
         if (!Context::$connection_id) {
             throw new Exception('closeCurrentClient can not be called in async context');
         }
-        $address = long2ip(Context::$local_ip) . ':' . Context::$local_port;
-        return self::kickAddress($address, Context::$connection_id, $message);
-    }
-
-    /**
-     * 踢掉某个客户端并直接立即销毁相关连接
-     *
-     * @param int $client_id
-     * @return bool
-     */
-    public static function destoryClient($client_id)
-    {
-        if ($client_id === Context::$client_id) {
-            return self::destoryCurrentClient();
-        } // 不是发给当前用户则使用存储中的地址
-        else {
-            $address_data = Context::clientIdToAddress($client_id);
-            if (!$address_data) {
-                return false;
-            }
-            $address      = long2ip($address_data['local_ip']) . ":{$address_data['local_port']}";
-            return self::destroyAddress($address, $address_data['connection_id']);
-        }
-    }
-
-    /**
-     * 踢掉当前客户端并直接立即销毁相关连接
-     *
-     * @return bool
-     * @throws Exception
-     */
-    public static function destoryCurrentClient()
-    {
-        if (!Context::$connection_id) {
-            throw new Exception('destoryCurrentClient can not be called in async context');
-        }
-        $address = long2ip(Context::$local_ip) . ':' . Context::$local_port;
-        return self::destroyAddress($address, Context::$connection_id);
+        return self::kickAddress(long2ip(Context::$local_ip) . ':' . Context::$local_port, Context::$connection_id);
     }
 
     /**
@@ -634,7 +595,7 @@ class Gateway
         }
         return self::setSocketSession($client_id, Context::sessionEncode($session));
     }
-    
+
     /**
      * 更新 session,实际上是与老的session合并
      *
@@ -649,12 +610,12 @@ class Gateway
         }
         return self::sendCmdAndMessageToClient($client_id, GatewayProtocol::CMD_UPDATE_SESSION, '', Context::sessionEncode($session));
     }
-    
+
     /**
      * 获取某个client_id的session
      *
      * @param int   $client_id
-     * @return mixed false表示出错、null表示用户不存在、array表示具体的session信息 
+     * @return mixed false表示出错、null表示用户不存在、array表示具体的session信息
      */
     public static function getSession($client_id)
     {
@@ -675,7 +636,7 @@ class Gateway
     }
 
     /**
-     * 某个用户网关发送命令和消息
+     * 某个用户网关发送命令和消息
      *
      * @param int    $client_id
      * @param int    $cmd
@@ -830,27 +791,11 @@ class Gateway
      * @param int    $connection_id
      * @return bool
      */
-    protected static function kickAddress($address, $connection_id, $message)
+    protected static function kickAddress($address, $connection_id)
     {
         $gateway_data                  = GatewayProtocol::$empty;
         $gateway_data['cmd']           = GatewayProtocol::CMD_KICK;
         $gateway_data['connection_id'] = $connection_id;
-        $gateway_data['body'] = $message;
-        return self::sendToGateway($address, $gateway_data);
-    }
-
-    /**
-     * 销毁某个网关的 socket
-     *
-     * @param string $address
-     * @param int    $connection_id
-     * @return bool
-     */
-    protected static function destroyAddress($address, $connection_id)
-    {
-        $gateway_data                  = GatewayProtocol::$empty;
-        $gateway_data['cmd']           = GatewayProtocol::CMD_DESTROY;
-        $gateway_data['connection_id'] = $connection_id;
         return self::sendToGateway($address, $gateway_data);
     }
 
@@ -912,6 +857,58 @@ class Gateway
         }
         return $addresses_cache;
     }
+
+    /**
+     * 获得访客操作系统
+     * @return string
+     */
+    public static function get_os(){
+        if (!empty($_SESSION['userAgent'])) {
+            $os = $_SESSION['userAgent'];
+            if (preg_match('/win/i', $os)) {
+                $os = 'Windows';
+            } else if (preg_match('/mac/i', $os)) {
+                $os = 'MAC';
+            } else if (preg_match('/linux/i', $os)) {
+                $os = 'Linux';
+            } else if (preg_match('/unix/i', $os)) {
+                $os = 'Unix';
+            } else if (preg_match('/bsd/i', $os)) {
+                $os = 'BSD';
+            } else {
+                $os = 'Other';
+            }
+            return $os;
+        } else {
+            return 'unknow';
+        }
+    }
+
+    /**
+     * 获得访问者浏览器
+     * @return string
+     */
+    public static function browse_info(){
+        if (!empty($_SESSION['userAgent'])) {
+            $br = $_SESSION['userAgent'];
+            if (preg_match('/MSIE/i', $br)) {
+                $br = 'MSIE';
+            } else if (preg_match('/Firefox/i', $br)) {
+                $br = 'Firefox';
+            } else if (preg_match('/Chrome/i', $br)) {
+                $br = 'Chrome';
+            } else if (preg_match('/Safari/i', $br)) {
+                $br = 'Safari';
+            } else if (preg_match('/Opera/i', $br)) {
+                $br = 'Opera';
+            } else {
+                $br = 'Other';
+            }
+            return $br;
+        } else {
+            return 'unknow';
+        }
+    }
 }
 
 if (!class_exists('\Protocols\GatewayProtocol')) {

+ 1 - 1
vendor/GatewayWorker_windows/Applications/whisper/Events.php

@@ -711,7 +711,7 @@ class Events
         $onlinekf = self::$global->kfList;
         if (!isset($onlinekf[$group]) || count($onlinekf[$group]) <= 0) {
             Gateway::sendToClient($client_id, json_encode(['message_type' => 'notice', 'content' => '暂时没有客服上班,请稍后再咨询。'], 256));
-            sleep(2);
+            sleep(1);
             Gateway::closeClient($client_id);
             return;
         }

+ 67 - 0
vendor/composer/autoload_files.php

@@ -0,0 +1,67 @@
+<?php
+
+// autoload_files.php @generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+    'abede361264e2ae69ec1eee813a101af' => $vendorDir . '/markbaker/complex/classes/src/functions/abs.php',
+    '21a5860fbef5be28db5ddfbc3cca67c4' => $vendorDir . '/markbaker/complex/classes/src/functions/acos.php',
+    '1546e3f9d127f2a9bb2d1b6c31c26ef1' => $vendorDir . '/markbaker/complex/classes/src/functions/acosh.php',
+    'd2516f7f4fba5ea5905f494b4a8262e0' => $vendorDir . '/markbaker/complex/classes/src/functions/acot.php',
+    '4511163d560956219b96882c0980b65e' => $vendorDir . '/markbaker/complex/classes/src/functions/acoth.php',
+    'c361f5616dc2a8da4fa3e137077cd4ea' => $vendorDir . '/markbaker/complex/classes/src/functions/acsc.php',
+    '02d68920fc98da71991ce569c91df0f6' => $vendorDir . '/markbaker/complex/classes/src/functions/acsch.php',
+    '88e19525eae308b4a6aa3419364875d3' => $vendorDir . '/markbaker/complex/classes/src/functions/argument.php',
+    '60e8e2d0827b58bfc904f13957e51849' => $vendorDir . '/markbaker/complex/classes/src/functions/asec.php',
+    '13d2f040713999eab66c359b4d79871d' => $vendorDir . '/markbaker/complex/classes/src/functions/asech.php',
+    '838ab38beb32c68a79d3cd2c007d5a04' => $vendorDir . '/markbaker/complex/classes/src/functions/asin.php',
+    'bb28eccd0f8f008333a1b3c163d604ac' => $vendorDir . '/markbaker/complex/classes/src/functions/asinh.php',
+    '9e483de83558c98f7d3feaa402c78cb3' => $vendorDir . '/markbaker/complex/classes/src/functions/atan.php',
+    '36b74b5b765ded91ee58c8ee3c0e85e3' => $vendorDir . '/markbaker/complex/classes/src/functions/atanh.php',
+    '05c15ee9510da7fd6bf6136f436500c0' => $vendorDir . '/markbaker/complex/classes/src/functions/conjugate.php',
+    'd3208dfbce2505e370788f9f22f6785f' => $vendorDir . '/markbaker/complex/classes/src/functions/cos.php',
+    '141cf1fb3a3046f8b64534b0ebab33ca' => $vendorDir . '/markbaker/complex/classes/src/functions/cosh.php',
+    'be660df75fd0dbe7fa7c03b7434b3294' => $vendorDir . '/markbaker/complex/classes/src/functions/cot.php',
+    '01e31ea298a51bc9e91517e3ce6b9e76' => $vendorDir . '/markbaker/complex/classes/src/functions/coth.php',
+    '803ddd97f7b1da68982a7b087c3476f6' => $vendorDir . '/markbaker/complex/classes/src/functions/csc.php',
+    '3001cdfd101ec3c32da34ee43c2e149b' => $vendorDir . '/markbaker/complex/classes/src/functions/csch.php',
+    '77b2d7629ef2a93fabb8c56754a91051' => $vendorDir . '/markbaker/complex/classes/src/functions/exp.php',
+    '4a4471296dec796c21d4f4b6552396a9' => $vendorDir . '/markbaker/complex/classes/src/functions/inverse.php',
+    'c3e9897e1744b88deb56fcdc39d34d85' => $vendorDir . '/markbaker/complex/classes/src/functions/ln.php',
+    'a83cacf2de942cff288de15a83afd26d' => $vendorDir . '/markbaker/complex/classes/src/functions/log2.php',
+    '6a861dacc9ee2f3061241d4c7772fa21' => $vendorDir . '/markbaker/complex/classes/src/functions/log10.php',
+    '4d2522d968c8ba78d6c13548a1b4200e' => $vendorDir . '/markbaker/complex/classes/src/functions/negative.php',
+    'fd587ca933fc0447fa5ab4843bdd97f7' => $vendorDir . '/markbaker/complex/classes/src/functions/pow.php',
+    '383ef01c62028fc78cd4388082fce3c2' => $vendorDir . '/markbaker/complex/classes/src/functions/rho.php',
+    '150fbd1b95029dc47292da97ecab9375' => $vendorDir . '/markbaker/complex/classes/src/functions/sec.php',
+    '549abd9bae174286d660bdaa07407c68' => $vendorDir . '/markbaker/complex/classes/src/functions/sech.php',
+    '6bfbf5eaea6b17a0ed85cb21ba80370c' => $vendorDir . '/markbaker/complex/classes/src/functions/sin.php',
+    '22efe13f1a497b8e199540ae2d9dc59c' => $vendorDir . '/markbaker/complex/classes/src/functions/sinh.php',
+    'e90135ab8e787795a509ed7147de207d' => $vendorDir . '/markbaker/complex/classes/src/functions/sqrt.php',
+    'bb0a7923ffc6a90919cd64ec54ff06bc' => $vendorDir . '/markbaker/complex/classes/src/functions/tan.php',
+    '2d302f32ce0fd4e433dd91c5bb404a28' => $vendorDir . '/markbaker/complex/classes/src/functions/tanh.php',
+    '24dd4658a952171a4ee79218c4f9fd06' => $vendorDir . '/markbaker/complex/classes/src/functions/theta.php',
+    'e49b7876281d6f5bc39536dde96d1f4a' => $vendorDir . '/markbaker/complex/classes/src/operations/add.php',
+    '47596e02b43cd6da7700134fd08f88cf' => $vendorDir . '/markbaker/complex/classes/src/operations/subtract.php',
+    '883af48563631547925fa4c3b48ead07' => $vendorDir . '/markbaker/complex/classes/src/operations/multiply.php',
+    'f190e3308e6ca23234a2875edc985c03' => $vendorDir . '/markbaker/complex/classes/src/operations/divideby.php',
+    'ac9e33ce6841aa5bf5d16d465a2f03a7' => $vendorDir . '/markbaker/complex/classes/src/operations/divideinto.php',
+    '9d8e013a5160a09477beb8e44f8ae97b' => $vendorDir . '/markbaker/matrix/classes/src/functions/adjoint.php',
+    '6e78d1bdea6248d6aa117229efae50f2' => $vendorDir . '/markbaker/matrix/classes/src/functions/antidiagonal.php',
+    '4623d87924d94f5412fe5afbf1cef31d' => $vendorDir . '/markbaker/matrix/classes/src/functions/cofactors.php',
+    '901fd1f6950a637ca85f66b701a45e13' => $vendorDir . '/markbaker/matrix/classes/src/functions/determinant.php',
+    '83057abc0e4acc99ba80154ee5d02a49' => $vendorDir . '/markbaker/matrix/classes/src/functions/diagonal.php',
+    '07b7fd7a434451149b4fd477fca0ce06' => $vendorDir . '/markbaker/matrix/classes/src/functions/identity.php',
+    'c8d43b340583e07ae89f2a3baef2cf89' => $vendorDir . '/markbaker/matrix/classes/src/functions/inverse.php',
+    '499bb10ed7a3aee2ba4c09a31a85e8d1' => $vendorDir . '/markbaker/matrix/classes/src/functions/minors.php',
+    '1cad2e6414d652e8b1c64e8967f6f37d' => $vendorDir . '/markbaker/matrix/classes/src/functions/trace.php',
+    '95a7f134ac17161d07def442b3b737e8' => $vendorDir . '/markbaker/matrix/classes/src/functions/transpose.php',
+    'b3a6bc628377118d4b4b8ba08d1eb949' => $vendorDir . '/markbaker/matrix/classes/src/operations/add.php',
+    '5fef6d0e407f3f8887266dfa4a6c534c' => $vendorDir . '/markbaker/matrix/classes/src/operations/directsum.php',
+    '684ba247e1385946e3babdaa054119de' => $vendorDir . '/markbaker/matrix/classes/src/operations/subtract.php',
+    'aa53dcba601214d17ad405b7c291b7e8' => $vendorDir . '/markbaker/matrix/classes/src/operations/multiply.php',
+    '75c79eb1b25749b05a47976f32b0d8a2' => $vendorDir . '/markbaker/matrix/classes/src/operations/divideby.php',
+    '6ab8ad87a734f276a6bcd5a0fe1289be' => $vendorDir . '/markbaker/matrix/classes/src/operations/divideinto.php',
+);

+ 4 - 0
vendor/composer/autoload_psr4.php

@@ -9,4 +9,8 @@ return array(
     'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
     'think\\' => array($baseDir . '/thinkphp/library/think'),
     'app\\' => array($baseDir . '/application'),
+    'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
+    'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'),
+    'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'),
+    'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
 );

+ 18 - 0
vendor/composer/autoload_real.php

@@ -47,6 +47,24 @@ class ComposerAutoloaderInit0e5a20f54bf215fd957bc14489129d05
 
         $loader->register(true);
 
+        if ($useStaticLoader) {
+            $includeFiles = Composer\Autoload\ComposerStaticInit0e5a20f54bf215fd957bc14489129d05::$files;
+        } else {
+            $includeFiles = require __DIR__ . '/autoload_files.php';
+        }
+        foreach ($includeFiles as $fileIdentifier => $file) {
+            composerRequire0e5a20f54bf215fd957bc14489129d05($fileIdentifier, $file);
+        }
+
         return $loader;
     }
 }
+
+function composerRequire0e5a20f54bf215fd957bc14489129d05($fileIdentifier, $file)
+{
+    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
+        require $file;
+
+        $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
+    }
+}

+ 90 - 0
vendor/composer/autoload_static.php

@@ -6,6 +6,67 @@ namespace Composer\Autoload;
 
 class ComposerStaticInit0e5a20f54bf215fd957bc14489129d05
 {
+    public static $files = array (
+        'abede361264e2ae69ec1eee813a101af' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/abs.php',
+        '21a5860fbef5be28db5ddfbc3cca67c4' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acos.php',
+        '1546e3f9d127f2a9bb2d1b6c31c26ef1' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acosh.php',
+        'd2516f7f4fba5ea5905f494b4a8262e0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acot.php',
+        '4511163d560956219b96882c0980b65e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acoth.php',
+        'c361f5616dc2a8da4fa3e137077cd4ea' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsc.php',
+        '02d68920fc98da71991ce569c91df0f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/acsch.php',
+        '88e19525eae308b4a6aa3419364875d3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/argument.php',
+        '60e8e2d0827b58bfc904f13957e51849' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asec.php',
+        '13d2f040713999eab66c359b4d79871d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asech.php',
+        '838ab38beb32c68a79d3cd2c007d5a04' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asin.php',
+        'bb28eccd0f8f008333a1b3c163d604ac' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/asinh.php',
+        '9e483de83558c98f7d3feaa402c78cb3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atan.php',
+        '36b74b5b765ded91ee58c8ee3c0e85e3' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/atanh.php',
+        '05c15ee9510da7fd6bf6136f436500c0' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/conjugate.php',
+        'd3208dfbce2505e370788f9f22f6785f' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cos.php',
+        '141cf1fb3a3046f8b64534b0ebab33ca' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cosh.php',
+        'be660df75fd0dbe7fa7c03b7434b3294' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/cot.php',
+        '01e31ea298a51bc9e91517e3ce6b9e76' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/coth.php',
+        '803ddd97f7b1da68982a7b087c3476f6' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csc.php',
+        '3001cdfd101ec3c32da34ee43c2e149b' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/csch.php',
+        '77b2d7629ef2a93fabb8c56754a91051' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/exp.php',
+        '4a4471296dec796c21d4f4b6552396a9' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/inverse.php',
+        'c3e9897e1744b88deb56fcdc39d34d85' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/ln.php',
+        'a83cacf2de942cff288de15a83afd26d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log2.php',
+        '6a861dacc9ee2f3061241d4c7772fa21' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/log10.php',
+        '4d2522d968c8ba78d6c13548a1b4200e' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/negative.php',
+        'fd587ca933fc0447fa5ab4843bdd97f7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/pow.php',
+        '383ef01c62028fc78cd4388082fce3c2' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/rho.php',
+        '150fbd1b95029dc47292da97ecab9375' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sec.php',
+        '549abd9bae174286d660bdaa07407c68' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sech.php',
+        '6bfbf5eaea6b17a0ed85cb21ba80370c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sin.php',
+        '22efe13f1a497b8e199540ae2d9dc59c' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sinh.php',
+        'e90135ab8e787795a509ed7147de207d' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/sqrt.php',
+        'bb0a7923ffc6a90919cd64ec54ff06bc' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tan.php',
+        '2d302f32ce0fd4e433dd91c5bb404a28' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/tanh.php',
+        '24dd4658a952171a4ee79218c4f9fd06' => __DIR__ . '/..' . '/markbaker/complex/classes/src/functions/theta.php',
+        'e49b7876281d6f5bc39536dde96d1f4a' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/add.php',
+        '47596e02b43cd6da7700134fd08f88cf' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/subtract.php',
+        '883af48563631547925fa4c3b48ead07' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/multiply.php',
+        'f190e3308e6ca23234a2875edc985c03' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideby.php',
+        'ac9e33ce6841aa5bf5d16d465a2f03a7' => __DIR__ . '/..' . '/markbaker/complex/classes/src/operations/divideinto.php',
+        '9d8e013a5160a09477beb8e44f8ae97b' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/adjoint.php',
+        '6e78d1bdea6248d6aa117229efae50f2' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/antidiagonal.php',
+        '4623d87924d94f5412fe5afbf1cef31d' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/cofactors.php',
+        '901fd1f6950a637ca85f66b701a45e13' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/determinant.php',
+        '83057abc0e4acc99ba80154ee5d02a49' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/diagonal.php',
+        '07b7fd7a434451149b4fd477fca0ce06' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/identity.php',
+        'c8d43b340583e07ae89f2a3baef2cf89' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/inverse.php',
+        '499bb10ed7a3aee2ba4c09a31a85e8d1' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/minors.php',
+        '1cad2e6414d652e8b1c64e8967f6f37d' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/trace.php',
+        '95a7f134ac17161d07def442b3b737e8' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/functions/transpose.php',
+        'b3a6bc628377118d4b4b8ba08d1eb949' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/operations/add.php',
+        '5fef6d0e407f3f8887266dfa4a6c534c' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/operations/directsum.php',
+        '684ba247e1385946e3babdaa054119de' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/operations/subtract.php',
+        'aa53dcba601214d17ad405b7c291b7e8' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/operations/multiply.php',
+        '75c79eb1b25749b05a47976f32b0d8a2' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/operations/divideby.php',
+        '6ab8ad87a734f276a6bcd5a0fe1289be' => __DIR__ . '/..' . '/markbaker/matrix/classes/src/operations/divideinto.php',
+    );
+
     public static $prefixLengthsPsr4 = array (
         't' => 
         array (
@@ -16,6 +77,19 @@ class ComposerStaticInit0e5a20f54bf215fd957bc14489129d05
         array (
             'app\\' => 4,
         ),
+        'P' => 
+        array (
+            'Psr\\SimpleCache\\' => 16,
+            'PhpOffice\\PhpSpreadsheet\\' => 25,
+        ),
+        'M' => 
+        array (
+            'Matrix\\' => 7,
+        ),
+        'C' => 
+        array (
+            'Complex\\' => 8,
+        ),
     );
 
     public static $prefixDirsPsr4 = array (
@@ -31,6 +105,22 @@ class ComposerStaticInit0e5a20f54bf215fd957bc14489129d05
         array (
             0 => __DIR__ . '/../..' . '/application',
         ),
+        'Psr\\SimpleCache\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/simple-cache/src',
+        ),
+        'PhpOffice\\PhpSpreadsheet\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet',
+        ),
+        'Matrix\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src',
+        ),
+        'Complex\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
+        ),
     );
 
     public static $classMap = array (

+ 315 - 0
vendor/composer/installed.json

@@ -1,4 +1,319 @@
 [
+    {
+        "name": "markbaker/complex",
+        "version": "1.4.7",
+        "version_normalized": "1.4.7.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/MarkBaker/PHPComplex.git",
+            "reference": "1ea674a8308baf547cbcbd30c5fcd6d301b7c000"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/1ea674a8308baf547cbcbd30c5fcd6d301b7c000",
+            "reference": "1ea674a8308baf547cbcbd30c5fcd6d301b7c000",
+            "shasum": ""
+        },
+        "require": {
+            "php": "^5.6.0|^7.0.0"
+        },
+        "require-dev": {
+            "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
+            "phpcompatibility/php-compatibility": "^8.0",
+            "phpdocumentor/phpdocumentor": "2.*",
+            "phploc/phploc": "2.*",
+            "phpmd/phpmd": "2.*",
+            "phpunit/phpunit": "^4.8.35|^5.4.0",
+            "sebastian/phpcpd": "2.*",
+            "squizlabs/php_codesniffer": "^3.3.0"
+        },
+        "time": "2018-10-13T23:28:42+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Complex\\": "classes/src/"
+            },
+            "files": [
+                "classes/src/functions/abs.php",
+                "classes/src/functions/acos.php",
+                "classes/src/functions/acosh.php",
+                "classes/src/functions/acot.php",
+                "classes/src/functions/acoth.php",
+                "classes/src/functions/acsc.php",
+                "classes/src/functions/acsch.php",
+                "classes/src/functions/argument.php",
+                "classes/src/functions/asec.php",
+                "classes/src/functions/asech.php",
+                "classes/src/functions/asin.php",
+                "classes/src/functions/asinh.php",
+                "classes/src/functions/atan.php",
+                "classes/src/functions/atanh.php",
+                "classes/src/functions/conjugate.php",
+                "classes/src/functions/cos.php",
+                "classes/src/functions/cosh.php",
+                "classes/src/functions/cot.php",
+                "classes/src/functions/coth.php",
+                "classes/src/functions/csc.php",
+                "classes/src/functions/csch.php",
+                "classes/src/functions/exp.php",
+                "classes/src/functions/inverse.php",
+                "classes/src/functions/ln.php",
+                "classes/src/functions/log2.php",
+                "classes/src/functions/log10.php",
+                "classes/src/functions/negative.php",
+                "classes/src/functions/pow.php",
+                "classes/src/functions/rho.php",
+                "classes/src/functions/sec.php",
+                "classes/src/functions/sech.php",
+                "classes/src/functions/sin.php",
+                "classes/src/functions/sinh.php",
+                "classes/src/functions/sqrt.php",
+                "classes/src/functions/tan.php",
+                "classes/src/functions/tanh.php",
+                "classes/src/functions/theta.php",
+                "classes/src/operations/add.php",
+                "classes/src/operations/subtract.php",
+                "classes/src/operations/multiply.php",
+                "classes/src/operations/divideby.php",
+                "classes/src/operations/divideinto.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Mark Baker",
+                "email": "mark@lange.demon.co.uk"
+            }
+        ],
+        "description": "PHP Class for working with complex numbers",
+        "homepage": "https://github.com/MarkBaker/PHPComplex",
+        "keywords": [
+            "complex",
+            "mathematics"
+        ]
+    },
+    {
+        "name": "markbaker/matrix",
+        "version": "1.1.4",
+        "version_normalized": "1.1.4.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/MarkBaker/PHPMatrix.git",
+            "reference": "6ea97472b5baf12119b4f31f802835b820dd6d64"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/6ea97472b5baf12119b4f31f802835b820dd6d64",
+            "reference": "6ea97472b5baf12119b4f31f802835b820dd6d64",
+            "shasum": ""
+        },
+        "require": {
+            "php": "^5.6.0|^7.0.0"
+        },
+        "require-dev": {
+            "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
+            "phpcompatibility/php-compatibility": "^8.0",
+            "phpdocumentor/phpdocumentor": "2.*",
+            "phploc/phploc": "2.*",
+            "phpmd/phpmd": "2.*",
+            "phpunit/phpunit": "^4.8.35|^5.4.0",
+            "sebastian/phpcpd": "2.*",
+            "squizlabs/php_codesniffer": "^3.3.0"
+        },
+        "time": "2018-11-04T22:12:12+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Matrix\\": "classes/src/"
+            },
+            "files": [
+                "classes/src/functions/adjoint.php",
+                "classes/src/functions/antidiagonal.php",
+                "classes/src/functions/cofactors.php",
+                "classes/src/functions/determinant.php",
+                "classes/src/functions/diagonal.php",
+                "classes/src/functions/identity.php",
+                "classes/src/functions/inverse.php",
+                "classes/src/functions/minors.php",
+                "classes/src/functions/trace.php",
+                "classes/src/functions/transpose.php",
+                "classes/src/operations/add.php",
+                "classes/src/operations/directsum.php",
+                "classes/src/operations/subtract.php",
+                "classes/src/operations/multiply.php",
+                "classes/src/operations/divideby.php",
+                "classes/src/operations/divideinto.php"
+            ]
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Mark Baker",
+                "email": "mark@lange.demon.co.uk"
+            }
+        ],
+        "description": "PHP Class for working with matrices",
+        "homepage": "https://github.com/MarkBaker/PHPMatrix",
+        "keywords": [
+            "mathematics",
+            "matrix",
+            "vector"
+        ]
+    },
+    {
+        "name": "phpoffice/phpspreadsheet",
+        "version": "1.8.2",
+        "version_normalized": "1.8.2.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
+            "reference": "0c1346a1956347590b7db09533966307d20cb7cc"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/0c1346a1956347590b7db09533966307d20cb7cc",
+            "reference": "0c1346a1956347590b7db09533966307d20cb7cc",
+            "shasum": ""
+        },
+        "require": {
+            "ext-ctype": "*",
+            "ext-dom": "*",
+            "ext-fileinfo": "*",
+            "ext-gd": "*",
+            "ext-iconv": "*",
+            "ext-libxml": "*",
+            "ext-mbstring": "*",
+            "ext-simplexml": "*",
+            "ext-xml": "*",
+            "ext-xmlreader": "*",
+            "ext-xmlwriter": "*",
+            "ext-zip": "*",
+            "ext-zlib": "*",
+            "markbaker/complex": "^1.4",
+            "markbaker/matrix": "^1.1",
+            "php": "^5.6|^7.0",
+            "psr/simple-cache": "^1.0"
+        },
+        "require-dev": {
+            "doctrine/instantiator": "^1.0.0",
+            "dompdf/dompdf": "^0.8.0",
+            "friendsofphp/php-cs-fixer": "@stable",
+            "jpgraph/jpgraph": "^4.0",
+            "mpdf/mpdf": "^7.0.0",
+            "phpcompatibility/php-compatibility": "^8.0",
+            "phpunit/phpunit": "^5.7",
+            "squizlabs/php_codesniffer": "^3.3",
+            "tecnickcom/tcpdf": "^6.2"
+        },
+        "suggest": {
+            "dompdf/dompdf": "Option for rendering PDF with PDF Writer",
+            "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
+            "mpdf/mpdf": "Option for rendering PDF with PDF Writer",
+            "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer"
+        },
+        "time": "2019-07-08T21:21:25+00:00",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "LGPL-2.1-or-later"
+        ],
+        "authors": [
+            {
+                "name": "Erik Tilt"
+            },
+            {
+                "name": "Adrien Crivelli"
+            },
+            {
+                "name": "Maarten Balliauw",
+                "homepage": "https://blog.maartenballiauw.be"
+            },
+            {
+                "name": "Mark Baker",
+                "homepage": "https://markbakeruk.net"
+            },
+            {
+                "name": "Franck Lefevre",
+                "homepage": "https://rootslabs.net"
+            }
+        ],
+        "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
+        "homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
+        "keywords": [
+            "OpenXML",
+            "excel",
+            "gnumeric",
+            "ods",
+            "php",
+            "spreadsheet",
+            "xls",
+            "xlsx"
+        ]
+    },
+    {
+        "name": "psr/simple-cache",
+        "version": "1.0.1",
+        "version_normalized": "1.0.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/php-fig/simple-cache.git",
+            "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+            "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.0"
+        },
+        "time": "2017-10-23T01:57:42+00:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "1.0.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-4": {
+                "Psr\\SimpleCache\\": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "PHP-FIG",
+                "homepage": "http://www.php-fig.org/"
+            }
+        ],
+        "description": "Common interfaces for simple caching",
+        "keywords": [
+            "cache",
+            "caching",
+            "psr",
+            "psr-16",
+            "simple-cache"
+        ]
+    },
     {
         "name": "topthink/framework",
         "version": "v5.0.24",

+ 156 - 0
vendor/markbaker/complex/README.md

@@ -0,0 +1,156 @@
+PHPComplex
+==========
+
+---
+
+PHP Class for handling Complex numbers
+
+Master: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=master)](http://travis-ci.org/MarkBaker/PHPComplex)
+
+Develop: [![Build Status](https://travis-ci.org/MarkBaker/PHPComplex.png?branch=develop)](http://travis-ci.org/MarkBaker/PHPComplex)
+
+[![Complex Numbers](https://imgs.xkcd.com/comics/complex_numbers_2x.png)](https://xkcd.com/2028/)
+
+---
+
+The library currently provides the following operations:
+
+ - addition
+ - subtraction
+ - multiplication
+ - division
+    - division by
+    - division into
+
+together with functions for 
+
+ - theta (polar theta angle)
+ - rho (polar distance/radius)
+ - conjugate
+ * negative
+ - inverse (1 / complex)
+ - cos (cosine)
+ - acos (inverse cosine)
+ - cosh (hyperbolic cosine)
+ - acosh (inverse hyperbolic cosine)
+ - sin (sine)
+ - asin (inverse sine)
+ - sinh (hyperbolic sine)
+ - asinh (inverse hyperbolic sine)
+ - sec (secant)
+ - asec (inverse secant)
+ - sech (hyperbolic secant)
+ - asech (inverse hyperbolic secant)
+ - csc (cosecant)
+ - acsc (inverse cosecant)
+ - csch (hyperbolic secant)
+ - acsch (inverse hyperbolic secant)
+ - tan (tangent)
+ - atan (inverse tangent)
+ - tanh (hyperbolic tangent)
+ - atanh (inverse hyperbolic tangent)
+ - cot (cotangent)
+ - acot (inverse cotangent)
+ - coth (hyperbolic cotangent)
+ - acoth (inverse hyperbolic cotangent)
+ - sqrt (square root)
+ - exp (exponential)
+ - ln (natural log)
+ - log10 (base-10 log)
+ - log2 (base-2 log)
+ - pow (raised to the power of a real number)
+ 
+ 
+---
+
+# Usage
+
+To create a new complex object, you can provide either the real, imaginary and suffix parts as individual values, or as an array of values passed passed to the constructor; or a string representing the value. e.g
+
+```
+$real = 1.23;
+$imaginary = -4.56;
+$suffix = 'i';
+
+$complexObject = new Complex\Complex($real, $imaginary, $suffix);
+```
+or
+```
+$real = 1.23;
+$imaginary = -4.56;
+$suffix = 'i';
+
+$arguments = [$real, $imaginary, $suffix];
+
+$complexObject = new Complex\Complex($arguments);
+```
+or
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+```
+
+Complex objects are immutable: whenever you call a method or pass a complex value to a function that returns a complex value, a new Complex object will be returned, and the original will remain unchanged.
+This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Complex result).
+
+## Performing Mathematical Operations
+
+To perform mathematical operations with Complex values, you can call the appropriate method against a complex value, passing other values as arguments
+
+```
+$complexString1 = '1.23-4.56i';
+$complexString2 = '2.34+5.67i';
+
+$complexObject = new Complex\Complex($complexString1);
+echo $complexObject->add($complexString2);
+```
+or pass all values to the appropriate function
+```
+$complexString1 = '1.23-4.56i';
+$complexString2 = '2.34+5.67i';
+
+echo Complex\add($complexString1, $complexString2);
+```
+If you want to perform the same operation against multiple values (e.g. to add three or more complex numbers), then you can pass multiple arguments to any of the operations.
+
+You can pass these arguments as Complex objects, or as an array or string that will parse to a complex object.
+
+## Using functions
+
+When calling any of the available functions for a complex value, you can either call the relevant method for the Complex object
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo $complexObject->sinh();
+```
+or you can call the function as you would in procedural code, passing the Complex object as an argument 
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo Complex\sinh($complexObject);
+```
+When called procedurally using the function, you can pass in the argument as a Complex object, or as an array or string that will parse to a complex object.
+```
+$complexString = '1.23-4.56i';
+
+echo Complex\sinh($complexString);
+```
+
+In the case of the `pow()` function (the only implemented function that requires an additional argument) you need to pass both arguments when calling the function procedurally
+
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo Complex\pow($complexObject, 2);
+```
+or pass the additional argument when calling the method
+```
+$complexString = '1.23-4.56i';
+
+$complexObject = new Complex\Complex($complexString);
+echo $complexObject->pow(2);
+```

+ 53 - 0
vendor/markbaker/complex/classes/Autoloader.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace Complex;
+
+/**
+ *
+ * Autoloader for Complex classes
+ *
+ * @package Complex
+ * @copyright  Copyright (c) 2014 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
+ */
+class Autoloader
+{
+    /**
+     * Register the Autoloader with SPL
+     *
+     */
+    public static function Register()
+    {
+        if (function_exists('__autoload')) {
+            //    Register any existing autoloader function with SPL, so we don't get any clashes
+            spl_autoload_register('__autoload');
+        }
+        //    Register ourselves with SPL
+        return spl_autoload_register(['Complex\\Autoloader', 'Load']);
+    }
+
+
+    /**
+     * Autoload a class identified by name
+     *
+     * @param    string    $pClassName    Name of the object to load
+     */
+    public static function Load($pClassName)
+    {
+        if ((class_exists($pClassName, false)) || (strpos($pClassName, 'Complex\\') !== 0)) {
+            // Either already loaded, or not a Complex class request
+            return false;
+        }
+
+        $pClassFilePath = __DIR__ . DIRECTORY_SEPARATOR .
+                          'src' . DIRECTORY_SEPARATOR .
+                          str_replace(['Complex\\', '\\'], ['', '/'], $pClassName) .
+                          '.php';
+
+        if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
+            // Can't load
+            return false;
+        }
+        require($pClassFilePath);
+    }
+}

+ 38 - 0
vendor/markbaker/complex/classes/Bootstrap.php

@@ -0,0 +1,38 @@
+<?php
+
+include_once __DIR__ . '/Autoloader.php';
+
+\Complex\Autoloader::Register();
+
+
+abstract class FilesystemRegexFilter extends RecursiveRegexIterator
+{
+    protected $regex;
+    public function __construct(RecursiveIterator $it, $regex)
+    {
+        $this->regex = $regex;
+        parent::__construct($it, $regex);
+    }
+}
+
+class FilenameFilter extends FilesystemRegexFilter
+{
+    // Filter files against the regex
+    public function accept()
+    {
+        return (!$this->isFile() || preg_match($this->regex, $this->getFilename()));
+    }
+}
+
+
+$srcFolder = __DIR__ . DIRECTORY_SEPARATOR . 'src';
+$srcDirectory = new RecursiveDirectoryIterator($srcFolder);
+
+$filteredFileList = new FilenameFilter($srcDirectory, '/(?:php)$/i');
+$filteredFileList = new FilenameFilter($filteredFileList, '/^(?!.*(Complex|Exception)\.php).*$/i');
+
+foreach (new RecursiveIteratorIterator($filteredFileList) as $file) {
+    if ($file->isFile()) {
+        include_once $file;
+    }
+}

+ 387 - 0
vendor/markbaker/complex/classes/src/Complex.php

@@ -0,0 +1,387 @@
+<?php
+
+/**
+ *
+ * Class for the management of Complex numbers
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Complex Number object.
+ *
+ * @package Complex
+ *
+ * @method float abs()
+ * @method Complex acos()
+ * @method Complex acosh()
+ * @method Complex acot()
+ * @method Complex acoth()
+ * @method Complex acsc()
+ * @method Complex acsch()
+ * @method float argument()
+ * @method Complex asec()
+ * @method Complex asech()
+ * @method Complex asin()
+ * @method Complex asinh()
+ * @method Complex atan()
+ * @method Complex atanh()
+ * @method Complex conjugate()
+ * @method Complex cos()
+ * @method Complex cosh()
+ * @method Complex cot()
+ * @method Complex coth()
+ * @method Complex csc()
+ * @method Complex csch()
+ * @method Complex exp()
+ * @method Complex inverse()
+ * @method Complex ln()
+ * @method Complex log2()
+ * @method Complex log10()
+ * @method Complex negative()
+ * @method Complex pow(int|float $power)
+ * @method float rho()
+ * @method Complex sec()
+ * @method Complex sech()
+ * @method Complex sin()
+ * @method Complex sinh()
+ * @method Complex sqrt()
+ * @method Complex tan()
+ * @method Complex tanh()
+ * @method float theta()
+ * @method Complex add(...$complexValues)
+ * @method Complex subtract(...$complexValues)
+ * @method Complex multiply(...$complexValues)
+ * @method Complex divideby(...$complexValues)
+ * @method Complex divideinto(...$complexValues)
+ */
+class Complex
+{
+    /**
+     * @constant    Euler's Number.
+     */
+    const EULER = 2.7182818284590452353602874713526624977572;
+
+    /**
+     * @constant    Regexp to split an input string into real and imaginary components and suffix
+     */
+    const NUMBER_SPLIT_REGEXP =
+        '` ^
+            (                                   # Real part
+                [-+]?(\d+\.?\d*|\d*\.?\d+)          # Real value (integer or float)
+                ([Ee][-+]?[0-2]?\d{1,3})?           # Optional real exponent for scientific format
+            )
+            (                                   # Imaginary part
+                [-+]?(\d+\.?\d*|\d*\.?\d+)          # Imaginary value (integer or float)
+                ([Ee][-+]?[0-2]?\d{1,3})?           # Optional imaginary exponent for scientific format
+            )?
+            (                                   # Imaginary part is optional
+                ([-+]?)                             # Imaginary (implicit 1 or -1) only
+                ([ij]?)                             # Imaginary i or j - depending on whether mathematical or engineering
+            )
+        $`uix';
+
+    /**
+     * @var    float    $realPart    The value of of this complex number on the real plane.
+     */
+    protected $realPart = 0.0;
+
+    /**
+     * @var    float    $imaginaryPart    The value of of this complex number on the imaginary plane.
+     */
+    protected $imaginaryPart = 0.0;
+
+    /**
+     * @var    string    $suffix    The suffix for this complex number (i or j).
+     */
+    protected $suffix;
+
+
+    /**
+     * Validates whether the argument is a valid complex number, converting scalar or array values if possible
+     *
+     * @param     mixed    $complexNumber   The value to parse
+     * @return    array
+     * @throws    Exception    If the argument isn't a Complex number or cannot be converted to one
+     */
+    private static function parseComplex($complexNumber)
+    {
+        // Test for real number, with no imaginary part
+        if (is_numeric($complexNumber)) {
+            return [$complexNumber, 0, null];
+        }
+
+        // Fix silly human errors
+        $complexNumber = str_replace(
+            ['+-', '-+', '++', '--'],
+            ['-', '-', '+', '+'],
+            $complexNumber
+        );
+
+        // Basic validation of string, to parse out real and imaginary parts, and any suffix
+        $validComplex = preg_match(
+            self::NUMBER_SPLIT_REGEXP,
+            $complexNumber,
+            $complexParts
+        );
+
+        if (!$validComplex) {
+            // Neither real nor imaginary part, so test to see if we actually have a suffix
+            $validComplex = preg_match('/^([\-\+]?)([ij])$/ui', $complexNumber, $complexParts);
+            if (!$validComplex) {
+                throw new Exception('Invalid complex number');
+            }
+            // We have a suffix, so set the real to 0, the imaginary to either 1 or -1 (as defined by the sign)
+            $imaginary = 1;
+            if ($complexParts[1] === '-') {
+                $imaginary = 0 - $imaginary;
+            }
+            return [0, $imaginary, $complexParts[2]];
+        }
+
+        // If we don't have an imaginary part, identify whether it should be +1 or -1...
+        if (($complexParts[4] === '') && ($complexParts[9] !== '')) {
+            if ($complexParts[7] !== $complexParts[9]) {
+                $complexParts[4] = 1;
+                if ($complexParts[8] === '-') {
+                    $complexParts[4] = -1;
+                }
+            } else {
+                // ... or if we have only the real and no imaginary part
+                //  (in which case our real should be the imaginary)
+                $complexParts[4] = $complexParts[1];
+                $complexParts[1] = 0;
+            }
+        }
+
+        // Return real and imaginary parts and suffix as an array, and set a default suffix if user input lazily
+        return [
+            $complexParts[1],
+            $complexParts[4],
+            !empty($complexParts[9]) ? $complexParts[9] : 'i'
+        ];
+    }
+
+
+    public function __construct($realPart = 0.0, $imaginaryPart = null, $suffix = 'i')
+    {
+        if ($imaginaryPart === null) {
+            if (is_array($realPart)) {
+                // We have an array of (potentially) real and imaginary parts, and any suffix
+                list ($realPart, $imaginaryPart, $suffix) = array_values($realPart) + [0.0, 0.0, 'i'];
+            } elseif ((is_string($realPart)) || (is_numeric($realPart))) {
+                // We've been given a string to parse to extract the real and imaginary parts, and any suffix
+                list($realPart, $imaginaryPart, $suffix) = self::parseComplex($realPart);
+            }
+        }
+        if ($imaginaryPart <> 0.0 && empty($suffix)) {
+            $suffix = 'i';
+        }
+
+        // Set parsed values in our properties
+        $this->realPart = (float) $realPart;
+        $this->imaginaryPart = (float) $imaginaryPart;
+        $this->suffix = strtolower($suffix);
+    }
+
+    /**
+     * Gets the real part of this complex number
+     *
+     * @return Float
+     */
+    public function getReal()
+    {
+        return $this->realPart;
+    }
+
+    /**
+     * Gets the imaginary part of this complex number
+     *
+     * @return Float
+     */
+    public function getImaginary()
+    {
+        return $this->imaginaryPart;
+    }
+
+    /**
+     * Gets the suffix of this complex number
+     *
+     * @return String
+     */
+    public function getSuffix()
+    {
+        return $this->suffix;
+    }
+
+    /**
+     * Returns true if this is a real value, false if a complex value
+     *
+     * @return Bool
+     */
+    public function isReal()
+    {
+        return $this->imaginaryPart == 0.0;
+    }
+
+    /**
+     * Returns true if this is a complex value, false if a real value
+     *
+     * @return Bool
+     */
+    public function isComplex()
+    {
+        return !$this->isReal();
+    }
+
+    public function format()
+    {
+        $str = "";
+        if ($this->imaginaryPart != 0.0) {
+            if (\abs($this->imaginaryPart) != 1.0) {
+                $str .= $this->imaginaryPart . $this->suffix;
+            } else {
+                $str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix;
+            }
+        }
+        if ($this->realPart != 0.0) {
+            if (($str) && ($this->imaginaryPart > 0.0)) {
+                $str = "+" . $str;
+            }
+            $str = $this->realPart . $str;
+        }
+        if (!$str) {
+            $str = "0.0";
+        }
+
+        return $str;
+    }
+
+    public function __toString()
+    {
+        return $this->format();
+    }
+
+    /**
+     * Validates whether the argument is a valid complex number, converting scalar or array values if possible
+     *
+     * @param     mixed    $complex   The value to validate
+     * @return    Complex
+     * @throws    Exception    If the argument isn't a Complex number or cannot be converted to one
+     */
+    public static function validateComplexArgument($complex)
+    {
+        if (is_scalar($complex) || is_array($complex)) {
+            $complex = new Complex($complex);
+        } elseif (!is_object($complex) || !($complex instanceof Complex)) {
+            throw new Exception('Value is not a valid complex number');
+        }
+
+        return $complex;
+    }
+
+    /**
+     * Returns the reverse of this complex number
+     *
+     * @return    Complex
+     */
+    public function reverse()
+    {
+        return new Complex(
+            $this->imaginaryPart,
+            $this->realPart,
+            ($this->realPart == 0.0) ? null : $this->suffix
+        );
+    }
+
+    public function invertImaginary()
+    {
+        return new Complex(
+            $this->realPart,
+            $this->imaginaryPart * -1,
+            ($this->imaginaryPart == 0.0) ? null : $this->suffix
+        );
+    }
+
+    public function invertReal()
+    {
+        return new Complex(
+            $this->realPart * -1,
+            $this->imaginaryPart,
+            ($this->imaginaryPart == 0.0) ? null : $this->suffix
+        );
+    }
+
+    protected static $functions = [
+        'abs',
+        'acos',
+        'acosh',
+        'acot',
+        'acoth',
+        'acsc',
+        'acsch',
+        'argument',
+        'asec',
+        'asech',
+        'asin',
+        'asinh',
+        'atan',
+        'atanh',
+        'conjugate',
+        'cos',
+        'cosh',
+        'cot',
+        'coth',
+        'csc',
+        'csch',
+        'exp',
+        'inverse',
+        'ln',
+        'log2',
+        'log10',
+        'negative',
+        'pow',
+        'rho',
+        'sec',
+        'sech',
+        'sin',
+        'sinh',
+        'sqrt',
+        'tan',
+        'tanh',
+        'theta',
+    ];
+
+    protected static $operations = [
+        'add',
+        'subtract',
+        'multiply',
+        'divideby',
+        'divideinto',
+    ];
+
+    /**
+     * Returns the result of the function call or operation
+     *
+     * @return    Complex|float
+     * @throws    Exception|\InvalidArgumentException
+     */
+    public function __call($functionName, $arguments)
+    {
+        $functionName = strtolower(str_replace('_', '', $functionName));
+
+        // Test for function calls
+        if (in_array($functionName, self::$functions)) {
+            $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
+            return $functionName($this, ...$arguments);
+        }
+        // Test for operation calls
+        if (in_array($functionName, self::$operations)) {
+            $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
+            return $functionName($this, ...$arguments);
+        }
+        throw new Exception('Function or Operation does not exist');
+    }
+}

+ 13 - 0
vendor/markbaker/complex/classes/src/Exception.php

@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * Exception.
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+class Exception extends \Exception
+{
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/abs.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex abs() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the absolute value (modulus) of a complex number.
+ * Also known as the rho of the complex number, i.e. the distance/radius
+ *   from the centrepoint to the representation of the number in polar coordinates.
+ *
+ * This function is a synonym for rho()
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    float            The absolute (or rho) value of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ *
+ * @see    rho
+ *
+ */
+function abs($complex)
+{
+    return rho($complex);
+}

+ 38 - 0
vendor/markbaker/complex/classes/src/functions/acos.php

@@ -0,0 +1,38 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acos() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse cosine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse cosine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function acos($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    $square = clone $complex;
+    $square = multiply($square, $complex);
+    $invsqrt = new Complex(1.0);
+    $invsqrt = subtract($invsqrt, $square);
+    $invsqrt = sqrt($invsqrt);
+    $adjust = new Complex(
+        $complex->getReal() - $invsqrt->getImaginary(),
+        $complex->getImaginary() + $invsqrt->getReal()
+    );
+    $log = ln($adjust);
+
+    return new Complex(
+        $log->getImaginary(),
+        -1 * $log->getReal()
+    );
+}

+ 34 - 0
vendor/markbaker/complex/classes/src/functions/acosh.php

@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acosh() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic cosine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse hyperbolic cosine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function acosh($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal() && ($complex->getReal() > 1)) {
+        return new Complex(\acosh($complex->getReal()));
+    }
+
+    $acosh = acos($complex)
+        ->reverse();
+    if ($acosh->getReal() < 0.0) {
+        $acosh = $acosh->invertReal();
+    }
+
+    return $acosh;
+}

+ 25 - 0
vendor/markbaker/complex/classes/src/functions/acot.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acot() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse cotangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse cotangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function acot($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    return atan(inverse($complex));
+}

+ 25 - 0
vendor/markbaker/complex/classes/src/functions/acoth.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acoth() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic cotangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse hyperbolic cotangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function acoth($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    return atanh(inverse($complex));
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/acsc.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acsc() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse cosecant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse cosecant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function acsc($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        return INF;
+    }
+
+    return asin(inverse($complex));
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/acsch.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex acsch() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic cosecant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse hyperbolic cosecant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function acsch($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        return INF;
+    }
+
+    return asinh(inverse($complex));
+}

+ 28 - 0
vendor/markbaker/complex/classes/src/functions/argument.php

@@ -0,0 +1,28 @@
+<?php
+
+/**
+ *
+ * Function code for the complex argument() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the argument of a complex number.
+ * Also known as the theta of the complex number, i.e. the angle in radians
+ *   from the real axis to the representation of the number in polar coordinates.
+ *
+ * This function is a synonym for theta()
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    float            The argument (or theta) value of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ *
+ * @see    theta
+ */
+function argument($complex)
+{
+    return theta($complex);
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/asec.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asec() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse secant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse secant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function asec($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        return INF;
+    }
+
+    return acos(inverse($complex));
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/asech.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asech() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic secant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse hyperbolic secant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function asech($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        return INF;
+    }
+
+    return acosh(inverse($complex));
+}

+ 37 - 0
vendor/markbaker/complex/classes/src/functions/asin.php

@@ -0,0 +1,37 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asin() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse sine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse sine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function asin($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    $square = multiply($complex, $complex);
+    $invsqrt = new Complex(1.0);
+    $invsqrt = subtract($invsqrt, $square);
+    $invsqrt = sqrt($invsqrt);
+    $adjust = new Complex(
+        $invsqrt->getReal() - $complex->getImaginary(),
+        $invsqrt->getImaginary() + $complex->getReal()
+    );
+    $log = ln($adjust);
+
+    return new Complex(
+        $log->getImaginary(),
+        -1 * $log->getReal()
+    );
+}

+ 33 - 0
vendor/markbaker/complex/classes/src/functions/asinh.php

@@ -0,0 +1,33 @@
+<?php
+
+/**
+ *
+ * Function code for the complex asinh() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic sine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse hyperbolic sine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function asinh($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal() && ($complex->getReal() > 1)) {
+        return new Complex(\asinh($complex->getReal()));
+    }
+
+    $asinh = clone $complex;
+    $asinh = $asinh->reverse()
+        ->invertReal();
+    $asinh = asin($asinh);
+    return $asinh->reverse()
+        ->invertImaginary();
+}

+ 45 - 0
vendor/markbaker/complex/classes/src/functions/atan.php

@@ -0,0 +1,45 @@
+<?php
+
+/**
+ *
+ * Function code for the complex atan() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+//include_once 'Math/Complex.php';
+//include_once 'Math/ComplexOp.php';
+
+/**
+ * Returns the inverse tangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse tangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function atan($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal()) {
+        return new Complex(\atan($complex->getReal()));
+    }
+
+    $t1Value = new Complex(-1 * $complex->getImaginary(), $complex->getReal());
+    $uValue = new Complex(1, 0);
+
+    $d1Value = clone $uValue;
+    $d1Value = subtract($d1Value, $t1Value);
+    $d2Value = add($t1Value, $uValue);
+    $uResult = $d1Value->divideBy($d2Value);
+    $uResult = ln($uResult);
+
+    return new Complex(
+        (($uResult->getImaginary() == M_PI) ? -M_PI : $uResult->getImaginary()) * -0.5,
+        $uResult->getReal() * 0.5,
+        $complex->getSuffix()
+    );
+}

+ 38 - 0
vendor/markbaker/complex/classes/src/functions/atanh.php

@@ -0,0 +1,38 @@
+<?php
+
+/**
+ *
+ * Function code for the complex atanh() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse hyperbolic tangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse hyperbolic tangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function atanh($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal()) {
+        $real = $complex->getReal();
+        if ($real >= -1.0 && $real <= 1.0) {
+            return new Complex(\atanh($real));
+        } else {
+            return new Complex(\atanh(1 / $real), (($real < 0.0) ? M_PI_2 : -1 * M_PI_2));
+        }
+    }
+
+    $iComplex = clone $complex;
+    $iComplex = $iComplex->invertImaginary()
+        ->reverse();
+    return atan($iComplex)
+        ->invertReal()
+        ->reverse();
+}

+ 28 - 0
vendor/markbaker/complex/classes/src/functions/conjugate.php

@@ -0,0 +1,28 @@
+<?php
+
+/**
+ *
+ * Function code for the complex conjugate() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the complex conjugate of a complex number
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The conjugate of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function conjugate($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    return new Complex(
+        $complex->getReal(),
+        -1 * $complex->getImaginary(),
+        $complex->getSuffix()
+    );
+}

+ 34 - 0
vendor/markbaker/complex/classes/src/functions/cos.php

@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex cos() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the cosine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The cosine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function cos($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal()) {
+        return new Complex(\cos($complex->getReal()));
+    }
+
+    return conjugate(
+        new Complex(
+            \cos($complex->getReal()) * \cosh($complex->getImaginary()),
+            \sin($complex->getReal()) * \sinh($complex->getImaginary()),
+            $complex->getSuffix()
+        )
+    );
+}

+ 32 - 0
vendor/markbaker/complex/classes/src/functions/cosh.php

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the complex cosh() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic cosine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The hyperbolic cosine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function cosh($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal()) {
+        return new Complex(\cosh($complex->getReal()));
+    }
+
+    return new Complex(
+        \cosh($complex->getReal()) * \cos($complex->getImaginary()),
+        \sinh($complex->getReal()) * \sin($complex->getImaginary()),
+        $complex->getSuffix()
+    );
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/cot.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex cot() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the cotangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The cotangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function cot($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        return new Complex(INF);
+    }
+
+    return inverse(tan($complex));
+}

+ 24 - 0
vendor/markbaker/complex/classes/src/functions/coth.php

@@ -0,0 +1,24 @@
+<?php
+
+/**
+ *
+ * Function code for the complex coth() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic cotangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The hyperbolic cotangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function coth($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+    return inverse(tanh($complex));
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/csc.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex csc() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the cosecant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The cosecant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function csc($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        return INF;
+    }
+
+    return inverse(sin($complex));
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/csch.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex csch() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic cosecant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The hyperbolic cosecant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function csch($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        return INF;
+    }
+
+    return inverse(sinh($complex));
+}

+ 34 - 0
vendor/markbaker/complex/classes/src/functions/exp.php

@@ -0,0 +1,34 @@
+<?php
+
+/**
+ *
+ * Function code for the complex exp() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the exponential of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The exponential of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function exp($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if (($complex->getReal() == 0.0) && (\abs($complex->getImaginary()) == M_PI)) {
+        return new Complex(-1.0, 0.0);
+    }
+
+    $rho = \exp($complex->getReal());
+ 
+    return new Complex(
+        $rho * \cos($complex->getImaginary()),
+        $rho * \sin($complex->getImaginary()),
+        $complex->getSuffix()
+    );
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/inverse.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex inverse() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the inverse of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The inverse of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function inverse($complex)
+{
+    $complex = clone Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+        throw new \InvalidArgumentException('Division by zero');
+    }
+
+    return $complex->divideInto(1.0);
+}

+ 33 - 0
vendor/markbaker/complex/classes/src/functions/ln.php

@@ -0,0 +1,33 @@
+<?php
+
+/**
+ *
+ * Function code for the complex ln() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the natural logarithm of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The natural logarithm of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException  If the real and the imaginary parts are both zero
+ */
+function ln($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
+        throw new \InvalidArgumentException();
+    }
+
+    return new Complex(
+        \log(rho($complex)),
+        theta($complex),
+        $complex->getSuffix()
+    );
+}

+ 32 - 0
vendor/markbaker/complex/classes/src/functions/log10.php

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the complex log10() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the common logarithm (base 10) of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The common logarithm (base 10) of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException  If the real and the imaginary parts are both zero
+ */
+function log10($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
+        throw new \InvalidArgumentException();
+    } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
+        return new Complex(\log10($complex->getReal()), 0.0, $complex->getSuffix());
+    }
+
+    return ln($complex)
+        ->multiply(\log10(Complex::EULER));
+}

+ 32 - 0
vendor/markbaker/complex/classes/src/functions/log2.php

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the complex log2() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the base-2 logarithm of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The base-2 logarithm of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException  If the real and the imaginary parts are both zero
+ */
+function log2($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
+        throw new \InvalidArgumentException();
+    } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
+        return new Complex(\log($complex->getReal(), 2), 0.0, $complex->getSuffix());
+    }
+
+    return ln($complex)
+        ->multiply(\log(Complex::EULER, 2));
+}

+ 31 - 0
vendor/markbaker/complex/classes/src/functions/negative.php

@@ -0,0 +1,31 @@
+<?php
+
+/**
+ *
+ * Function code for the complex negative() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the negative of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    float            The negative value of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ *
+ * @see    rho
+ *
+ */
+function negative($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    return new Complex(
+        -1 * $complex->getReal(),
+        -1 * $complex->getImaginary(),
+        $complex->getSuffix()
+    );
+}

+ 40 - 0
vendor/markbaker/complex/classes/src/functions/pow.php

@@ -0,0 +1,40 @@
+<?php
+
+/**
+ *
+ * Function code for the complex pow() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns a complex number raised to a power.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @param     float|integer    $power      The power to raise this value to
+ * @return    Complex          The complex argument raised to the real power.
+ * @throws    Exception        If the power argument isn't a valid real
+ */
+function pow($complex, $power)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if (!is_numeric($power)) {
+        throw new Exception('Power argument must be a real number');
+    }
+
+    if ($complex->getImaginary() == 0.0 && $complex->getReal() >= 0.0) {
+        return new Complex(\pow($complex->getReal(), $power));
+    }
+
+    $rValue = \sqrt(($complex->getReal() * $complex->getReal()) + ($complex->getImaginary() * $complex->getImaginary()));
+    $rPower = \pow($rValue, $power);
+    $theta = $complex->argument() * $power;
+    if ($theta == 0) {
+        return new Complex(1);
+    }
+
+    return new Complex($rPower * \cos($theta), $rPower * \sin($theta), $complex->getSuffix());
+}

+ 28 - 0
vendor/markbaker/complex/classes/src/functions/rho.php

@@ -0,0 +1,28 @@
+<?php
+
+/**
+ *
+ * Function code for the complex rho() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the rho of a complex number.
+ * This is the distance/radius from the centrepoint to the representation of the number in polar coordinates.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    float            The rho value of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function rho($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    return \sqrt(
+        ($complex->getReal() * $complex->getReal()) +
+        ($complex->getImaginary() * $complex->getImaginary())
+    );
+}

+ 25 - 0
vendor/markbaker/complex/classes/src/functions/sec.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sec() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the secant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The secant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function sec($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    return inverse(cos($complex));
+}

+ 25 - 0
vendor/markbaker/complex/classes/src/functions/sech.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sech() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic secant of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The hyperbolic secant of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function sech($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    return inverse(cosh($complex));
+}

+ 32 - 0
vendor/markbaker/complex/classes/src/functions/sin.php

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sin() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the sine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The sine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function sin($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal()) {
+        return new Complex(\sin($complex->getReal()));
+    }
+
+    return new Complex(
+        \sin($complex->getReal()) * \cosh($complex->getImaginary()),
+        \cos($complex->getReal()) * \sinh($complex->getImaginary()),
+        $complex->getSuffix()
+    );
+}

+ 32 - 0
vendor/markbaker/complex/classes/src/functions/sinh.php

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sinh() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic sine of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The hyperbolic sine of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function sinh($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal()) {
+        return new Complex(\sinh($complex->getReal()));
+    }
+
+    return new Complex(
+        \sinh($complex->getReal()) * \cos($complex->getImaginary()),
+        \cosh($complex->getReal()) * \sin($complex->getImaginary()),
+        $complex->getSuffix()
+    );
+}

+ 29 - 0
vendor/markbaker/complex/classes/src/functions/sqrt.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ *
+ * Function code for the complex sqrt() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the square root of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The Square root of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function sqrt($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    $theta = theta($complex);
+    $delta1 = \cos($theta / 2);
+    $delta2 = \sin($theta / 2);
+    $rho = \sqrt(rho($complex));
+
+    return new Complex($delta1 * $rho, $delta2 * $rho, $complex->getSuffix());
+}

+ 40 - 0
vendor/markbaker/complex/classes/src/functions/tan.php

@@ -0,0 +1,40 @@
+<?php
+
+/**
+ *
+ * Function code for the complex tan() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the tangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The tangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function tan($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->isReal()) {
+        return new Complex(\tan($complex->getReal()));
+    }
+
+    $real = $complex->getReal();
+    $imaginary = $complex->getImaginary();
+    $divisor = 1 + \pow(\tan($real), 2) * \pow(\tanh($imaginary), 2);
+    if ($divisor == 0.0) {
+        throw new \InvalidArgumentException('Division by zero');
+    }
+
+    return new Complex(
+        \pow(sech($imaginary)->getReal(), 2) * \tan($real) / $divisor,
+        \pow(sec($real)->getReal(), 2) * \tanh($imaginary) / $divisor,
+        $complex->getSuffix()
+    );
+}

+ 35 - 0
vendor/markbaker/complex/classes/src/functions/tanh.php

@@ -0,0 +1,35 @@
+<?php
+
+/**
+ *
+ * Function code for the complex tanh() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the hyperbolic tangent of a complex number.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    Complex          The hyperbolic tangent of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ * @throws    \InvalidArgumentException    If function would result in a division by zero
+ */
+function tanh($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+    $real = $complex->getReal();
+    $imaginary = $complex->getImaginary();
+    $divisor = \cos($imaginary) * \cos($imaginary) + \sinh($real) * \sinh($real);
+    if ($divisor == 0.0) {
+        throw new \InvalidArgumentException('Division by zero');
+    }
+
+    return new Complex(
+        \sinh($real) * \cosh($real) / $divisor,
+        0.5 * \sin(2 * $imaginary) / $divisor,
+        $complex->getSuffix()
+    );
+}

+ 38 - 0
vendor/markbaker/complex/classes/src/functions/theta.php

@@ -0,0 +1,38 @@
+<?php
+
+/**
+ *
+ * Function code for the complex theta() function
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Returns the theta of a complex number.
+ *   This is the angle in radians from the real axis to the representation of the number in polar coordinates.
+ *
+ * @param     Complex|mixed    $complex    Complex number or a numeric value.
+ * @return    float            The theta value of the complex argument.
+ * @throws    Exception        If argument isn't a valid real or complex number.
+ */
+function theta($complex)
+{
+    $complex = Complex::validateComplexArgument($complex);
+
+    if ($complex->getReal() == 0.0) {
+        if ($complex->isReal()) {
+            return 0.0;
+        } elseif ($complex->getImaginary() < 0.0) {
+            return M_PI / -2;
+        }
+        return M_PI / 2;
+    } elseif ($complex->getReal() > 0.0) {
+        return \atan($complex->getImaginary() / $complex->getReal());
+    } elseif ($complex->getImaginary() < 0.0) {
+        return -(M_PI - \atan(\abs($complex->getImaginary()) / \abs($complex->getReal())));
+    }
+
+    return M_PI - \atan($complex->getImaginary() / \abs($complex->getReal()));
+}

+ 46 - 0
vendor/markbaker/complex/classes/src/operations/add.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ *
+ * Function code for the complex addition operation
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Adds two or more complex numbers
+ *
+ * @param     array of string|integer|float|Complex    $complexValues   The numbers to add
+ * @return    Complex
+ */
+function add(...$complexValues)
+{
+    if (count($complexValues) < 2) {
+        throw new \Exception('This function requires at least 2 arguments');
+    }
+
+    $base = array_shift($complexValues);
+    $result = clone Complex::validateComplexArgument($base);
+
+    foreach ($complexValues as $complex) {
+        $complex = Complex::validateComplexArgument($complex);
+
+        if ($result->isComplex() && $complex->isComplex() &&
+            $result->getSuffix() !== $complex->getSuffix()) {
+            throw new Exception('Suffix Mismatch');
+        }
+
+        $real = $result->getReal() + $complex->getReal();
+        $imaginary = $result->getImaginary() + $complex->getImaginary();
+
+        $result = new Complex(
+            $real,
+            $imaginary,
+            ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+        );
+    }
+
+    return $result;
+}

+ 56 - 0
vendor/markbaker/complex/classes/src/operations/divideby.php

@@ -0,0 +1,56 @@
+<?php
+
+/**
+ *
+ * Function code for the complex division operation
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Divides two or more complex numbers
+ *
+ * @param     array of string|integer|float|Complex    $complexValues   The numbers to divide
+ * @return    Complex
+ */
+function divideby(...$complexValues)
+{
+    if (count($complexValues) < 2) {
+        throw new \Exception('This function requires at least 2 arguments');
+    }
+
+    $base = array_shift($complexValues);
+    $result = clone Complex::validateComplexArgument($base);
+
+    foreach ($complexValues as $complex) {
+        $complex = Complex::validateComplexArgument($complex);
+
+        if ($result->isComplex() && $complex->isComplex() &&
+            $result->getSuffix() !== $complex->getSuffix()) {
+            throw new Exception('Suffix Mismatch');
+        }
+        if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
+            throw new \InvalidArgumentException('Division by zero');
+        }
+
+        $delta1 = ($result->getReal() * $complex->getReal()) +
+            ($result->getImaginary() * $complex->getImaginary());
+        $delta2 = ($result->getImaginary() * $complex->getReal()) -
+            ($result->getReal() * $complex->getImaginary());
+        $delta3 = ($complex->getReal() * $complex->getReal()) +
+            ($complex->getImaginary() * $complex->getImaginary());
+
+        $real = $delta1 / $delta3;
+        $imaginary = $delta2 / $delta3;
+
+        $result = new Complex(
+            $real,
+            $imaginary,
+            ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+        );
+    }
+
+    return $result;
+}

+ 56 - 0
vendor/markbaker/complex/classes/src/operations/divideinto.php

@@ -0,0 +1,56 @@
+<?php
+
+/**
+ *
+ * Function code for the complex division operation
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Divides two or more complex numbers
+ *
+ * @param     array of string|integer|float|Complex    $complexValues   The numbers to divide
+ * @return    Complex
+ */
+function divideinto(...$complexValues)
+{
+    if (count($complexValues) < 2) {
+        throw new \Exception('This function requires at least 2 arguments');
+    }
+
+    $base = array_shift($complexValues);
+    $result = clone Complex::validateComplexArgument($base);
+
+    foreach ($complexValues as $complex) {
+        $complex = Complex::validateComplexArgument($complex);
+
+        if ($result->isComplex() && $complex->isComplex() &&
+            $result->getSuffix() !== $complex->getSuffix()) {
+            throw new Exception('Suffix Mismatch');
+        }
+        if ($result->getReal() == 0.0 && $result->getImaginary() == 0.0) {
+            throw new \InvalidArgumentException('Division by zero');
+        }
+
+        $delta1 = ($complex->getReal() * $result->getReal()) +
+            ($complex->getImaginary() * $result->getImaginary());
+        $delta2 = ($complex->getImaginary() * $result->getReal()) -
+            ($complex->getReal() * $result->getImaginary());
+        $delta3 = ($result->getReal() * $result->getReal()) +
+            ($result->getImaginary() * $result->getImaginary());
+
+        $real = $delta1 / $delta3;
+        $imaginary = $delta2 / $delta3;
+
+        $result = new Complex(
+            $real,
+            $imaginary,
+            ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+        );
+    }
+
+    return $result;
+}

+ 48 - 0
vendor/markbaker/complex/classes/src/operations/multiply.php

@@ -0,0 +1,48 @@
+<?php
+
+/**
+ *
+ * Function code for the complex multiplication operation
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Multiplies two or more complex numbers
+ *
+ * @param     array of string|integer|float|Complex    $complexValues   The numbers to multiply
+ * @return    Complex
+ */
+function multiply(...$complexValues)
+{
+    if (count($complexValues) < 2) {
+        throw new \Exception('This function requires at least 2 arguments');
+    }
+
+    $base = array_shift($complexValues);
+    $result = clone Complex::validateComplexArgument($base);
+
+    foreach ($complexValues as $complex) {
+        $complex = Complex::validateComplexArgument($complex);
+
+        if ($result->isComplex() && $complex->isComplex() &&
+            $result->getSuffix() !== $complex->getSuffix()) {
+            throw new Exception('Suffix Mismatch');
+        }
+
+        $real = ($result->getReal() * $complex->getReal()) -
+            ($result->getImaginary() * $complex->getImaginary());
+        $imaginary = ($result->getReal() * $complex->getImaginary()) +
+            ($result->getImaginary() * $complex->getReal());
+
+        $result = new Complex(
+            $real,
+            $imaginary,
+            ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+        );
+    }
+
+    return $result;
+}

+ 46 - 0
vendor/markbaker/complex/classes/src/operations/subtract.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ *
+ * Function code for the complex subtraction operation
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Complex;
+
+/**
+ * Subtracts two or more complex numbers
+ *
+ * @param     array of string|integer|float|Complex    $complexValues   The numbers to subtract
+ * @return    Complex
+ */
+function subtract(...$complexValues)
+{
+    if (count($complexValues) < 2) {
+        throw new \Exception('This function requires at least 2 arguments');
+    }
+
+    $base = array_shift($complexValues);
+    $result = clone Complex::validateComplexArgument($base);
+
+    foreach ($complexValues as $complex) {
+        $complex = Complex::validateComplexArgument($complex);
+
+        if ($result->isComplex() && $complex->isComplex() &&
+            $result->getSuffix() !== $complex->getSuffix()) {
+            throw new Exception('Suffix Mismatch');
+        }
+
+        $real = $result->getReal() - $complex->getReal();
+        $imaginary = $result->getImaginary() - $complex->getImaginary();
+
+        $result = new Complex(
+            $real,
+            $imaginary,
+            ($imaginary == 0.0) ? null : max($result->getSuffix(), $complex->getSuffix())
+        );
+    }
+
+    return $result;
+}

+ 91 - 0
vendor/markbaker/complex/composer.json

@@ -0,0 +1,91 @@
+{
+    "name": "markbaker/complex",
+    "type": "library",
+    "description": "PHP Class for working with complex numbers",
+    "keywords": ["complex", "mathematics"],
+    "homepage": "https://github.com/MarkBaker/PHPComplex",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Mark Baker",
+            "email": "mark@lange.demon.co.uk"
+        }
+    ],
+    "require": {
+        "php": "^5.6.0|^7.0.0"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "^4.8.35|^5.4.0",
+        "phpdocumentor/phpdocumentor":"2.*",
+        "phpmd/phpmd": "2.*",
+        "sebastian/phpcpd": "2.*",
+        "phploc/phploc": "2.*",
+        "squizlabs/php_codesniffer": "^3.3.0",
+        "phpcompatibility/php-compatibility": "^8.0",
+        "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3"
+    },
+    "autoload": {
+        "psr-4": {
+            "Complex\\": "classes/src/"
+        },
+        "files": [
+            "classes/src/functions/abs.php",
+            "classes/src/functions/acos.php",
+            "classes/src/functions/acosh.php",
+            "classes/src/functions/acot.php",
+            "classes/src/functions/acoth.php",
+            "classes/src/functions/acsc.php",
+            "classes/src/functions/acsch.php",
+            "classes/src/functions/argument.php",
+            "classes/src/functions/asec.php",
+            "classes/src/functions/asech.php",
+            "classes/src/functions/asin.php",
+            "classes/src/functions/asinh.php",
+            "classes/src/functions/atan.php",
+            "classes/src/functions/atanh.php",
+            "classes/src/functions/conjugate.php",
+            "classes/src/functions/cos.php",
+            "classes/src/functions/cosh.php",
+            "classes/src/functions/cot.php",
+            "classes/src/functions/coth.php",
+            "classes/src/functions/csc.php",
+            "classes/src/functions/csch.php",
+            "classes/src/functions/exp.php",
+            "classes/src/functions/inverse.php",
+            "classes/src/functions/ln.php",
+            "classes/src/functions/log2.php",
+            "classes/src/functions/log10.php",
+            "classes/src/functions/negative.php",
+            "classes/src/functions/pow.php",
+            "classes/src/functions/rho.php",
+            "classes/src/functions/sec.php",
+            "classes/src/functions/sech.php",
+            "classes/src/functions/sin.php",
+            "classes/src/functions/sinh.php",
+            "classes/src/functions/sqrt.php",
+            "classes/src/functions/tan.php",
+            "classes/src/functions/tanh.php",
+            "classes/src/functions/theta.php",
+            "classes/src/operations/add.php",
+            "classes/src/operations/subtract.php",
+            "classes/src/operations/multiply.php",
+            "classes/src/operations/divideby.php",
+            "classes/src/operations/divideinto.php"
+        ]
+    },
+    "scripts": {
+        "style": [
+            "phpcs --report-width=200 --report-summary  --report-full classes/src/ --standard=PSR2 -n"
+        ],
+        "mess": [
+            "phpmd classes/src/ xml codesize,unusedcode,design,naming -n"
+        ],
+        "lines": [
+            "phploc classes/src/ -n"
+        ],
+        "cpd": [
+            "phpcpd classes/src/ -n"
+        ]
+    },
+    "minimum-stability": "dev"
+}

+ 154 - 0
vendor/markbaker/complex/examples/complexTest.php

@@ -0,0 +1,154 @@
+<?php
+
+use Complex\Complex as Complex;
+
+include('../classes/Bootstrap.php');
+
+echo 'Create', PHP_EOL;
+
+$x = new Complex(123);
+echo $x, PHP_EOL;
+
+$x = new Complex(123, 456);
+echo $x, PHP_EOL;
+
+$x = new Complex(array(123,456,'j'));
+echo $x, PHP_EOL;
+
+$x = new Complex('1.23e-4--2.34e-5i');
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Add', PHP_EOL;
+
+$x = new Complex(123);
+$x->add(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->add(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->add(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->add(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->add(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->add(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Subtract', PHP_EOL;
+
+$x = new Complex(123);
+$x->subtract(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->subtract(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->subtract(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->subtract(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->subtract(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->subtract(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Multiply', PHP_EOL;
+
+$x = new Complex(123);
+$x->multiply(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->multiply(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->multiply(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->multiply(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->multiply(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->multiply(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Divide By', PHP_EOL;
+
+$x = new Complex(123);
+$x->divideBy(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->divideBy(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideBy(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideBy(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideBy(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideBy(new Complex(0, -1));
+echo $x, PHP_EOL;
+
+
+echo PHP_EOL, 'Divide Into', PHP_EOL;
+
+$x = new Complex(123);
+$x->divideInto(456);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456);
+$x->divideInto(789.012);
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideInto(new Complex(-987.654, -32.1));
+echo $x, PHP_EOL;
+
+$x = new Complex(123.456, 78.90);
+$x->divideInto(-987.654);
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideInto(new Complex(0, 1));
+echo $x, PHP_EOL;
+
+$x = new Complex(-987.654, -32.1);
+$x->divideInto(new Complex(0, -1));
+echo $x, PHP_EOL;

+ 52 - 0
vendor/markbaker/complex/examples/testFunctions.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace Complex;
+
+include('../classes/Bootstrap.php');
+
+echo 'Function Examples', PHP_EOL;
+
+$functions = array(
+    'abs',
+    'acos',
+    'acosh',
+    'acsc',
+    'acsch',
+    'argument',
+    'asec',
+    'asech',
+    'asin',
+    'asinh',
+    'conjugate',
+    'cos',
+    'cosh',
+    'csc',
+    'csch',
+    'exp',
+    'inverse',
+    'ln',
+    'log2',
+    'log10',
+    'rho',
+    'sec',
+    'sech',
+    'sin',
+    'sinh',
+    'sqrt',
+    'theta'
+);
+
+for ($real = -3.5; $real <= 3.5; $real += 0.5) {
+    for ($imaginary = -3.5; $imaginary <= 3.5; $imaginary += 0.5) {
+        foreach ($functions as $function) {
+            $complexFunction = __NAMESPACE__ . '\\' . $function;
+            $complex = new Complex($real, $imaginary);
+            try {
+                echo $function, '(', $complex, ') = ', $complexFunction($complex), PHP_EOL;
+            } catch (\Exception $e) {
+                echo $function, '(', $complex, ') ERROR: ', $e->getMessage(), PHP_EOL;
+            }
+        }
+        echo PHP_EOL;
+    }
+}

+ 34 - 0
vendor/markbaker/complex/examples/testOperations.php

@@ -0,0 +1,34 @@
+<?php
+
+use Complex\Complex as Complex;
+
+include('../classes/Bootstrap.php');
+
+$values = [
+    new Complex(123),
+    new Complex(456, 123),
+    new Complex(0.0, 456),
+];
+
+foreach ($values as $value) {
+    echo $value, PHP_EOL;
+}
+
+echo 'Addition', PHP_EOL;
+
+$result = \Complex\add(...$values);
+echo '=> ', $result, PHP_EOL;
+
+echo PHP_EOL;
+
+echo 'Subtraction', PHP_EOL;
+
+$result = \Complex\subtract(...$values);
+echo '=> ', $result, PHP_EOL;
+
+echo PHP_EOL;
+
+echo 'Multiplication', PHP_EOL;
+
+$result = \Complex\multiply(...$values);
+echo '=> ', $result, PHP_EOL;

+ 25 - 0
vendor/markbaker/complex/license.md

@@ -0,0 +1,25 @@
+The MIT License (MIT)
+=====================
+
+Copyright © `2017` `Mark Baker`
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the “Software”), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.

+ 165 - 0
vendor/markbaker/matrix/README.md

@@ -0,0 +1,165 @@
+PHPMatrix
+==========
+
+---
+
+PHP Class for handling Matrices
+
+Master: [![Build Status](https://travis-ci.org/MarkBaker/PHPMatrix.png?branch=master)](http://travis-ci.org/MarkBaker/PHPMatrix)
+
+Develop: [![Build Status](https://travis-ci.org/MarkBaker/PHPMatrix.png?branch=develop)](http://travis-ci.org/MarkBaker/PHPMatrix)
+
+[![Matrix Transform](https://imgs.xkcd.com/comics/matrix_transform.png)](https://xkcd.com/184/)
+
+Matrix Transform
+
+---
+
+This library currently provides the following operations:
+
+ - addition
+ - direct sum
+ - subtraction
+ - multiplication
+ - division (using [A].[B]<sup>-1</sup>)
+    - division by
+    - division into
+
+together with functions for 
+
+ - adjoint
+ - antidiagonal
+ - cofactors
+ - determinant
+ - diagonal
+ - identity
+ - inverse
+ - minors
+ - trace
+ - transpose
+
+
+## TO DO
+
+ - power()
+ - EigenValues
+ - EigenVectors
+ - Decomposition
+
+---
+
+# Usage
+
+To create a new Matrix object, provide an array as the constructor argument
+
+```
+$grid = [
+    [16,  3,  2, 13],
+    [ 5, 10, 11,  8],
+    [ 9,  6,  7, 12],
+    [ 4, 15, 14,  1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+```
+The `Builder` class provides helper methods for creating specific matrices, specifically an identity matrix of a specified size; or a matrix of a specified dimensions, with every cell containing a set value.
+```
+$matrix = new Matrix\Builder::createFilledMatrix(1, 5, 3);
+```
+Will create a matrix of 5 rows and 3 columns, filled with a `1` in every cell; while
+```
+$matrix = new Matrix\Builder::createIdentityMatrix(3);
+```
+will create a 3x3 identity matrix.
+
+
+Matrix objects are immutable: whenever you call a method or pass a grid to a function that returns a matrix value, a new Matrix object will be returned, and the original will remain unchanged. This also allows you to chain multiple methods as you would for a fluent interface (as long as they are methods that will return a Matrix result).
+
+## Performing Mathematical Operations
+
+To perform mathematical operations with Matrices, you can call the appropriate method against a matrix value, passing other values as arguments
+
+```
+$matrix1 = new Matrix([
+    [2, 7, 6],
+    [9, 5, 1],
+    [4, 3, 8],
+]);
+$matrix2 = new Matrix([
+    [1, 2, 3],
+    [4, 5, 6],
+    [7, 8, 9],
+]);
+
+echo $matrix1->multiply($matrix2);
+```
+or pass all values to the appropriate function
+```
+$matrix1 = new Matrix([
+    [2, 7, 6],
+    [9, 5, 1],
+    [4, 3, 8],
+]);
+$matrix2 = new Matrix([
+    [1, 2, 3],
+    [4, 5, 6],
+    [7, 8, 9],
+]);
+
+echo Matrix\multiply($matrix1, $matrix2);
+```
+You can pass in the arguments as Matrix objects, or as arrays.
+
+If you want to perform the same operation against multiple values (e.g. to add three or more matrices), then you can pass multiple arguments to any of the operations.
+
+## Using functions
+
+When calling any of the available functions for a matrix value, you can either call the relevant method for the Matrix object
+```
+$grid = [
+    [16,  3,  2, 13],
+    [ 5, 10, 11,  8],
+    [ 9,  6,  7, 12],
+    [ 4, 15, 14,  1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+
+echo $matrix->trace();
+```
+or you can call the function as you would in procedural code, passing the Matrix object as an argument 
+```
+$grid = [
+    [16,  3,  2, 13],
+    [ 5, 10, 11,  8],
+    [ 9,  6,  7, 12],
+    [ 4, 15, 14,  1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+echo Matrix\trace($matrix);
+```
+When called procedurally using the function, you can pass in the argument as a Matrix object, or as an array.
+```
+$grid = [
+    [16,  3,  2, 13],
+    [ 5, 10, 11,  8],
+    [ 9,  6,  7, 12],
+    [ 4, 15, 14,  1],
+];
+
+echo Matrix\trace($grid);
+```
+As an alternative, it is also possible to call the method directly from the `Functions` class.
+```
+$grid = [
+    [16,  3,  2, 13],
+    [ 5, 10, 11,  8],
+    [ 9,  6,  7, 12],
+    [ 4, 15, 14,  1],
+];
+
+$matrix = new Matrix\Matrix($grid);
+echo Matrix\Functions::trace($matrix);
+```
+Used this way, methods must be called statically, and the argument must be the Matrix object, and cannot be an array.

+ 62 - 0
vendor/markbaker/matrix/buildPhar.php

@@ -0,0 +1,62 @@
+<?php
+
+# required: PHP 5.3+ and zlib extension
+
+// ini option check
+if (ini_get('phar.readonly')) {
+    echo "php.ini: set the 'phar.readonly' option to 0 to enable phar creation\n";
+    exit(1);
+}
+
+// output name
+$pharName = 'Matrix.phar';
+
+// target folder
+$sourceDir = __DIR__ . DIRECTORY_SEPARATOR . 'classes' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR;
+
+// default meta information
+$metaData = array(
+    'Author'      => 'Mark Baker <mark@lange.demon.co.uk>',
+    'Description' => 'PHP Class for working with Matrix numbers',
+    'Copyright'   => 'Mark Baker (c) 2013-' . date('Y'),
+    'Timestamp'   => time(),
+    'Version'     => '0.1.0',
+    'Date'        => date('Y-m-d')
+);
+
+// cleanup
+if (file_exists($pharName)) {
+    echo "Removed: {$pharName}\n";
+    unlink($pharName);
+}
+
+echo "Building phar file...\n";
+
+// the phar object
+$phar = new Phar($pharName, null, 'Matrix');
+$phar->buildFromDirectory($sourceDir);
+$phar->setStub(
+<<<'EOT'
+<?php
+    spl_autoload_register(function ($className) {
+        include 'phar://' . $className . '.php';
+    });
+
+    try {
+        Phar::mapPhar();
+    } catch (PharException $e) {
+        error_log($e->getMessage());
+        exit(1);
+    }
+
+    include 'phar://functions/sqrt.php';
+
+    __HALT_COMPILER();
+EOT
+);
+$phar->setMetadata($metaData);
+$phar->compressFiles(Phar::GZ);
+
+echo "Complete.\n";
+
+exit();

+ 53 - 0
vendor/markbaker/matrix/classes/Autoloader.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace Matrix;
+
+/**
+ *
+ * Autoloader for Matrix classes
+ *
+ * @package Matrix
+ * @copyright  Copyright (c) 2014 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT          MIT
+ */
+class Autoloader
+{
+    /**
+     * Register the Autoloader with SPL
+     *
+     */
+    public static function Register()
+    {
+        if (function_exists('__autoload')) {
+            //    Register any existing autoloader function with SPL, so we don't get any clashes
+            spl_autoload_register('__autoload');
+        }
+        //    Register ourselves with SPL
+        return spl_autoload_register(['Matrix\\Autoloader', 'Load']);
+    }
+
+
+    /**
+     * Autoload a class identified by name
+     *
+     * @param    string    $pClassName    Name of the object to load
+     */
+    public static function Load($pClassName)
+    {
+        if ((class_exists($pClassName, false)) || (strpos($pClassName, 'Matrix\\') !== 0)) {
+            // Either already loaded, or not a Matrix class request
+            return false;
+        }
+
+        $pClassFilePath = __DIR__ . DIRECTORY_SEPARATOR .
+                          'src' . DIRECTORY_SEPARATOR .
+                          str_replace(['Matrix\\', '\\'], ['', '/'], $pClassName) .
+                          '.php';
+
+        if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) {
+            // Can't load
+            return false;
+        }
+        require($pClassFilePath);
+    }
+}

+ 38 - 0
vendor/markbaker/matrix/classes/Bootstrap.php

@@ -0,0 +1,38 @@
+<?php
+
+include_once __DIR__ . '/Autoloader.php';
+
+\Matrix\Autoloader::Register();
+
+
+abstract class FilesystemRegexFilter extends RecursiveRegexIterator
+{
+    protected $regex;
+    public function __construct(RecursiveIterator $it, $regex)
+    {
+        $this->regex = $regex;
+        parent::__construct($it, $regex);
+    }
+}
+
+class FilenameFilter extends FilesystemRegexFilter
+{
+    // Filter files against the regex
+    public function accept()
+    {
+        return (!$this->isFile() || preg_match($this->regex, $this->getFilename()));
+    }
+}
+
+
+$srcFolder = __DIR__ . DIRECTORY_SEPARATOR . 'src';
+$srcDirectory = new RecursiveDirectoryIterator($srcFolder);
+
+$filteredFileList = new FilenameFilter($srcDirectory, '/(?:php)$/i');
+$filteredFileList = new FilenameFilter($filteredFileList, '/^(?!.*(Matrix|Exception)\.php).*$/i');
+
+foreach (new RecursiveIteratorIterator($filteredFileList) as $file) {
+    if ($file->isFile()) {
+        include_once $file;
+    }
+}

+ 69 - 0
vendor/markbaker/matrix/classes/src/Builder.php

@@ -0,0 +1,69 @@
+<?php
+
+/**
+ *
+ * Class for the creating "special" Matrices
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Matrix Builder class.
+ *
+ * @package Matrix
+ */
+class Builder
+{
+    /**
+     * Create a new matrix of specified dimensions, and filled with a specified value
+     * If the column argument isn't provided, then a square matrix will be created
+     *
+     * @param $value
+     * @param $rows
+     * @param null $columns
+     * @return Matrix
+     * @throws Exception
+     */
+    public static function createFilledMatrix($value, $rows, $columns = null)
+    {
+        if ($columns === null) {
+            $columns = $rows;
+        }
+
+        $rows = Matrix::validateRow($rows);
+        $columns = Matrix::validateColumn($columns);
+
+        return new Matrix(
+            array_fill(
+                0,
+                $rows,
+                array_fill(
+                    0,
+                    $columns,
+                    $value
+                )
+            )
+        );
+    }
+
+    /**
+     * Create a new identity matrix of specified dimensions
+     * This will always be a square matrix, with the number of rows and columns matching the provided dimension
+     *
+     * @param int $dimensions
+     * @return Matrix
+     * @throws Exception
+     */
+    public static function createIdentityMatrix($dimensions)
+    {
+        $grid = static::createFilledMatrix(null, $dimensions)->toArray();
+
+        for ($x = 0; $x < $dimensions; ++$x) {
+            $grid[$x][$x] = 1;
+        }
+
+        return new Matrix($grid);
+    }
+}

+ 13 - 0
vendor/markbaker/matrix/classes/src/Exception.php

@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * Exception.
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+class Exception extends \Exception
+{
+}

+ 318 - 0
vendor/markbaker/matrix/classes/src/Functions.php

@@ -0,0 +1,318 @@
+<?php
+
+namespace Matrix;
+
+class Functions
+{
+    /**
+     * Calculate the adjoint of the matrix
+     *
+     * @param Matrix $matrix The matrix whose adjoint we wish to calculate
+     * @return Matrix
+     **/
+    private static function getAdjoint(Matrix $matrix)
+    {
+        return self::transpose(
+            self::getCofactors($matrix)
+        );
+    }
+
+    /**
+     * Return the adjoint of this matrix
+     * The adjugate, classical adjoint, or adjunct of a square matrix is the transpose of its cofactor matrix.
+     * The adjugate has sometimes been called the "adjoint", but today the "adjoint" of a matrix normally refers
+     *     to its corresponding adjoint operator, which is its conjugate transpose.
+     *
+     * @param Matrix $matrix The matrix whose adjoint we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function adjoint(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Adjoint can only be calculated for a square matrix');
+        }
+
+        return self::getAdjoint($matrix);
+    }
+
+    /**
+     * Calculate the cofactors of the matrix
+     *
+     * @param Matrix $matrix The matrix whose cofactors we wish to calculate
+     * @return Matrix
+     **/
+    private static function getCofactors(Matrix $matrix)
+    {
+        $cofactors = self::getMinors($matrix);
+        $dimensions = $matrix->rows;
+
+        $cof = 1;
+        for ($i = 0; $i < $dimensions; ++$i) {
+            $cofs = $cof;
+            for ($j = 0; $j < $dimensions; ++$j) {
+                $cofactors[$i][$j] *= $cofs;
+                $cofs = -$cofs;
+            }
+            $cof = -$cof;
+        }
+
+        return new Matrix($cofactors);
+    }
+
+    /**
+     * Return the cofactors of this matrix
+     *
+     * @param Matrix $matrix The matrix whose cofactors we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function cofactors(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Cofactors can only be calculated for a square matrix');
+        }
+
+        return self::getCofactors($matrix);
+    }
+
+    private static function getDeterminantSegment(Matrix $matrix, $row, $column)
+    {
+        $tmpMatrix = $matrix->toArray();
+        unset($tmpMatrix[$row]);
+        array_walk(
+            $tmpMatrix,
+            function (&$row) use ($column) {
+                unset($row[$column]);
+            }
+        );
+
+        return self::getDeterminant(new Matrix($tmpMatrix));
+    }
+
+    /**
+     * Calculate the determinant of the matrix
+     *
+     * @param Matrix $matrix The matrix whose determinant we wish to calculate
+     * @return float
+     **/
+    private static function getDeterminant(Matrix $matrix)
+    {
+        $dimensions = $matrix->rows;
+        if ($dimensions == 1) {
+            return $matrix->getValue(1, 1);
+        } elseif ($dimensions == 2) {
+            return $matrix->getValue(1, 1) * $matrix->getValue(2, 2) - $matrix->getValue(1, 2) * $matrix->getValue(2, 1);
+        }
+        
+        $determinant = 0;
+        for ($i = 1; $i <= $dimensions; ++$i) {
+            $det = $matrix->getValue(1, $i) * self::getDeterminantSegment($matrix, 0, $i-1);
+            if (($i % 2) == 0) {
+                $determinant -= $det;
+            } else {
+                $determinant += $det;
+            }
+        }
+
+        return $determinant;
+    }
+
+    /**
+     * Return the determinant of this matrix
+     *
+     * @param Matrix $matrix The matrix whose determinant we wish to calculate
+     * @return float
+     * @throws Exception
+     **/
+    public static function determinant(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Determinant can only be calculated for a square matrix');
+        }
+
+        return self::getDeterminant($matrix);
+    }
+
+    /**
+     * Return the diagonal of this matrix
+     *
+     * @param Matrix $matrix The matrix whose diagonal we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function diagonal(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Diagonal can only be extracted from a square matrix');
+        }
+
+        $dimensions = $matrix->rows;
+        $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
+            ->toArray();
+
+        for ($i = 0; $i < $dimensions; ++$i) {
+            $grid[$i][$i] = $matrix->getValue($i + 1, $i + 1);
+        }
+
+        return new Matrix($grid);
+    }
+
+    /**
+     * Return the antidiagonal of this matrix
+     *
+     * @param Matrix $matrix The matrix whose antidiagonal we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function antidiagonal(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Anti-Diagonal can only be extracted from a square matrix');
+        }
+
+        $dimensions = $matrix->rows;
+        $grid = Builder::createFilledMatrix(0, $dimensions, $dimensions)
+            ->toArray();
+
+        for ($i = 0; $i < $dimensions; ++$i) {
+            $grid[$i][$dimensions - $i - 1] = $matrix->getValue($i + 1, $dimensions - $i);
+        }
+
+        return new Matrix($grid);
+    }
+
+    /**
+     * Return the identity matrix
+     * The identity matrix, or sometimes ambiguously called a unit matrix, of size n is the n × n square matrix
+     *   with ones on the main diagonal and zeros elsewhere
+     *
+     * @param Matrix $matrix The matrix whose identity we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function identity(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Identity can only be created for a square matrix');
+        }
+
+        $dimensions = $matrix->rows;
+
+        return Builder::createIdentityMatrix($dimensions);
+    }
+
+    /**
+     * Return the inverse of this matrix
+     *
+     * @param Matrix $matrix The matrix whose inverse we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function inverse(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Inverse can only be calculated for a square matrix');
+        }
+
+        $determinant = self::getDeterminant($matrix);
+        if ($determinant == 0.0) {
+            throw new Exception('Inverse can only be calculated for a matrix with a non-zero determinant');
+        }
+
+        if ($matrix->rows == 1) {
+            return new Matrix([[1 / $matrix->getValue(1, 1)]]);
+        }
+
+        return self::getAdjoint($matrix)
+            ->multiply(1 / $determinant);
+    }
+
+    /**
+     * Calculate the minors of the matrix
+     *
+     * @param Matrix $matrix The matrix whose minors we wish to calculate
+     * @return array[]
+     **/
+    protected static function getMinors(Matrix $matrix)
+    {
+        $minors = $matrix->toArray();
+        $dimensions = $matrix->rows;
+        if ($dimensions == 1) {
+            return $minors;
+        }
+
+        for ($i = 0; $i < $dimensions; ++$i) {
+            for ($j = 0; $j < $dimensions; ++$j) {
+                $minors[$i][$j] = self::getDeterminantSegment($matrix, $i, $j);
+            }
+        }
+
+        return $minors;
+    }
+
+    /**
+     * Return the minors of the matrix
+     * The minor of a matrix A is the determinant of some smaller square matrix, cut down from A by removing one or
+     *     more of its rows or columns.
+     * Minors obtained by removing just one row and one column from square matrices (first minors) are required for
+     *     calculating matrix cofactors, which in turn are useful for computing both the determinant and inverse of
+     *     square matrices.
+     *
+     * @param Matrix $matrix The matrix whose minors we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function minors(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Minors can only be calculated for a square matrix');
+        }
+
+        return new Matrix(self::getMinors($matrix));
+    }
+
+    /**
+     * Return the trace of this matrix
+     * The trace is defined as the sum of the elements on the main diagonal (the diagonal from the upper left to the lower right)
+     *     of the matrix
+     *
+     * @param Matrix $matrix The matrix whose trace we wish to calculate
+     * @return float
+     * @throws Exception
+     **/
+    public static function trace(Matrix $matrix)
+    {
+        if (!$matrix->isSquare()) {
+            throw new Exception('Trace can only be extracted from a square matrix');
+        }
+
+        $dimensions = $matrix->rows;
+        $result = 0;
+        for ($i = 1; $i <= $dimensions; ++$i) {
+            $result += $matrix->getValue($i, $i);
+        }
+
+        return $result;
+    }
+
+    /**
+     * Return the transpose of this matrix
+     *
+     * @param Matrix $matrix The matrix whose transpose we wish to calculate
+     * @return Matrix
+     * @throws Exception
+     **/
+    public static function transpose(Matrix $matrix)
+    {
+        $grid = call_user_func_array(
+            'array_map',
+            array_merge(
+                [null],
+                $matrix->toArray()
+            )
+        );
+
+        return new Matrix($grid);
+    }
+}

+ 403 - 0
vendor/markbaker/matrix/classes/src/Matrix.php

@@ -0,0 +1,403 @@
+<?php
+
+/**
+ *
+ * Class for the management of Matrices
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Matrix object.
+ *
+ * @package Matrix
+ *
+ * @property-read int $rows The number of rows in the matrix
+ * @property-read int $columns The number of columns in the matrix
+ * @method Matrix antidiagonal()
+ * @method Matrix adjoint()
+ * @method Matrix cofactors()
+ * @method float determinant()
+ * @method Matrix diagonal()
+ * @method Matrix identity()
+ * @method Matrix inverse()
+ * @method Matrix pseudoInverse()
+ * @method Matrix minors()
+ * @method float trace()
+ * @method Matrix transpose()
+ * @method Matrix add(...$matrices)
+ * @method Matrix subtract(...$matrices)
+ * @method Matrix multiply(...$matrices)
+ * @method Matrix divideby(...$matrices)
+ * @method Matrix divideinto(...$matrices)
+ */
+class Matrix
+{
+    protected $rows;
+    protected $columns;
+    protected $grid = [];
+
+    /*
+     * Create a new Matrix object from an array of values
+     *
+     * @param array $grid
+     */
+    public function __construct(array $grid)
+    {
+        $this->buildFromArray(array_values($grid));
+    }
+
+    /*
+     * Create a new Matrix object from an array of values
+     *
+     * @param array $grid
+     */
+    protected function buildFromArray(array $grid)
+    {
+        $this->rows = count($grid);
+        $columns = array_reduce(
+            $grid,
+            function ($carry, $value) {
+                return max($carry, is_array($value) ? count($value) : 1);
+            },
+            0
+        );
+        $this->columns = $columns;
+
+        array_walk(
+            $grid,
+            function (&$value) use ($columns) {
+                if (!is_array($value)) {
+                    $value = [$value];
+                }
+                $value = array_pad(array_values($value), $columns, null);
+            }
+        );
+
+        $this->grid = $grid;
+    }
+
+    /**
+     * Validate that a row number is a positive integer
+     *
+     * @param $row
+     * @return int
+     * @throws Exception
+     */
+    public static function validateRow($row)
+    {
+        if ((!is_numeric($row)) || (intval($row) < 1)) {
+            throw new Exception('Invalid Row');
+        }
+
+        return (int) $row;
+    }
+
+    /**
+     * Validate that a column number is a positive integer
+     *
+     * @param $column
+     * @return int
+     * @throws Exception
+     */
+    public static function validateColumn($column)
+    {
+        if ((!is_numeric($column)) || (intval($column) < 1)) {
+            throw new Exception('Invalid Column');
+        }
+
+        return (int) $column;
+    }
+
+    /**
+     * Validate that a row number falls within the set of rows for this matrix
+     *
+     * @param $row
+     * @return int
+     * @throws Exception
+     */
+    protected function validateRowInRange($row)
+    {
+        $row = static::validateRow($row);
+        if ($row > $this->rows) {
+            throw new Exception('Requested Row exceeds matrix size');
+        }
+
+        return $row;
+    }
+
+    /**
+     * Validate that a column number falls within the set of columns for this matrix
+     *
+     * @param $column
+     * @return int
+     * @throws Exception
+     */
+    protected function validateColumnInRange($column)
+    {
+        $column = static::validateColumn($column);
+        if ($column > $this->columns) {
+            throw new Exception('Requested Column exceeds matrix size');
+        }
+
+        return $column;
+    }
+
+    /**
+     * Return a new matrix as a subset of rows from this matrix, starting at row number $row, and $rowCount rows
+     * A $rowCount value of 0 will return all rows of the matrix from $row
+     * A negative $rowCount value will return rows until that many rows from the end of the matrix
+     *
+     * Note that row numbers start from 1, not from 0
+     *
+     * @param $row
+     * @param int $rowCount
+     * @return static
+     * @throws Exception
+     */
+    public function getRows($row, $rowCount = 1)
+    {
+        $row = $this->validateRowInRange($row);
+        if ($rowCount == 0) {
+            $rowCount = $this->rows - $row + 1;
+        }
+
+        return new static(array_slice($this->grid, $row - 1, $rowCount));
+    }
+
+    /**
+     * Return a new matrix as a subset of columns from this matrix, starting at column number $column, and $columnCount columns
+     * A $columnCount value of 0 will return all columns of the matrix from $column
+     * A negative $columnCount value will return columns until that many columns from the end of the matrix
+     *
+     * Note that column numbers start from 1, not from 0
+     *
+     * @param $column
+     * @param int $columnCount
+     * @return static
+     * @throws Exception
+     */
+    public function getColumns($column, $columnCount = 1)
+    {
+        $column = $this->validateColumnInRange($column);
+        if ($columnCount < 1) {
+            $columnCount = $this->columns + $columnCount - $column + 1;
+        }
+
+        $grid = [];
+        for ($i = $column - 1; $i < $column + $columnCount - 1; ++$i) {
+            $grid[] = array_column($this->grid, $i);
+        }
+
+        return (new static($grid))->transpose();
+    }
+
+    /**
+     * Return a new matrix as a subset of rows from this matrix, dropping rows starting at row number $row,
+     *     and $rowCount rows
+     * A negative $rowCount value will drop rows until that many rows from the end of the matrix
+     * A $rowCount value of 0 will remove all rows of the matrix from $row
+     *
+     * Note that row numbers start from 1, not from 0
+     *
+     * @param $row
+     * @param int $rowCount
+     * @return static
+     * @throws Exception
+     */
+    public function dropRows($row, $rowCount = 1)
+    {
+        $this->validateRowInRange($row);
+        if ($rowCount == 0) {
+            $rowCount = $this->rows - $row + 1;
+        }
+
+        $grid = $this->grid;
+        array_splice($grid, $row - 1, $rowCount);
+
+        return new static($grid);
+    }
+
+    /**
+     * Return a new matrix as a subset of columns from this matrix, dropping columns starting at column number $column,
+     *     and $columnCount columns
+     * A negative $columnCount value will drop columns until that many columns from the end of the matrix
+     * A $columnCount value of 0 will remove all columns of the matrix from $column
+     *
+     * Note that column numbers start from 1, not from 0
+     *
+     * @param $column
+     * @param int $columnCount
+     * @return static
+     * @throws Exception
+     */
+    public function dropColumns($column, $columnCount = 1)
+    {
+        $this->validateColumnInRange($column);
+        if ($columnCount < 1) {
+            $columnCount = $this->columns + $columnCount - $column + 1;
+        }
+        
+        $grid = $this->grid;
+        array_walk(
+            $grid,
+            function (&$row) use ($column, $columnCount) {
+                array_splice($row, $column - 1, $columnCount);
+            }
+        );
+
+        return new static($grid);
+    }
+
+    /**
+     * Return a value from this matrix, from the "cell" identified by the row and column numbers
+     * Note that row and column numbers start from 1, not from 0
+     *
+     * @param $row
+     * @param $column
+     * @return static
+     * @throws Exception
+     */
+    public function getValue($row, $column)
+    {
+        $row = $this->validateRowInRange($row);
+        $column = $this->validateColumnInRange($column);
+
+        return $this->grid[$row - 1][$column - 1];
+    }
+
+    /**
+     * Returns a Generator that will yield each row of the matrix in turn as a vector matrix
+     *     or the value of each cell if the matrix is a vector
+     *
+     * @return \Generator|Matrix[]|mixed[]
+     */
+    public function rows()
+    {
+        foreach ($this->grid as $i => $row) {
+            yield $i + 1 => ($this->columns == 1)
+                ? $row[0]
+                : new static([$row]);
+        }
+    }
+
+    /**
+     * Returns a Generator that will yield each column of the matrix in turn as a vector matrix
+     *     or the value of each cell if the matrix is a vector
+     *
+     * @return \Generator|Matrix[]|mixed[]
+     */
+    public function columns()
+    {
+        for ($i = 0; $i < $this->columns; ++$i) {
+            yield $i + 1 => ($this->rows == 1)
+                ? $this->grid[0][$i]
+                : new static(array_column($this->grid, $i));
+        }
+    }
+
+    /**
+     * Identify if the row and column dimensions of this matrix are equal,
+     *     i.e. if it is a "square" matrix
+     *
+     * @return bool
+     */
+    public function isSquare()
+    {
+        return $this->rows == $this->columns;
+    }
+
+    /**
+     * Identify if this matrix is a vector
+     *     i.e. if it comprises only a single row or a single column
+     *
+     * @return bool
+     */
+    public function isVector()
+    {
+        return $this->rows == 1 || $this->columns == 1;
+    }
+
+    /**
+     * Return the matrix as a 2-dimensional array
+     *
+     * @return array
+     */
+    public function toArray()
+    {
+        return $this->grid;
+    }
+
+    protected static $getters = [
+        'rows',
+        'columns',
+    ];
+
+    /**
+     * Access specific properties as read-only (no setters)
+     *
+     * @param     $propertyName
+     * @return    mixed
+     * @throws    Exception
+     */
+    public function __get($propertyName)
+    {
+        $propertyName = strtolower($propertyName);
+
+        // Test for function calls
+        if (in_array($propertyName, self::$getters)) {
+            return $this->$propertyName;
+        }
+
+        throw new Exception('Property does not exist');
+    }
+
+    protected static $functions = [
+        'antidiagonal',
+        'adjoint',
+        'cofactors',
+        'determinant',
+        'diagonal',
+        'identity',
+        'inverse',
+        'minors',
+        'trace',
+        'transpose',
+    ];
+
+    protected static $operations = [
+        'add',
+        'subtract',
+        'multiply',
+        'divideby',
+        'divideinto',
+        'directsum',
+    ];
+
+    /**
+     * Returns the result of the function call or operation
+     *
+     * @param     string $functionName
+     * @param     mixed[] $arguments
+     * @return    Matrix|float
+     * @throws    Exception|\InvalidArgumentException
+     */
+    public function __call($functionName, $arguments)
+    {
+        $functionName = strtolower(str_replace('_', '', $functionName));
+
+        // Test for function calls
+        if (in_array($functionName, self::$functions)) {
+            $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
+            return $functionName($this, ...$arguments);
+        }
+        // Test for operation calls
+        if (in_array($functionName, self::$operations)) {
+            $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}";
+            return $functionName($this, ...$arguments);
+        }
+        throw new Exception('Function or Operation does not exist');
+    }
+}

+ 68 - 0
vendor/markbaker/matrix/classes/src/Operators/Addition.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+class Addition extends Operator
+{
+    /**
+     * Execute the addition
+     *
+     * @param mixed $value The matrix or numeric value to add to the current base value
+     * @throws Exception If the provided argument is not appropriate for the operation
+     * @return $this The operation object, allowing multiple additions to be chained
+     **/
+    public function execute($value)
+    {
+        if (is_array($value)) {
+            $value = new Matrix($value);
+        }
+
+        if (is_object($value) && ($value instanceof Matrix)) {
+            return $this->addMatrix($value);
+        } elseif (is_numeric($value)) {
+            return $this->addScalar($value);
+        }
+
+        throw new Exception('Invalid argument for addition');
+    }
+
+    /**
+     * Execute the addition for a scalar
+     *
+     * @param mixed $value The numeric value to add to the current base value
+     * @return $this The operation object, allowing multiple additions to be chained
+     **/
+    protected function addScalar($value)
+    {
+        for ($row = 0; $row < $this->rows; ++$row) {
+            for ($column = 0; $column < $this->columns; ++$column) {
+                $this->matrix[$row][$column] += $value;
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Execute the addition for a matrix
+     *
+     * @param Matrix $value The numeric value to add to the current base value
+     * @return $this The operation object, allowing multiple additions to be chained
+     * @throws Exception If the provided argument is not appropriate for the operation
+     **/
+    protected function addMatrix(Matrix $value)
+    {
+        $this->validateMatchingDimensions($value);
+
+        for ($row = 0; $row < $this->rows; ++$row) {
+            for ($column = 0; $column < $this->columns; ++$column) {
+                $this->matrix[$row][$column] += $value->getValue($row + 1, $column + 1);
+            }
+        }
+
+        return $this;
+    }
+}

+ 65 - 0
vendor/markbaker/matrix/classes/src/Operators/DirectSum.php

@@ -0,0 +1,65 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+class DirectSum extends Operator
+{
+    /**
+     * Execute the addition
+     *
+     * @param mixed $value The matrix or numeric value to add to the current base value
+     * @throws Exception If the provided argument is not appropriate for the operation
+     * @return $this The operation object, allowing multiple additions to be chained
+     **/
+    public function execute($value)
+    {
+        if (is_array($value)) {
+            $value = new Matrix($value);
+        }
+
+        if (is_object($value) && ($value instanceof Matrix)) {
+            return $this->directSumMatrix($value);
+        }
+
+        throw new Exception('Invalid argument for addition');
+    }
+
+    /**
+     * Execute the direct sum for a matrix
+     *
+     * @param Matrix $value The numeric value to concatenate/direct sum with the current base value
+     * @return $this The operation object, allowing multiple additions to be chained
+     * @throws Exception If the provided argument is not appropriate for the operation
+     **/
+    protected function directSumMatrix(Matrix $value)
+    {
+        $originalColumnCount = count($this->matrix[0]);
+        $originalRowCount = count($this->matrix);
+        $additionalColumnCount = $value->columns;
+        $additionalRowCount = $value->rows;
+        $value = $value->toArray();
+
+        for ($row = 0; $row < $this->rows; ++$row) {
+            $this->matrix[$row] = array_merge($this->matrix[$row], array_fill(0, $additionalColumnCount, 0));
+        }
+
+        $this->matrix = array_merge(
+            $this->matrix,
+            array_fill(0, $additionalRowCount, array_fill(0, $originalColumnCount, 0))
+        );
+
+        for ($row = $originalRowCount; $row < $originalRowCount + $additionalRowCount; ++$row) {
+            array_splice(
+                $this->matrix[$row],
+                $originalColumnCount,
+                $additionalColumnCount,
+                $value[$row - $originalRowCount]
+            );
+        }
+
+        return $this;
+    }
+}

+ 38 - 0
vendor/markbaker/matrix/classes/src/Operators/Division.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace Matrix\Operators;
+
+use \Matrix\Matrix;
+use \Matrix\Functions;
+use Matrix\Exception;
+
+class Division extends Multiplication
+{
+    /**
+     * Execute the division
+     *
+     * @param mixed $value The matrix or numeric value to divide the current base value by
+     * @throws Exception If the provided argument is not appropriate for the operation
+     * @return $this The operation object, allowing multiple divisions to be chained
+     **/
+    public function execute($value)
+    {
+        if (is_array($value)) {
+            $value = new Matrix($value);
+        }
+
+        if (is_object($value) && ($value instanceof Matrix)) {
+            try {
+                $value = Functions::inverse($value);
+            } catch (Exception $e) {
+                throw new Exception('Division can only be calculated using a matrix with a non-zero determinant');
+            }
+
+            return $this->multiplyMatrix($value);
+        } elseif (is_numeric($value)) {
+            return $this->multiplyScalar(1 / $value);
+        }
+
+        throw new Exception('Invalid argument for division');
+    }
+}

+ 77 - 0
vendor/markbaker/matrix/classes/src/Operators/Multiplication.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use \Matrix\Builder;
+use Matrix\Exception;
+
+class Multiplication extends Operator
+{
+    /**
+     * Execute the multiplication
+     *
+     * @param mixed $value The matrix or numeric value to multiply the current base value by
+     * @throws Exception If the provided argument is not appropriate for the operation
+     * @return $this The operation object, allowing multiple multiplications to be chained
+     **/
+    public function execute($value)
+    {
+        if (is_array($value)) {
+            $value = new Matrix($value);
+        }
+
+        if (is_object($value) && ($value instanceof Matrix)) {
+            return $this->multiplyMatrix($value);
+        } elseif (is_numeric($value)) {
+            return $this->multiplyScalar($value);
+        }
+
+        throw new Exception('Invalid argument for multiplication');
+    }
+
+    /**
+     * Execute the multiplication for a scalar
+     *
+     * @param mixed $value The numeric value to multiply with the current base value
+     * @return $this The operation object, allowing multiple mutiplications to be chained
+     **/
+    protected function multiplyScalar($value)
+    {
+        for ($row = 0; $row < $this->rows; ++$row) {
+            for ($column = 0; $column < $this->columns; ++$column) {
+                $this->matrix[$row][$column] *= $value;
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Execute the multiplication for a matrix
+     *
+     * @param Matrix $value The numeric value to multiply with the current base value
+     * @return $this The operation object, allowing multiple mutiplications to be chained
+     * @throws Exception If the provided argument is not appropriate for the operation
+     **/
+    protected function multiplyMatrix(Matrix $value)
+    {
+        $this->validateReflectingDimensions($value);
+
+        $newRows = $this->rows;
+        $newColumns = $value->columns;
+        $matrix = Builder::createFilledMatrix(0, $newRows, $newColumns)
+            ->toArray();
+        for ($row = 0; $row < $newRows; ++$row) {
+            for ($column = 0; $column < $newColumns; ++$column) {
+                $columnData = $value->getColumns($column + 1)->toArray();
+                foreach ($this->matrix[$row] as $key => $valueData) {
+                    $matrix[$row][$column] += $valueData * $columnData[$key][0];
+                }
+            }
+        }
+        $this->matrix = $matrix;
+
+        return $this;
+    }
+}

+ 78 - 0
vendor/markbaker/matrix/classes/src/Operators/Operator.php

@@ -0,0 +1,78 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+abstract class Operator
+{
+    /**
+     * Stored internally as a 2-dimension array of values
+     *
+     * @property mixed[][] $matrix
+     **/
+    protected $matrix;
+
+    /**
+     * Number of rows in the matrix
+     *
+     * @property integer $rows
+     **/
+    protected $rows;
+
+    /**
+     * Number of columns in the matrix
+     *
+     * @property integer $columns
+     **/
+    protected $columns;
+
+    /**
+     * Create an new handler object for the operation
+     *
+     * @param Matrix $matrix The base Matrix object on which the operation will be performed
+     */
+    public function __construct(Matrix $matrix)
+    {
+        $this->rows = $matrix->rows;
+        $this->columns = $matrix->columns;
+        $this->matrix = $matrix->toArray();
+    }
+
+    /**
+     * Compare the dimensions of the matrices being operated on to see if they are valid for addition/subtraction
+     *
+     * @param Matrix $matrix The second Matrix object on which the operation will be performed
+     * @throws Exception
+     */
+    protected function validateMatchingDimensions(Matrix $matrix)
+    {
+        if (($this->rows != $matrix->rows) || ($this->columns != $matrix->columns)) {
+            throw new Exception('Matrices have mismatched dimensions');
+        }
+    }
+
+    /**
+     * Compare the dimensions of the matrices being operated on to see if they are valid for multiplication/division
+     *
+     * @param Matrix $matrix The second Matrix object on which the operation will be performed
+     * @throws Exception
+     */
+    protected function validateReflectingDimensions(Matrix $matrix)
+    {
+        if ($this->columns != $matrix->rows) {
+            throw new Exception('Matrices have mismatched dimensions');
+        }
+    }
+
+    /**
+     * Return the result of the operation
+     *
+     * @return Matrix
+     */
+    public function result()
+    {
+        return new Matrix($this->matrix);
+    }
+}

+ 68 - 0
vendor/markbaker/matrix/classes/src/Operators/Subtraction.php

@@ -0,0 +1,68 @@
+<?php
+
+namespace Matrix\Operators;
+
+use Matrix\Matrix;
+use Matrix\Exception;
+
+class Subtraction extends Operator
+{
+    /**
+     * Execute the subtraction
+     *
+     * @param mixed $value The matrix or numeric value to subtract from the current base value
+     * @throws Exception If the provided argument is not appropriate for the operation
+     * @return $this The operation object, allowing multiple subtractions to be chained
+     **/
+    public function execute($value)
+    {
+        if (is_array($value)) {
+            $value = new Matrix($value);
+        }
+
+        if (is_object($value) && ($value instanceof Matrix)) {
+            return $this->subtractMatrix($value);
+        } elseif (is_numeric($value)) {
+            return $this->subtractScalar($value);
+        }
+
+        throw new Exception('Invalid argument for subtraction');
+    }
+
+    /**
+     * Execute the subtraction for a scalar
+     *
+     * @param mixed $value The numeric value to subtracted from the current base value
+     * @return $this The operation object, allowing multiple additions to be chained
+     **/
+    protected function subtractScalar($value)
+    {
+        for ($row = 0; $row < $this->rows; ++$row) {
+            for ($column = 0; $column < $this->columns; ++$column) {
+                $this->matrix[$row][$column] -= $value;
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Execute the subtraction for a matrix
+     *
+     * @param Matrix $value The numeric value to subtract from the current base value
+     * @return $this The operation object, allowing multiple subtractions to be chained
+     * @throws Exception If the provided argument is not appropriate for the operation
+     **/
+    protected function subtractMatrix(Matrix $value)
+    {
+        $this->validateMatchingDimensions($value);
+
+        for ($row = 0; $row < $this->rows; ++$row) {
+            for ($column = 0; $column < $this->columns; ++$column) {
+                $this->matrix[$row][$column] -= $value->getValue($row + 1, $column + 1);
+            }
+        }
+
+        return $this;
+    }
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/adjoint.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix adjoint() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the adjoint of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The new matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function adjoint($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::adjoint($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/antidiagonal.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix antidiagonal() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the antidiagonal of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The new matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function antidiagonal($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::antidiagonal($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/cofactors.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix cofactors() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the cofactors of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The new matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function cofactors($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::cofactors($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/determinant.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix determinant() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the determinant of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The new matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function determinant($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::determinant($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/diagonal.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix diagonal() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the diagonal of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The new matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function diagonal($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::diagonal($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/identity.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix identity() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the identity of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The identity matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function identity($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::identity($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/inverse.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix inverse() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the inverse of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The new matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function inverse($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::inverse($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/minors.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix minors() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the minors of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The new matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function minors($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::minors($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/trace.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix trace() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the trace of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    float            The trace of the matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function trace($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::trace($matrix);
+}

+ 26 - 0
vendor/markbaker/matrix/classes/src/functions/transpose.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix transpose() function
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+/**
+ * Returns the transpose of a matrix or an array.
+ *
+ * @param     Matrix|array     $matrix    Matrix or an array to treat as a matrix.
+ * @return    Matrix           The transposed matrix
+ * @throws    Exception        If argument isn't a valid matrix or array.
+ */
+function transpose($matrix)
+{
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    return Functions::transpose($matrix);
+}

+ 39 - 0
vendor/markbaker/matrix/classes/src/operations/add.php

@@ -0,0 +1,39 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix addition operation
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+use Matrix\Operators\Addition;
+
+/**
+ * Adds two or more matrices
+ *
+ * @param     mixed[]    $matrixValues   The matrices to add
+ * @return    Matrix
+ * @throws    Exception
+ */
+function add(...$matrixValues)
+{
+    if (count($matrixValues) < 2) {
+        throw new Exception('This operation requires at least 2 arguments');
+    }
+
+    $matrix = array_shift($matrixValues);
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    $result = new Addition($matrix);
+
+    foreach ($matrixValues as $matrix) {
+        $result->execute($matrix);
+    }
+
+    return $result->result();
+}

+ 39 - 0
vendor/markbaker/matrix/classes/src/operations/directsum.php

@@ -0,0 +1,39 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix direct sum operation
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+use Matrix\Operators\DirectSum;
+
+/**
+ * Adds two or more matrices
+ *
+ * @param     mixed[]    $matrixValues   The matrices to add
+ * @return    Matrix
+ * @throws    Exception
+ */
+function directsum(...$matrixValues)
+{
+    if (count($matrixValues) < 2) {
+        throw new Exception('This operation requires at least 2 arguments');
+    }
+
+    $matrix = array_shift($matrixValues);
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    $result = new DirectSum($matrix);
+
+    foreach ($matrixValues as $matrix) {
+        $result->execute($matrix);
+    }
+
+    return $result->result();
+}

+ 38 - 0
vendor/markbaker/matrix/classes/src/operations/divideby.php

@@ -0,0 +1,38 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix division operation
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+use Matrix\Operators\Division;
+
+/**
+ * Divides two or more matrix numbers
+ *
+ * @param     mixed[]    $matrixValues   The matrices to divide
+ * @return    Matrix
+ */
+function divideby(...$matrixValues)
+{
+    if (count($matrixValues) < 2) {
+        throw new \Exception('This function requires at least 2 arguments');
+    }
+
+    $matrix = array_shift($matrixValues);
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    $result = new Division($matrix);
+
+    foreach ($matrixValues as $matrix) {
+        $result->execute($matrix);
+    }
+
+    return $result->result();
+}

+ 39 - 0
vendor/markbaker/matrix/classes/src/operations/divideinto.php

@@ -0,0 +1,39 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix division operation
+ *
+ * @copyright  Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+use Matrix\Operators\Division;
+
+/**
+ * Divides two or more matrix numbers
+ *
+ * @param     array of string|integer|float|Matrix    $matrixValues   The numbers to divide
+ * @return    Matrix
+ */
+function divideinto(...$matrixValues)
+{
+    if (count($matrixValues) < 2) {
+        throw new \Exception('This function requires at least 2 arguments');
+    }
+    $matrixValues = array_reverse($matrixValues);
+
+    $matrix = array_shift($matrixValues);
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    $result = new Division($matrix);
+
+    foreach ($matrixValues as $matrix) {
+        $result->execute($matrix);
+    }
+
+    return $result->result();
+}

+ 39 - 0
vendor/markbaker/matrix/classes/src/operations/multiply.php

@@ -0,0 +1,39 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix multiplication operation
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+use Matrix\Operators\Multiplication;
+
+/**
+ * Multiplies two or more matrices
+ *
+ * @param     mixed[]    $matrixValues   The matrices to multiply
+ * @return    Matrix
+ * @throws    Exception
+ */
+function multiply(...$matrixValues)
+{
+    if (count($matrixValues) < 2) {
+        throw new Exception('This operation requires at least 2 arguments');
+    }
+
+    $matrix = array_shift($matrixValues);
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    $result = new Multiplication($matrix);
+
+    foreach ($matrixValues as $matrix) {
+        $result->execute($matrix);
+    }
+
+    return $result->result();
+}

+ 39 - 0
vendor/markbaker/matrix/classes/src/operations/subtract.php

@@ -0,0 +1,39 @@
+<?php
+
+/**
+ *
+ * Function code for the matrix subtraction operation
+ *
+ * @copyright  Copyright (c) 2018 Mark Baker (https://github.com/MarkBaker/PHPMatrix)
+ * @license    https://opensource.org/licenses/MIT    MIT
+ */
+namespace Matrix;
+
+use Matrix\Operators\Subtraction;
+
+/**
+ * Subtracts two or more matrices
+ *
+ * @param     mixed[]    $matrixValues   The matrices to subtract
+ * @return    Matrix
+ * @throws    Exception
+ */
+function subtract(...$matrixValues)
+{
+    if (count($matrixValues) < 2) {
+        throw new Exception('This operation requires at least 2 arguments');
+    }
+
+    $matrix = array_shift($matrixValues);
+    if (!is_object($matrix) || !($matrix instanceof Matrix)) {
+        $matrix = new Matrix($matrix);
+    }
+
+    $result = new Subtraction($matrix);
+
+    foreach ($matrixValues as $matrix) {
+        $result->execute($matrix);
+    }
+
+    return $result->result();
+}

+ 68 - 0
vendor/markbaker/matrix/composer.json

@@ -0,0 +1,68 @@
+{
+    "name": "markbaker/matrix",
+    "type": "library",
+    "description": "PHP Class for working with matrices",
+    "keywords": ["matrix", "vector", "mathematics"],
+    "homepage": "https://github.com/MarkBaker/PHPMatrix",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Mark Baker",
+            "email": "mark@lange.demon.co.uk"
+        }
+    ],
+    "require": {
+        "php": "^5.6.0|^7.0.0"
+    },
+    "require-dev": {
+        "phpunit/phpunit": "^4.8.35|^5.4.0",
+        "phpdocumentor/phpdocumentor":"2.*",
+        "phpmd/phpmd": "2.*",
+        "sebastian/phpcpd": "2.*",
+        "phploc/phploc": "2.*",
+        "squizlabs/php_codesniffer": "^3.3.0",
+        "phpcompatibility/php-compatibility": "^8.0",
+        "dealerdirect/phpcodesniffer-composer-installer": "^0.4.3"
+    },
+    "autoload": {
+        "psr-4": {
+            "Matrix\\": "classes/src/"
+        },
+        "files": [
+            "classes/src/functions/adjoint.php",
+            "classes/src/functions/antidiagonal.php",
+            "classes/src/functions/cofactors.php",
+            "classes/src/functions/determinant.php",
+            "classes/src/functions/diagonal.php",
+            "classes/src/functions/identity.php",
+            "classes/src/functions/inverse.php",
+            "classes/src/functions/minors.php",
+            "classes/src/functions/trace.php",
+            "classes/src/functions/transpose.php",
+            "classes/src/operations/add.php",
+            "classes/src/operations/directsum.php",
+            "classes/src/operations/subtract.php",
+            "classes/src/operations/multiply.php",
+            "classes/src/operations/divideby.php",
+            "classes/src/operations/divideinto.php"
+        ]
+    },
+    "scripts": {
+        "style": [
+            "phpcs --report-width=200 --report-summary  --report-full classes/src/ --standard=PSR2 -n"
+        ],
+        "test": [
+            "phpunit"
+        ],
+        "mess": [
+            "phpmd classes/src/ xml codesize,unusedcode,design,naming -n"
+        ],
+        "lines": [
+            "phploc classes/src/ -n"
+        ],
+        "cpd": [
+            "phpcpd classes/src/ -n"
+        ]
+    },
+    "minimum-stability": "dev"
+}

+ 19 - 0
vendor/markbaker/matrix/examples/test.php

@@ -0,0 +1,19 @@
+<?php
+
+include __DIR__ . '/../classes/Bootstrap.php';
+
+$grid1 = [
+    [1, 3, 2],
+    [2, 3, 1],
+];
+
+$grid2 = [
+    [1, 6],
+    [0, 1],
+];
+
+$matrix = new Matrix\Matrix($grid1);
+
+$new = $matrix->directsum(new Matrix\Matrix($grid2));
+
+var_dump($new);

+ 25 - 0
vendor/markbaker/matrix/license.md

@@ -0,0 +1,25 @@
+The MIT License (MIT)
+=====================
+
+Copyright © `2018` `Mark Baker`
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the “Software”), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.

+ 3 - 0
vendor/phpoffice/phpspreadsheet/.gitattributes

@@ -0,0 +1,3 @@
+/tests export-ignore
+README.md export-ignore
+*.min.js binary

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.