فهرست منبع

Tworzenie XMLa dla analizy Benford'a

Mariusz Muszyński 7 سال پیش
والد
کامیت
e105c91725
2فایلهای تغییر یافته به همراه232 افزوده شده و 132 حذف شده
  1. 44 44
      SE/se-lib/Benford.php
  2. 188 88
      SE/se-lib/Route/UrlAction/BiAuditGenerate.php

+ 44 - 44
SE/se-lib/Benford.php

@@ -32,79 +32,79 @@ class Benford {
 		return log10(1 + 1 / $k);
 		return log10(1 + 1 / $k);
 	}
 	}
 
 
-	public function calculate($secondStage = true) {
-		return $this->calculateFirstStage($secondStage);
+	public function calculate($secondStep = true) {
+		return $this->calculateFirstStep($secondStep);
 	}
 	}
 
 
-	public function calculateFirstStage($secondStage = false) {
+	public function calculateFirstStep($secondStep = false) {
 		if ($this->array === null) return false;
 		if ($this->array === null) return false;
 		$this->benford = [];
 		$this->benford = [];
 
 
 		foreach ($this->array as $k => $v) {
 		foreach ($this->array as $k => $v) {
 			$s = (string) $v;
 			$s = (string) $v;
-			$this->benford['firstStage'][$s[0]]['keys'][] = $k;
+			$this->benford['firstStep'][$s[0]]['keys'][] = $k;
 		}
 		}
 
 
-		foreach ($this->benford['firstStage'] as $k => $v) {
-			$this->benford['firstStage'][$k]['count'] = count($v['keys']);
-			$this->benford['firstStage'][$k]['value'] = count($v['keys']) / count($this->array);
-			if ($this->benford['firstStage'][$k]['correct'] = ($this->benford['firstStage'][$k]['value'] <= self::benford($k))) {
-				unset($this->benford['firstStage'][$k]['keys']);
-			} elseif ($secondStage) {
-				$this->calculateSecondStage($k);
+		foreach ($this->benford['firstStep'] as $k => $v) {
+			$this->benford['firstStep'][$k]['count'] = count($v['keys']);
+			$this->benford['firstStep'][$k]['value'] = count($v['keys']) / count($this->array);
+			if ($this->benford['firstStep'][$k]['correct'] = ($this->benford['firstStep'][$k]['value'] <= self::benford($k))) {
+				unset($this->benford['firstStep'][$k]['keys']);
+			} elseif ($secondStep) {
+				$this->calculateSecondStep($k);
 			}
 			}
 		}
 		}
-		ksort($this->benford['firstStage']);
+		ksort($this->benford['firstStep']);
 
 
 		return true;
 		return true;
 	}
 	}
 
 
-	public function calculateSecondStage($a = null) {
+	public function calculateSecondStep($a = null) {
 		if ($a === null) {
 		if ($a === null) {
-			if (!isset($this->benford['firstStage'])) $this->calculate(false);
-			foreach ($this->benford['firstStage'] as $k => $v) {
-				if (!$v['correct']) $this->_calculateSecondStage($k);
+			if (!isset($this->benford['firstStep'])) $this->calculate(false);
+			foreach ($this->benford['firstStep'] as $k => $v) {
+				if (!$v['correct']) $this->_calculateSecondStep($k);
 			}
 			}
-		} else $this->_calculateSecondStage($a);
+		} else $this->_calculateSecondStep($a);
 	}
 	}
 
 
-	private function _calculateSecondStage($a) {
-		if (!isset($this->benford['firstStage'][$a]['keys'])) throw new Exception("Wrong data ({$a})");
-		foreach ($this->benford['firstStage'][$a]['keys'] as $k) {
+	private function _calculateSecondStep($a) {
+		if (!isset($this->benford['firstStep'][$a]['keys'])) throw new Exception("Wrong data ({$a})");
+		foreach ($this->benford['firstStep'][$a]['keys'] as $k) {
 			$s = (string) $this->array[$k];
 			$s = (string) $this->array[$k];
 			if (strlen($s) < 2) continue;
 			if (strlen($s) < 2) continue;
-			$this->benford['secondStage'][$a][$s[1]]['keys'][] = $k;
+			$this->benford['secondStep'][$a][$s[1]]['keys'][] = $k;
 		}
 		}
 
 
-		foreach ($this->benford['secondStage'][$a] as $k => $v) {
-			$this->benford['secondStage'][$a][$k]['count'] = count($v['keys']);
-			$this->benford['secondStage'][$a][$k]['value'] = count($v['keys']) / count($this->array);
-			if ($this->benford['secondStage'][$a][$k]['correct'] = ($this->benford['secondStage'][$a][$k]['value'] <= self::benford($a * 10 + $k))) {
-				unset($this->benford['secondStage'][$a][$k]['keys']);
+		foreach ($this->benford['secondStep'][$a] as $k => $v) {
+			$this->benford['secondStep'][$a][$k]['count'] = count($v['keys']);
+			$this->benford['secondStep'][$a][$k]['value'] = count($v['keys']) / count($this->array);
+			if ($this->benford['secondStep'][$a][$k]['correct'] = ($this->benford['secondStep'][$a][$k]['value'] <= self::benford($a * 10 + $k))) {
+				unset($this->benford['secondStep'][$a][$k]['keys']);
 			}
 			}
 		}
 		}
 
 
-		ksort($this->benford['secondStage'][$a]);
+		ksort($this->benford['secondStep'][$a]);
 	}
 	}
 
 
 	private function getResult($type = null, $k = null) {
 	private function getResult($type = null, $k = null) {
 		if ($type === null) throw new Exception("Wrong usage");
 		if ($type === null) throw new Exception("Wrong usage");
-		if ($this->benford === null) $this->calculateFirstStage();
+		if ($this->benford === null) $this->calculateFirstStep();
 		switch ($type) {
 		switch ($type) {
 			case 'all':
 			case 'all':
-			case 'secondStage':
-				if (!isset($this->benford['secondStage'])) $this->calculateSecondStage();
-			case 'firstStage':
+			case 'secondStep':
+				if (!isset($this->benford['secondStep'])) $this->calculateSecondStep();
+			case 'firstStep':
 				if ($type == 'all') return $this->benford;
 				if ($type == 'all') return $this->benford;
 				else return $this->benford[$type];
 				else return $this->benford[$type];
-			case 'secondStageItem':
+			case 'secondStepItem':
 				if ($k === null) throw new Exception("Missing parameter");
 				if ($k === null) throw new Exception("Missing parameter");
 				if (!is_int($k)) throw new Exception("Bad parameter - not integer ({$k})");
 				if (!is_int($k)) throw new Exception("Bad parameter - not integer ({$k})");
 				if ($k < 1 || $k > 9) throw new Exception("Bad parameter - not between 1 and 9 ({$k})");
 				if ($k < 1 || $k > 9) throw new Exception("Bad parameter - not between 1 and 9 ({$k})");
-				if (!isset($this->benford['secondStage'][$k])) throw new Exception("Wrong data");
-				return $this->benford['secondStage'][$k];
-			case 'badFirstStage':
-				return array_keys(array_filter($this->benford['firstStage'], function($v) {
+				if (!isset($this->benford['secondStep'][$k])) throw new Exception("Wrong data");
+				return $this->benford['secondStep'][$k];
+			case 'badFirstStep':
+				return array_keys(array_filter($this->benford['firstStep'], function($v) {
 					if (!$v['correct']) return true;
 					if (!$v['correct']) return true;
 				}));
 				}));
 			default: throw new Exception('Wrong usage');
 			default: throw new Exception('Wrong usage');
@@ -115,19 +115,19 @@ class Benford {
 		return $this->getResult('all');
 		return $this->getResult('all');
 	}
 	}
 
 
-	public function getFirstStage() {
-		return $this->getResult('firstStage');
+	public function getFirstStep() {
+		return $this->getResult('firstStep');
 	}
 	}
 
 
-	public function getSecondStage() {
-		return $this->getResult('secondStage');
+	public function getSecondStep() {
+		return $this->getResult('secondStep');
 	}
 	}
 
 
-	public function getSecondStageItem($k = null) {
-		return $this->getResult('secondStageItem', $k);
+	public function getSecondStepItem($k = null) {
+		return $this->getResult('secondStepItem', $k);
 	}
 	}
 
 
-	public function getBadFirstStage() {
-		return $this->getResult('badFirstStage');
+	public function getBadFirstStep() {
+		return $this->getResult('badFirstStep');
 	}
 	}
 }
 }

+ 188 - 88
SE/se-lib/Route/UrlAction/BiAuditGenerate.php

@@ -1103,9 +1103,52 @@ function validateCompany(source) {
 		}
 		}
 	}
 	}
 
 
+	private function benford_getDetails($a = null, $b = null) {
+                try {
+			if (!($benford = V::get('benford', '', $_SESSION))) throw new Exception("Nieznany błąd wewnętrzny #1");
+			if (isset($benford[$this->SOURCE['TABLE']]['details'][$a][$b])) throw new Exception(@gzuncompress($benford[$this->SOURCE['TABLE']]['details'][$a][$b]));
+			if (!($benford = @unserialize(@gzuncompress($benford[$this->SOURCE['TABLE']]['data'])))) throw new Exception("Nieznany błąd wewnętrzny #2");
+			if (!($groupField = V::get('_benfordGroupField', '', $_GET))) throw new Exception("Brak konfiguracji kolumny grupującej");
+			if ($a === null) throw new Exception("Nieznany błąd wewnętrzny #3");
+			if ($b === null) {
+				if (!isset($benford['firstStep'][$a]['keys'])) throw new Exception("Nieznany błąd wewnętrzny #4");
+				$keys = $benford['firstStep'][$a]['keys'];
+			} else {
+				if (!isset($benford['secondStep'][$a][$b]['keys'])) throw new Exception("Nieznany błąd wewnętrzny #5");
+				$keys = $benford['secondStep'][$a][$b]['keys'];
+			}
+
+			$tempTable = uniqid('_temp_benford_ids_');
+			DB::getPDO()->query("create temporary table `{$tempTable}` (`ID` int(11) NOT NULL, UNIQUE KEY `ID` (`ID`))");
+			foreach (array_chunk($keys, 100) as $ids) {
+                       	        DB::getPDO()->query("insert into `{$tempTable}` values (" . implode('),(', $ids) . ")");
+			}
+			$query = "select `table`.`{$groupField}` as `field`, count(*) as `count` from `{$this->SOURCE['TABLE']}` `table` join `{$tempTable}` `temp` on `table`.`ID` = `temp`.`ID` where coalesce(`table`.`{$groupField}`,'') != '' group by `table`.`{$groupField}` having `count` > 1 order by `count` desc limit 10";
+			try {
+				$result = DB::getPDO()->fetchAll($query);
+			} catch (Exception $e) {
+				throw new Exception("Nieznany błąd, prawdopodobnie błędna konfiguracja kolumny grupującej");
+			}
+			$showDetails = "<h4>Najczęściej występujące wartości kolumny {$groupField}</h4>";
+			if ($result) {
+				$showDetails .= "<table class=\"table table-bordered table-hover table-striped table-condensed\"><thead><tr style=\"font-weight:bold;\"><td>Wartość</td><td>Liczba wystąpień</td><td>Procent występowania</td></tr></thead><tbody>";
+				$showDetails .= implode('', array_map(function($v) use ($keys) {
+					return "<tr><td>{$v['field']}</td><td>{$v['count']}</td><td>" . number_format(round($v['count'] / count($keys) * 100, 3), 3, ',', '') . "</td></tr>";
+				}, $result));
+				$showDetails .= "</tbody></table>";
+			} else {
+				$showDetails .= "<h5>Żadna wartość nie występuje wiele razy</h5>";
+			}
+		} catch (Exception $e) {
+			$showDetails = $e->getMessage();
+		}
+		$_SESSION['benford'][$this->SOURCE['TABLE']]['details'][$a][$b] = gzcompress($showDetails);
+		$showDetails .= '<button type="submit" class="btn btn-primary btn-sm" onClick="hideDetails()">Zamknij</button>';
+		return $showDetails;
+	}
+
 	private function benford_form($edit = false) {
 	private function benford_form($edit = false) {
 		if (!($valueField = V::get('_benfordValueField', '', $_GET))) throw new Exception ("Błąd konfiguracji UrlAction - brak parametru _benfordField (DANE )");
 		if (!($valueField = V::get('_benfordValueField', '', $_GET))) throw new Exception ("Błąd konfiguracji UrlAction - brak parametru _benfordField (DANE )");
-		$groupField = V::get('_benfordGroupField', '', $_GET);
 		if (!($namespace = V::get('_fromNamespace', '', $_GET))) throw new Exception("Błąd formularza");
 		if (!($namespace = V::get('_fromNamespace', '', $_GET))) throw new Exception("Błąd formularza");
 
 
 		Lib::loadClass('FeatureAttrSelected');
 		Lib::loadClass('FeatureAttrSelected');
@@ -1125,12 +1168,14 @@ function validateCompany(source) {
 		try {
 		try {
 			$benfordObj = new Benford($values);
 			$benfordObj = new Benford($values);
 			$benford = $benfordObj->getAllResult();
 			$benford = $benfordObj->getAllResult();
+			$_SESSION['benford'][$this->SOURCE['TABLE']] = ['data' => gzcompress(serialize($benford))];
 		} catch (Exception $e) {
 		} catch (Exception $e) {
 			die($e->getMessage());
 			die($e->getMessage());
 		}
 		}
 ?>
 ?>
 <div class="container" style="margin-top:20px">
 <div class="container" style="margin-top:20px">
   <form method="post">
   <form method="post">
+    <input type="hidden" name="count" value="<?=count($values)?>">
     <legend>
     <legend>
       Analiza rozkładu Benford'a
       Analiza rozkładu Benford'a
       <span class="pull-right">Tabela: <?=$this->SOURCE['TABLE']?></span>
       <span class="pull-right">Tabela: <?=$this->SOURCE['TABLE']?></span>
@@ -1148,7 +1193,7 @@ function validateCompany(source) {
           <table>
           <table>
             <tr>
             <tr>
               <td>
               <td>
-                <select name="stage" class="form-control" onChange="toggleStage(this)">
+                <select name="step" class="form-control" onChange="toggleStep(this)">
                   <option value="first" selected>Pierwszy stopień analizy</option>
                   <option value="first" selected>Pierwszy stopień analizy</option>
                   <option value="second">Drugi stopień analizy</option>
                   <option value="second">Drugi stopień analizy</option>
                 </select>
                 </select>
@@ -1191,79 +1236,46 @@ function validateCompany(source) {
 		return number_format($n, 3, ',', '');
 		return number_format($n, 3, ',', '');
 	};
 	};
 
 
-	$genShowDetails = function($a, $groupField) use ($number_format) {
-		try {
-			if (!$groupField) throw new Exception("Brak konfiguracji kolumny grupującej");
-			$tempTable = uniqid('_temp_benford_ids_');
-			DB::getPDO()->query("create temporary table `{$tempTable}` (`ID` int(11) NOT NULL, UNIQUE KEY `ID` (`ID`))");
-			foreach (array_chunk($a, 100) as $ids) {
-				DB::getPDO()->query("insert into `{$tempTable}` values (" . implode('),(', $ids) . ")");
-			}
-			$query = "select `table`.`{$groupField}` as `field`, count(*) as `count` from `{$this->SOURCE['TABLE']}` `table` join `{$tempTable}` `temp` on `table`.`ID` = `temp`.`ID` where coalesce(`table`.`{$groupField}`,'') != '' group by `table`.`{$groupField}` having `count` > 1 order by `count` desc limit 10";
-			try {
-				$result = DB::getPDO()->fetchAll($query);
-			} catch (Exception $e) {
-				throw new Exception("Nieznany błąd, prawdopodobnie błędna konfiguracja kolumny grupującej");
-			}
-			$showDetails = "<h4>Najczęściej występujące wartości kolumny {$groupField}</h4>";
-			if ($result) {
-				$showDetails .= "<table class=\"table table-bordered table-hover table-striped table-condensed\"><thead><tr style=\"font-weight:bold;\"><td>Wartość</td><td>Liczba wystąpień</td><td>Procent występowania</td></tr></thead><tbody>";
-				$showDetails .= implode('', array_map(function($v) use ($a, $number_format){
-					return "<tr><td>{$v['field']}</td><td>{$v['count']}</td><td>" . $number_format(round($v['count'] / count($a) * 100, 3)) . "</td></tr>";
-				}, $result));
-				$showDetails .= "</tbody></table>";
-			} else {
-				$showDetails .= "<h5>Żadna wartość nie występuje wiele razy</h5>";
-			}
-		} catch (Exception $e) {
-			$showDetails = $e->getMessage();
-		}
-		$showDetails .= '<button type="submit" class="btn btn-primary btn-sm" onClick="hideAlert()">Zamknij</button>';
-		return htmlentities($showDetails);
-	};
-
 	for ($ka = 1; $ka < 10; $ka++) {
 	for ($ka = 1; $ka < 10; $ka++) {
-		if (!isset($benford['firstStage'][$ka])) $benford['firstStage'][$ka] = ['count' => 0, 'value' => 0, 'correct' => true];
-		$va = $benford['firstStage'][$ka];
+		if (!isset($benford['firstStep'][$ka])) $benford['firstStep'][$ka] = ['count' => 0, 'value' => 0, 'correct' => true];
+		$va = $benford['firstStep'][$ka];
 		$odchylenie = round(($va['value'] / Benford::benford($ka) - 1) * 100, 3);
 		$odchylenie = round(($va['value'] / Benford::benford($ka) - 1) * 100, 3);
 		if ($odchylenie > 0) $odchylenie = "+" . $number_format($odchylenie);
 		if ($odchylenie > 0) $odchylenie = "+" . $number_format($odchylenie);
 		else $odchylenie = $number_format($odchylenie);
 		else $odchylenie = $number_format($odchylenie);
-		if (!$va['correct']) $showDetails = $genShowDetails($va['keys'], $groupField);
 ?>
 ?>
-            <tr style="text-align:center; font-weight:bold;<?=$va['correct'] ? '' : ' cursor:pointer;'?>"<?=$va['correct'] ? '' : ' onClick="toggleSecondStage(' . $ka . ');"'?>>
-              <td style="text-align:left" class="stage1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$ka?></td>
-              <td class="stage1-<?=$va['correct'] ? 'green' : 'red'?>">I</td>
-              <td style="text-align:right" class="stage1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$va['count']?></td>
-              <td style="text-align:right" class="stage1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$number_format(round($va['value'] * 100, 3))?></td>
-              <td style="text-align:right" class="stage1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$number_format(round(Benford::benford($ka) * 100, 3))?></td>
-              <td style="text-align:right" class="stage1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$odchylenie?></td>
-              <td <?=$va['correct'] ? 'class="stage1-green">Tak' : 'class="stage1-red" name="firstStageDesc" data-ka="' . $ka . '" nowrap>Nie (rozwiń)'?></td>
-              <td<?=$va['correct'] ? '>' : ' onClick="showAlert(\''. $showDetails .'\')"><span class="glyphicon glyphicon-search"></span>'?></td>
+            <tr style="text-align:center; font-weight:bold;<?=$va['correct'] ? '' : ' cursor:pointer;'?>"<?=$va['correct'] ? '' : ' onClick="toggleSecondStep(' . $ka . ');"'?>>
+              <td style="text-align:left" class="step1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$ka?></td>
+              <td class="step1-<?=$va['correct'] ? 'green' : 'red'?>">I</td>
+              <td style="text-align:right" class="step1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$va['count']?></td>
+              <td style="text-align:right" class="step1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$number_format(round($va['value'] * 100, 3))?></td>
+              <td style="text-align:right" class="step1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$number_format(round(Benford::benford($ka) * 100, 3))?></td>
+              <td style="text-align:right" class="step1-<?=$va['correct'] ? 'green' : 'red'?>"><?=$odchylenie?></td>
+              <td <?=$va['correct'] ? 'class="step1-green">Tak' : 'class="step1-red" name="firstStepDesc" data-ka="' . $ka . '" nowrap>Nie (rozwiń)'?></td>
+              <td<?=$va['correct'] ? '>' : ' onClick="showDetails(' . $ka . ', 0)"><span class="glyphicon glyphicon-search"></span>'?></td>
 <?php if($edit):?>
 <?php if($edit):?>
-              <td<?=$va['correct'] ? '' : ' onClick="_click(\'checkFirstStage_' . $ka . '\')"'?>><input type="checkbox" <?=$va['correct'] ? 'disabled' : 'checked id="checkFirstStage_' . $ka . '" name="checkFirstStage[]" value="' . $ka . '" onClick="toggleCheckFirst(this)"'?>></td>
+              <td<?=$va['correct'] ? '' : ' onClick="_click(\'checkFirstStep_' . $ka . '\')"'?>><input type="checkbox" <?=$va['correct'] ? 'disabled' : 'checked id="checkFirstStep_' . $ka . '" name="checkFirstStep[]" value="' . $ka . '" onClick="toggleCheckFirst(this)"'?>></td>
 <?php endif;?>
 <?php endif;?>
             </tr>
             </tr>
 <?php
 <?php
 		if (!$va['correct']) {
 		if (!$va['correct']) {
 			for ($kb = 0; $kb < 10; $kb++) {
 			for ($kb = 0; $kb < 10; $kb++) {
-				if (!isset($benford['secondStage'][$ka][$kb])) $benford['secondStage'][$ka][$kb] = ['count' => 0, 'value' => 0, 'correct' => true];
-				$vb = $benford['secondStage'][$ka][$kb];
+				if (!isset($benford['secondStep'][$ka][$kb])) $benford['secondStep'][$ka][$kb] = ['count' => 0, 'value' => 0, 'correct' => true];
+				$vb = $benford['secondStep'][$ka][$kb];
 				$odchylenie = round(($vb['value'] / Benford::benford($ka * 10 + $kb) - 1) * 100, 3);
 				$odchylenie = round(($vb['value'] / Benford::benford($ka * 10 + $kb) - 1) * 100, 3);
 				if ($odchylenie > 0) $odchylenie = "+" . $number_format($odchylenie);
 				if ($odchylenie > 0) $odchylenie = "+" . $number_format($odchylenie);
 				else $odchylenie = $number_format($odchylenie);
 				else $odchylenie = $number_format($odchylenie);
-				if (!$vb['correct']) $showDetails = $genShowDetails($vb['keys'], $groupField);
 ?>
 ?>
-            <tr style="text-align:center;" name="secondStage" data-ka="<?=$ka?>" hidden>
-              <td style="text-align:left" class="stage2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$ka . $kb?></td>
-              <td class="stage2-<?=$vb['correct'] ? 'green' : 'red'?>">II</td>
-              <td style="text-align:right" class="stage2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$vb['count']?></td>
-              <td style="text-align:right" class="stage2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$number_format(round($vb['value'] * 100, 3))?></td>
-              <td style="text-align:right" class="stage2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$number_format(round(Benford::benford($ka * 10 + $kb) * 100, 3))?></td>
-              <td style="text-align:right" class="stage2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$odchylenie?></td>
-              <td class="stage2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$vb['correct'] ? 'Tak' : 'Nie'?></td>
-              <td<?=$vb['correct'] ? '>' : ' style="cursor:pointer;" onClick="showAlert(\''. $showDetails .'\')"><span class="glyphicon glyphicon-search"></span>'?></td>
+            <tr style="text-align:center;" name="secondStep" data-ka="<?=$ka?>" hidden>
+              <td style="text-align:left" class="step2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$ka . $kb?></td>
+              <td class="step2-<?=$vb['correct'] ? 'green' : 'red'?>">II</td>
+              <td style="text-align:right" class="step2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$vb['count']?></td>
+              <td style="text-align:right" class="step2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$number_format(round($vb['value'] * 100, 3))?></td>
+              <td style="text-align:right" class="step2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$number_format(round(Benford::benford($ka * 10 + $kb) * 100, 3))?></td>
+              <td style="text-align:right" class="step2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$odchylenie?></td>
+              <td class="step2-<?=$vb['correct'] ? 'green' : 'red'?>"><?=$vb['correct'] ? 'Tak' : 'Nie'?></td>
+              <td<?=$vb['correct'] ? '>' : ' style="cursor:pointer;" onClick="showDetails(' . "{$ka}, {$kb}" . ')"><span class="glyphicon glyphicon-search"></span>'?></td>
 <?php if($edit):?>
 <?php if($edit):?>
-              <td<?=$vb['correct'] ? '' : ' style="cursor:pointer;" onClick="_click(\'checkSecondStage_' . $ka . $kb . '\')"'?>><input type="checkbox"<?=$vb['correct'] ?: ' checked id="checkSecondStage_' . $ka . $kb . '" name="checkSecondStage[]" value="' . $ka . $kb . '" onClick="toggleCheckSecond(this)"'?> disabled></td>
+              <td<?=$vb['correct'] ? '' : ' style="cursor:pointer;" onClick="_click(\'checkSecondStep_' . $ka . $kb . '\')"'?>><input type="checkbox"<?=$vb['correct'] ?: ' checked id="checkSecondStep_' . $ka . $kb . '" name="checkSecondStep[]" value="' . $ka . $kb . '" onClick="toggleCheckSecond(this)"'?> disabled></td>
 <?php endif;?>
 <?php endif;?>
             </tr>
             </tr>
 <?php
 <?php
@@ -1277,38 +1289,48 @@ function validateCompany(source) {
     </div>
     </div>
   </form>
   </form>
 </div>
 </div>
-<div id="alert" onClick="hideAlert();">
-  <div id="alertMsg" onClick="event.stopPropagation();"></div>
+<div id="details" onClick="hideDetails();">
+  <div id="detailsMsg" onClick="event.stopPropagation();"></div>
 </div>
 </div>
 <style type="text/css">
 <style type="text/css">
 <!--
 <!--
-#benford .stage1-green,#benford .stage1-red {font-weight:bold;}
-#benford .stage1-green,#benford .stage2-green {color:#008800;}
-#benford .stage1-red,#benford .stage2-red {color:#ff0000;}
+#benford .step1-green,#benford .step1-red {font-weight:bold;}
+#benford .step1-green,#benford .step2-green {color:#008800;}
+#benford .step1-red,#benford .step2-red {color:#ff0000;}
 #benford table { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;}
 #benford table { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;}
 td {font-size: 12px;}
 td {font-size: 12px;}
 #benford ::selection {background: transparent;}
 #benford ::selection {background: transparent;}
-#alert {display:none; position: fixed; left: 0; top: 0; width: 100%; height: 100%; text-align: center; z-index: 1000; background-color: rgba(0,0,0,0.5);}
-#alert div {width: 500px; height: auto; margin: 100px auto; background: #fff; padding: 10px; text-align: center; overflow: hidden;}
+#details {display:none; position: fixed; left: 0; top: 0; width: 100%; height: 100%; text-align: center; z-index: 1000; background-color: rgba(0,0,0,0.5);}
+#details div {width: 500px; height: auto; margin: 100px auto; background: #fff; padding: 10px; text-align: center; overflow: hidden;}
 -->
 -->
 </style>
 </style>
-<script src="static/sweetalert2.min.js"></script>
 <script language="JavaScript">
 <script language="JavaScript">
 <!--
 <!--
-function showAlert(s) {
+function showDetails(ka, kb) {
   event.stopPropagation();
   event.stopPropagation();
-  document.getElementById('alertMsg').innerHTML = s;
-  document.getElementById('alert').style.display = 'block';
+  document.getElementById('detailsMsg').innerHTML = "<h4>Proszę czekać...</h4>";
+  document.getElementById('details').style.display = 'block';
+  var post = "_noMenu=1&action=getDetails&_ka=" + ka;
+  if (kb) post += "&_kb=" + kb;
+  var xhttp = new XMLHttpRequest();
+  xhttp.open("POST", '', true);
+  xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+  xhttp.onreadystatechange = function() {
+    if (this.readyState == 4 && this.status == 200) {
+      document.getElementById('detailsMsg').innerHTML = this.responseText;
+    }
+  }
+  xhttp.send(post);
 }
 }
-function hideAlert() {
-  document.getElementById('alert').style.display = 'none';
+function hideDetails() {
+  document.getElementById('details').style.display = 'none';
 }
 }
 function _click(id) {
 function _click(id) {
   event.stopPropagation();
   event.stopPropagation();
   document.getElementById(id).click();
   document.getElementById(id).click();
 }
 }
-function toggleSecondStage(ka) {
-  var rows = document.getElementsByName('secondStage');
+function toggleSecondStep(ka) {
+  var rows = document.getElementsByName('secondStep');
   var hidden = false;
   var hidden = false;
   for(var i = 0, n = rows.length; i < n; i++) {
   for(var i = 0, n = rows.length; i < n; i++) {
     if (rows[i].dataset.ka == ka) {
     if (rows[i].dataset.ka == ka) {
@@ -1316,21 +1338,21 @@ function toggleSecondStage(ka) {
       hidden = rows[i].hidden;
       hidden = rows[i].hidden;
     }
     }
   }
   }
-  var descs = document.getElementsByName('firstStageDesc');
+  var descs = document.getElementsByName('firstStepDesc');
   for(var i = 0, n = descs.length; i < n; i++) {
   for(var i = 0, n = descs.length; i < n; i++) {
     if (descs[i].dataset.ka == ka) {
     if (descs[i].dataset.ka == ka) {
       descs[i].innerHTML = (hidden ? 'Nie (rozwiń)' : 'Nie (zwiń)');
       descs[i].innerHTML = (hidden ? 'Nie (rozwiń)' : 'Nie (zwiń)');
     }
     }
   }
   }
 }
 }
-function toggleStage(option) {
+function toggleStep(option) {
   if (option.value == 'first') first = true;
   if (option.value == 'first') first = true;
   else if (option.value == 'second') first = false;
   else if (option.value == 'second') first = false;
   else {
   else {
     alert('Wystąpił nieznany błąd formularza');
     alert('Wystąpił nieznany błąd formularza');
     return;
     return;
   }
   }
-  var checks = document.getElementsByName('checkSecondStage[]');
+  var checks = document.getElementsByName('checkSecondStep[]');
   var all = [];
   var all = [];
   for(var i = 0, n = checks.length; i < n; i++) {
   for(var i = 0, n = checks.length; i < n; i++) {
     checks[i].disabled = first;
     checks[i].disabled = first;
@@ -1338,7 +1360,7 @@ function toggleStage(option) {
     if (all[ka] === 'undefined') all[ka] = checks[i].checked;
     if (all[ka] === 'undefined') all[ka] = checks[i].checked;
     else if (checks[i].checked) all[ka] = true;
     else if (checks[i].checked) all[ka] = true;
   }
   }
-  var checks = document.getElementsByName('checkFirstStage[]');
+  var checks = document.getElementsByName('checkFirstStep[]');
   for(var i = 0, n = checks.length; i < n; i++) {
   for(var i = 0, n = checks.length; i < n; i++) {
     checks[i].disabled = !(first);
     checks[i].disabled = !(first);
     if (checks[i].checked != all[checks[i].value]) {
     if (checks[i].checked != all[checks[i].value]) {
@@ -1346,25 +1368,25 @@ function toggleStage(option) {
       toggleCheckFirst(checks[i]);
       toggleCheckFirst(checks[i]);
     }
     }
   }
   }
-  var descs = document.getElementsByName('firstStageDesc');
+  var descs = document.getElementsByName('firstStepDesc');
   for(var i = 0, n = descs.length; i < n; i++) {
   for(var i = 0, n = descs.length; i < n; i++) {
     descs[i].innerHTML = (first ? 'Nie (rozwiń)' : 'Nie (zwiń)');
     descs[i].innerHTML = (first ? 'Nie (rozwiń)' : 'Nie (zwiń)');
   }
   }
-  var rows = document.getElementsByName('secondStage');
+  var rows = document.getElementsByName('secondStep');
   for(var i = 0, n = rows.length; i < n; i++) {
   for(var i = 0, n = rows.length; i < n; i++) {
     rows[i].hidden = first;
     rows[i].hidden = first;
   }
   }
 }
 }
 function toggleCheckFirst(check) {
 function toggleCheckFirst(check) {
   event.stopPropagation();
   event.stopPropagation();
-  var checks = document.getElementsByName('checkSecondStage[]');
+  var checks = document.getElementsByName('checkSecondStep[]');
   for(var i = 0, n = checks.length; i < n; i++) {
   for(var i = 0, n = checks.length; i < n; i++) {
     if ((checks[i].value / 10 | 0) == check.value) checks[i].checked = check.checked;
     if ((checks[i].value / 10 | 0) == check.value) checks[i].checked = check.checked;
   }
   }
 }
 }
 function toggleCheckSecond(check) {
 function toggleCheckSecond(check) {
   event.stopPropagation();
   event.stopPropagation();
-  var checks = document.getElementsByName('checkSecondStage[]');
+  var checks = document.getElementsByName('checkSecondStep[]');
   var all = true;
   var all = true;
   var ka = check.value / 10 | 0;
   var ka = check.value / 10 | 0;
   for(var i = 0, n = checks.length; i < n; i++) {
   for(var i = 0, n = checks.length; i < n; i++) {
@@ -1375,7 +1397,7 @@ function toggleCheckSecond(check) {
       }
       }
     }
     }
   }
   }
-  var checks = document.getElementsByName('checkFirstStage[]');
+  var checks = document.getElementsByName('checkFirstStep[]');
   for(var i = 0, n = checks.length; i < n; i++) {
   for(var i = 0, n = checks.length; i < n; i++) {
     if (checks[i].value == ka) {
     if (checks[i].value == ka) {
       checks[i].checked = all;
       checks[i].checked = all;
@@ -1389,8 +1411,76 @@ function toggleCheckSecond(check) {
 	}
 	}
 
 
 	private function benford_generate() {
 	private function benford_generate() {
-		SE_Layout::alert('warning', 'Not implemented yet');
+		$benford = @unserialize(@gzuncompress(V::get('benford', '', $_SESSION)[$this->SOURCE['TABLE']]['data']));
+		unset($_SESSION['benford'][$this->SOURCE['TABLE']]);
+		if (!$benford) {
+			$this->benford_form(true);
+			return;
+		}
+
+		$root = 'RelatedFeatureRoot';
+		$namespace = 'BI_audit_BENFORD';
+		$array = [];
+		$array['@attributes'] = ['xmlns:system_cache__dita' => 'http://biuro.biall-net.pl/xmlschema_procesy5/default_db_xml_cache/dita.xsd'];
+		$array[$namespace] = [
+			'@attributes' => ['fid' => "{$namespace}.1"],
+			'ID' => 1,
+			'L_APPOITMENT_INFO' => V::get('L_APPOITMENT_INFO', '', $_POST),
+			'step' => V::get('step', '', $_POST),
+			'table' => $this->SOURCE['TABLE'],
+			'count' => V::get('count', '', $_POST),
+		];
+
+		$firstStep = [];
+		for ($ka = 1; $ka <= 9; $ka++) {
+			if (!isset($benford['firstStep'][$ka])) $va = ['count' => 0, 'value' => 0, 'correct' => true];
+			else $va = $benford['firstStep'][$ka];
+			$_firstStep = [
+				'@attributes' => ['leadingNumber' => $ka],
+				'count' => $va['count'],
+				'value' => $va['value'],
+				'correct' => $va['correct'] ? 'true' : 'false'
+			];
+			if ($array[$namespace]['step'] == 'second') {
+				$secondStep = [];
+				for ($kb = 0; $kb <= 9; $kb++) {
+					if (!isset($benford['secondStep'][$ka][$kb])) $vb = ['count' => 0, 'value' => 0, 'correct' => true];
+					else $vb = $benford['secondStep'][$ka][$kb];
+					$_secondStep = [
+						'@attributes' => ['leadingNumber' => $ka.$kb],
+						'count' => $vb['count'],
+						'value' => $vb['value'],
+						'correct' => $vb['correct'] ? 'true' : 'false'
+					];
+					if (!$vb['correct']) {
+						$objects = [];
+						foreach ($benford['secondStep'][$ka][$kb]['keys'] as $id) {
+							$object = DB::getPDO()->fetchFirst("select * from `{$this->SOURCE['TABLE']}` where `ID` = " . DB::getPDO()->quote($id));
+							if (!$object) continue;
+							$objects[] = array_merge(['@attributes' => ['fid' => "{$this->SOURCE['TABLE']}.{$id}"]], $object);
+						}
+						$_secondStep[$this->SOURCE['TABLE']][] = $objects;
+					}
+					$secondStep[] = $_secondStep;
+				}
+				$_firstStep['secondStep'] = $secondStep;
+			} elseif (!$va['correct']) {
+				$objects = [];
+				foreach ($benford['firstStep'][$ka]['keys'] as $id) {
+					$object = DB::getPDO()->fetchFirst("select * from `{$this->SOURCE['TABLE']}` where `ID` = " . DB::getPDO()->quote($id));
+					if (!$object) continue;
+					$objects[] = array_merge(['@attributes' => ['fid' => "{$this->SOURCE['TABLE']}.{$id}"]], $object);
+				}
+				$_firstStep[$this->SOURCE['TABLE']][] = $objects;
+			}
+			$firstStep[] = $_firstStep;
+		}
+		$array[$namespace]['firstStep'] = $firstStep;
+
+		$xml = V::arrayToXML($array, true, $root);
+		file_put_contents("/tmp/benford_{$array[$namespace]['step']}Step.xml", $xml);
 ?>
 ?>
+<pre><?//=htmlspecialchars($xml)?></pre>
 <br><br>
 <br><br>
 <div style="text-align:center">
 <div style="text-align:center">
   <a href="<?=$this->REFERER?>" class="btn btn-default" style="width: 80px;">Powrót</a>
   <a href="<?=$this->REFERER?>" class="btn btn-default" style="width: 80px;">Powrót</a>
@@ -1405,6 +1495,11 @@ function toggleCheckSecond(check) {
 				case "generate":
 				case "generate":
 					$this->benford_generate();
 					$this->benford_generate();
 					break;
 					break;
+				case "getDetails":
+					$ka = V::get('_ka', null, $_POST, 'int');
+					$kb = V::get('_kb', null, $_POST, 'int');
+					echo $this->benford_getDetails($ka, $kb);
+					break;
 				default:
 				default:
 					$this->benford_form(true);
 					$this->benford_form(true);
 			}
 			}
@@ -1414,8 +1509,11 @@ function toggleCheckSecond(check) {
 	}
 	}
 
 
 	public function defaultAction() {
 	public function defaultAction() {
-		SE_Layout::gora();
-		SE_Layout::menu();
+		$showMenu = !(V::get('_noMenu', false, $_POST));
+		if ($showMenu) {
+			SE_Layout::gora();
+			SE_Layout::menu();
+		}
 		if (isset($_SESSION['REFERER'])) {
 		if (isset($_SESSION['REFERER'])) {
 			$this->REFERER = $_SESSION['REFERER'];
 			$this->REFERER = $_SESSION['REFERER'];
 			unset($_SESSION['REFERER']);
 			unset($_SESSION['REFERER']);
@@ -1502,8 +1600,10 @@ function toggleCheckSecond(check) {
 			}
 			}
 		}
 		}
 		else SE_Layout::alert('danger', 'Błąd parametru #0');
 		else SE_Layout::alert('danger', 'Błąd parametru #0');
-		echo "<br/><br/>";
-		SE_Layout::dol();
+		if ($showMenu) {
+			echo "<br/><br/>";
+			SE_Layout::dol();
+		}
 	}
 	}
 
 
 	private static function truncatePowiazaniaFromDB($ID) {
 	private static function truncatePowiazaniaFromDB($ID) {