Browse Source

Merge branch 'master' of https://github.com/visuddhinanda/mint

visuddhinanda 4 years ago
parent
commit
a11198c219
48 changed files with 1085 additions and 252 deletions
  1. 2 1
      .gitignore
  2. 2 2
      app/article/mobile.css
  3. 11 1
      app/config.sample.php
  4. 75 68
      app/install/db_insert_bold.php
  5. 1 0
      app/path.sample.php
  6. 11 11
      app/search/bold_search.php
  7. 0 102
      app/statistics/_pdo.php
  8. 20 17
      app/statistics/index.php
  9. 5 5
      app/tools/pc_word_analysis.php
  10. 1 1
      app/users_guide/zh-cn/grammar_aor.md
  11. 6 0
      db/sqlite/bold/down.sql
  12. 23 0
      db/sqlite/bold/up.sql
  13. 4 0
      db/sqlite/word_statistics/down.sql
  14. 19 0
      db/sqlite/word_statistics/up.sql
  15. 1 0
      deploy/.gitignore
  16. 0 0
      deploy/.txt
  17. 32 0
      deploy/README.md
  18. 9 0
      deploy/group_vars/all.yml
  19. 2 0
      deploy/group_vars/nano_pi.yml
  20. 1 0
      deploy/group_vars/orange_pi.yml
  21. 1 0
      deploy/group_vars/raspbarry_pi.yml
  22. 71 0
      deploy/migaration/word_statistics.php
  23. 12 0
      deploy/mint.yml
  24. 0 33
      deploy/php.sh
  25. 4 0
      deploy/ping.yml
  26. 21 0
      deploy/roles/os/tasks/init.yml
  27. 42 0
      deploy/roles/os/tasks/main.yml
  28. 22 0
      deploy/roles/os/tasks/sshd.yml
  29. 80 0
      deploy/roles/os/tasks/ulimits.yml
  30. 1 0
      deploy/roles/os/templates/sudo.conf.j2
  31. 32 0
      deploy/roles/php/tasks/main.yml
  32. 6 0
      deploy/roles/ping/tasks/main.yml
  33. 30 0
      deploy/roles/python3/roles/main.yml
  34. 5 0
      deploy/roles/reboot/tasks/main.yml
  35. 15 0
      deploy/roles/ubuntu/tasks/armbian.yml
  36. 14 0
      deploy/roles/ubuntu/tasks/clean.yml
  37. 60 0
      deploy/roles/ubuntu/tasks/friendly-core.yml
  38. 38 0
      deploy/roles/ubuntu/tasks/locales.yml
  39. 166 0
      deploy/roles/ubuntu/tasks/main.yml
  40. 133 0
      deploy/roles/ubuntu/tasks/pi.yml
  41. 52 0
      deploy/roles/ubuntu/tasks/raspbian.yml
  42. 26 0
      deploy/roles/ubuntu/tasks/zsh.yml
  43. 1 0
      deploy/staging/.gitignore
  44. 14 0
      deploy/staging/hosts
  45. 4 7
      docker/README.md
  46. 0 2
      docker/first.sh
  47. 0 2
      docker/next.sh
  48. 10 0
      docker/start.sh

+ 2 - 1
.gitignore

@@ -25,4 +25,5 @@
 /node_modules/
 
 # vi
-.swap
+.swap
+.env

+ 2 - 2
app/article/mobile.css

@@ -71,10 +71,10 @@ note:hover .ref {
 }
 .right_float_min #right_float_pannal {
     position: fixed;
-    top: 30%;
+    top: 60%;
     left: 0;
     width: 100%;
-    height: 70%;
+    height: 40%;
 }
 #head_nav_right{
 	flex-direction: column;

+ 11 - 1
app/config.sample.php

@@ -32,9 +32,19 @@ define("Database",[
 	"name"=>"mint",
 	"sslmode" => "disable",
 	"user" => "postgres",
-	"password" => ""
+	"password" => "123456"
 ]);
 
+#数据库
+# 数据库基本参数 pgsql sqlite
+define("_DB_ENGIN_", "pgsql");
+define("_DB_HOST_", "localhost");
+define("_DB_NAME_", "mint");
+define("_DB_PORT_", "5432");
+define("_DB_USERNAME_", "postgres");
+define("_DB_PASSWORD_", "123456");
+
+
 /*
 Redis 设置,
 使用集群

+ 75 - 68
app/install/db_insert_bold.php

@@ -12,8 +12,8 @@ require_once "install_head.php";
 生成黑体字数据库。黑体字多数是义注复注里的单词(尤其是专有名词)解释。
 </div>
 <?php
-include "./_pdo.php";
-include "../path.php";
+require_once "./_pdo.php";
+require_once "../path.php";
 
 if (isset($_GET["from"]) == false) {
     ?>
@@ -26,8 +26,8 @@ To: <input type="text" name="to" value="216"><br>
 return;
 }
 
-$from = $_GET["from"];
-$to = $_GET["to"];
+$from = (int)$_GET["from"];
+$to = (int)$_GET["to"];
 $filelist = array();
 $fileNums = 0;
 $log = "";
@@ -84,8 +84,8 @@ echo "doing:" . $xmlfile . "<br>";
 $log = $log . "$from,$FileName,open\r\n";
 
 $arrInserString = array();
-$db_file = _FILE_DB_BOLD_;
-PDO_Connect("$db_file");
+
+
 
 // 打开文件并读取数据
 if (($fp = fopen($dirXmlBase . $dirXml . $outputFileNameHead . ".csv", "r")) !== false) {
@@ -95,73 +95,80 @@ if (($fp = fopen($dirXmlBase . $dirXml . $outputFileNameHead . ".csv", "r")) !==
     }
     fclose($fp);
     echo "单词表load:" . $dirXmlBase . $dirXml . $outputFileNameHead . ".csv<br>";
+
+	PDO_Connect(_FILE_DB_BOLD_);
+
+	$query = "DELETE FROM "._TABLE_WORD_BOLD_." WHERE book=?";
+	PDO_Execute($query,array($from+1));
+	// 开始一个事务,关闭自动提交
+	$PDO->beginTransaction();
+	$query = "INSERT INTO "._TABLE_WORD_BOLD_." (book , paragraph , word , word2 , word_en ) VALUES (?,?,?,?,?)";
+	$stmt = $PDO->prepare($query);
+	$allcount = 1;
+	$count = 0;
+	$count1 = 0;
+	$sen = "";
+	$sen1 = "";
+	$sen_en = "";
+	$sen_count = 0;
+	$book = "";
+	$paragraph = "";
+	foreach ($arrInserString as $oneParam) {
+		if ($oneParam[15] == "bld") {
+			if ($oneParam[5] != "") {
+				$sen_count++;
+			}
+			$sen .= $oneParam[4] . " ";
+			$sen1 .= $oneParam[5] . " ";
+			$book = substr($oneParam[2], 1);
+			$paragraph = $oneParam[3];
+			if ($oneParam[5] != "") {
+				$newWord = array($book, $paragraph, $oneParam[4], $oneParam[5], getWordEn($oneParam[5]));
+				$stmt->execute($newWord);
+				$count++;
+				$allcount++;
+			}
+		} else {
+			if ($sen_count > 1) {
+				$sen = rtrim($sen);
+				$sen1 = rtrim($sen1);
+				$sen_en = getWordEn($sen1);
+				$newWord = array($book, $paragraph, $sen, $sen1, $sen_en);
+				$stmt->execute($newWord);
+				$count1++;
+				$allcount++;
+				$sen = "";
+				$sen1 = "";
+				$sen_en = "";
+				$sen_count = 0;
+			} else {
+				$sen = "";
+				$sen1 = "";
+				$sen_en = "";
+				$sen_count = 0;
+			}
+		}
+	}
+	// 提交更改
+	$PDO->commit();
+	if (!$stmt || ($stmt && $stmt->errorCode() != 0)) {
+		$error = PDO_ErrorInfo();
+		echo "error - $error[2] <br>";
+
+		$log = $log . "$from, $FileName, error, $error[2] \r\n";
+	} else {
+		echo "updata $count-$count1 recorders.";
+	}
+
+	$myLogFile = fopen($dirLog . "insert_bold.log", "a");
+	fwrite($myLogFile, $log);
+	fclose($myLogFile);
+	
 } else {
     echo "can not open csv file. filename=" . $dirXmlBase . $dirXml . $outputFileNameHead . ".csv";
 }
 
-// 开始一个事务,关闭自动提交
-$PDO->beginTransaction();
-$query = "INSERT INTO bold ('id','book','paragraph','word','word2','word_en') VALUES (NULL,?,?,?,?,?)";
-$stmt = $PDO->prepare($query);
-$allcount = 1;
-$count = 0;
-$count1 = 0;
-$sen = "";
-$sen1 = "";
-$sen_en = "";
-$sen_count = 0;
-$book = "";
-$paragraph = "";
-foreach ($arrInserString as $oneParam) {
-    if ($oneParam[15] == "bld") {
-        if ($oneParam[5] != "") {
-            $sen_count++;
-        }
-        $sen .= $oneParam[4] . " ";
-        $sen1 .= $oneParam[5] . " ";
-        $book = substr($oneParam[2], 1);
-        $paragraph = $oneParam[3];
-        if ($oneParam[5] != "") {
-            $newWord = array($book, $paragraph, $oneParam[4], $oneParam[5], getWordEn($oneParam[5]));
-            $stmt->execute($newWord);
-            $count++;
-            $allcount++;
-        }
-    } else {
-        if ($sen_count > 1) {
-            $sen = rtrim($sen);
-            $sen1 = rtrim($sen1);
-            $sen_en = getWordEn($sen1);
-            $newWord = array($book, $paragraph, $sen, $sen1, $sen_en);
-            $stmt->execute($newWord);
-            $count1++;
-            $allcount++;
-            $sen = "";
-            $sen1 = "";
-            $sen_en = "";
-            $sen_count = 0;
-        } else {
-            $sen = "";
-            $sen1 = "";
-            $sen_en = "";
-            $sen_count = 0;
-        }
-    }
-}
-// 提交更改
-$PDO->commit();
-if (!$stmt || ($stmt && $stmt->errorCode() != 0)) {
-    $error = PDO_ErrorInfo();
-    echo "error - $error[2] <br>";
-
-    $log = $log . "$from, $FileName, error, $error[2] \r\n";
-} else {
-    echo "updata $count-$count1 recorders.";
-}
 
-$myLogFile = fopen($dirLog . "insert_bold.log", "a");
-fwrite($myLogFile, $log);
-fclose($myLogFile);
 ?>
 
 

+ 1 - 0
app/path.sample.php

@@ -1,4 +1,5 @@
 <?php
+require_once "./config.php";
 # 目录
 define("_DIR_APPDATA_", __DIR__ . "/../tmp/appdata");
 

+ 11 - 11
app/search/bold_search.php

@@ -21,7 +21,7 @@ switch ($op) {
     case "pre": //预查询
         PDO_Connect(_FILE_DB_REF_INDEX_);
         echo "<div>";
-        $query = "select word,count from dict where \"eword\" like " . $PDO->quote($word . '%') . " OR \"word\" like " . $PDO->quote($word . '%') . "  limit 0,20";
+        $query = "SELECT word,count from dict where \"eword\" like " . $PDO->quote($word . '%') . " OR \"word\" like " . $PDO->quote($word . '%') . "  limit 20";
 
         $Fetch = PDO_FetchAll($query);
         $iFetch = count($Fetch);
@@ -83,7 +83,7 @@ switch ($op) {
 
         PDO_Connect(_FILE_DB_BOLD_);
         //查询符合的记录数
-        $query = "select count(*) as co from bold where \"word2\" in  $strQueryWord";
+        $query = "SELECT count(*) as co from "._TABLE_WORD_BOLD_." where \"word2\" in  $strQueryWord";
         $Fetch = PDO_FetchOne($query);
         if ($Fetch > 0) {
             $strDictTab .= "<li id=\"dt_bold\"  onclick=\"tab_click('dict_bold','dt_bold')\">{$_local->gui->vannana}({$Fetch})</li>";
@@ -100,7 +100,7 @@ switch ($op) {
             $strQueryWord中是所有可能的拼写
              */
             $realQueryWord = "(";
-            $query = "select word2,count(word) as co from bold where \"word2\" in $strQueryWord group by word2 order by co DESC";
+            $query = "SELECT word2,count(word) as co from "._TABLE_WORD_BOLD_." where \"word2\" in $strQueryWord group by word2 order by co DESC";
             $Fetch = PDO_FetchAll($query);
             $iFetch = count($Fetch);
             if ($iFetch > 0) {
@@ -121,7 +121,7 @@ switch ($op) {
             }
 
             //查找这些词出现在哪些书中
-            $query = "select book,count(word) as co from bold where \"word2\" in $realQueryWord group by book order by co DESC";
+            $query = "SELECT book,count(word) as co from "._TABLE_WORD_BOLD_." where \"word2\" in $realQueryWord group by book order by co DESC";
             $Fetch = PDO_FetchAll($query);
             $iFetch = count($Fetch);
             if ($iFetch > 0) {
@@ -146,7 +146,7 @@ switch ($op) {
             //黑体字主显示区右侧开始
             echo "<div id=\"dict_bold_right\" style='flex:7;'>";
             //前20条记录
-            $query = "select * from bold where \"word2\" in $realQueryWord limit 0,20";
+            $query = "SELECT * from "._TABLE_WORD_BOLD_." where \"word2\" in $realQueryWord limit 20";
             $Fetch = PDO_FetchAll($query);
             $iFetch = count($Fetch);
             if ($iFetch > 0) {
@@ -168,7 +168,7 @@ switch ($op) {
                         echo "<div class='mean'>$pali</div>";
                     } else {
                         //PDO_Connect(_FILE_DB_PALITEXT_);
-                        $query = "select * from "._TABLE_PALI_TEXT_." where \"book\" = '{$book}' and \"paragraph\" = '{$paragraph}' limit 0,20";
+                        $query = "SELECT * from "._TABLE_PALI_TEXT_." where \"book\" = '{$book}' and \"paragraph\" = '{$paragraph}' limit 20";
                         $FetchPaliText = PDO_FetchAll($query);
                         $countPaliText = count($FetchPaliText);
                         if ($countPaliText > 0) {
@@ -179,7 +179,7 @@ switch ($op) {
                                 $deep = 0;
                                 $sFirstParentTitle = "";
                                 while ($parent > -1) {
-                                    $query = "select * from pali_text where \"book\" = '{$book}' and \"paragraph\" = '{$parent}' limit 0,1";
+                                    $query = "SELECT * from pali_text where \"book\" = '{$book}' and \"paragraph\" = '{$parent}' limit 1";
                                     $FetParent = PDO_FetchAll($query);
                                     if ($sFirstParentTitle == "") {
                                         $sFirstParentTitle = $FetParent[0]["toc"];
@@ -273,7 +273,7 @@ switch ($op) {
                 }
 
                 //查找这些词出现在哪些书中
-                $query = "select book,count(word) as co from bold where \"word2\" in $wordlist group by book order by co DESC";
+                $query = "SELECT book,count(word) as co from "._TABLE_WORD_BOLD_." where \"word2\" in $wordlist group by book order by co DESC";
                 $Fetch = PDO_FetchAll($query);
                 $iFetch = count($Fetch);
                 if ($iFetch > 0) {
@@ -301,7 +301,7 @@ switch ($op) {
                 if ($booklist == "()") {
                     echo "<div>请选择书名</div>";
                 }
-                $query = "select * from bold where \"word2\" in $wordlist and \"book\" in $booklist  limit 0,20";
+                $query = "SELECT * from "._TABLE_WORD_BOLD_." where \"word2\" in $wordlist and \"book\" in $booklist  limit 20";
                 $Fetch = PDO_FetchAll($query);
                 $iFetch = count($Fetch);
                 if ($iFetch > 0) {
@@ -324,7 +324,7 @@ switch ($op) {
                             echo "<div class='mean'>$pali</div>";
                         } else {
                             PDO_Connect(_FILE_DB_PALITEXT_);
-                            $query = "select * from "._TABLE_PALI_TEXT_." where \"book\" = '{$book}' and \"paragraph\" = '{$paragraph}' limit 0,20";
+                            $query = "SELECT * from "._TABLE_PALI_TEXT_." where \"book\" = '{$book}' and \"paragraph\" = '{$paragraph}' limit 20";
                             $FetchPaliText = PDO_FetchAll($query);
                             $countPaliText = count($FetchPaliText);
                             if ($countPaliText > 0) {
@@ -335,7 +335,7 @@ switch ($op) {
                                     $deep = 0;
                                     $sFirstParentTitle = "";
                                     while ($parent > -1) {
-                                        $query = "select * from "._TABLE_PALI_TEXT_." where \"book\" = '{$book}' and \"paragraph\" = '{$parent}' limit 0,1";
+                                        $query = "SELECT * from "._TABLE_PALI_TEXT_." where \"book\" = '{$book}' and \"paragraph\" = '{$parent}' limit 1";
                                         $FetParent = PDO_FetchAll($query);
                                         if ($sFirstParentTitle == "") {
                                             $sFirstParentTitle = $FetParent[0]["toc"];

+ 0 - 102
app/statistics/_pdo.php

@@ -1,102 +0,0 @@
-<?php
-// PDO helper functions.
-// Copyright (c) 2012-2014 The PHP Desktop authors. All rights reserved.
-// License: New BSD License.
-// Website: http://code.google.com/p/phpdesktop/
-
-function PDO_Connect($dsn, $user="", $password="")
-{
-    global $PDO;
-    $PDO = new PDO($dsn, $user, $password);
-    $PDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
-}
-function PDO_FetchOne($query, $params=null)
-{
-    global $PDO;
-    if (isset($params)) {
-        $stmt = $PDO->prepare($query);
-        $stmt->execute($params);
-    } else {
-        $stmt = $PDO->query($query);
-    }
-    $row = $stmt->fetch(PDO::FETCH_NUM);
-    if ($row) {
-        return $row[0];
-    } else {
-        return false;
-    }
-}
-
-function PDO_FetchNum($query, $params=null)
-{
-    global $PDO;
-    if (isset($params)) {
-        $stmt = $PDO->prepare($query);
-        $stmt->execute($params);
-    } else {
-        $stmt = $PDO->query($query);
-    }
-    return PDO::FETCH_NUM;
-
-}
-function PDO_FetchRow($query, $params=null)
-{
-    global $PDO;
-    if (isset($params)) {
-        $stmt = $PDO->prepare($query);
-        $stmt->execute($params);
-    } else {
-        $stmt = $PDO->query($query);
-    }
-    return $stmt->fetch(PDO::FETCH_ASSOC);
-}
-function PDO_FetchAll($query, $params=null)
-{
-    global $PDO;
-    if (isset($params)) {
-        $stmt = $PDO->prepare($query);
-        $stmt->execute($params);
-    } else {
-        $stmt = $PDO->query($query);
-    }
-    return $stmt->fetchAll(PDO::FETCH_ASSOC);
-}
-function PDO_FetchAssoc($query, $params=null)
-{
-    global $PDO;
-    if (isset($params)) {
-        $stmt = $PDO->prepare($query);
-        $stmt->execute($params);
-    } else {
-        $stmt = $PDO->query($query);
-    }
-    $rows = $stmt->fetchAll(PDO::FETCH_NUM);
-    $assoc = array();
-    foreach ($rows as $row) {
-        $assoc[$row[0]] = $row[1];
-    }
-    return $assoc;
-}
-function PDO_Execute($query, $params=null)
-{
-    global $PDO;
-    if (isset($params)) {
-        $stmt = $PDO->prepare($query);
-        $stmt->execute($params);
-        return $stmt;
-    } else {
-        return $PDO->query($query);
-    }
-}
-function PDO_LastInsertId()
-{
-    global $PDO;
-    return $PDO->lastInsertId();
-}
-function PDO_ErrorInfo()
-{
-    global $PDO;
-    return $PDO->errorInfo();
-}
-
-?>

+ 20 - 17
app/statistics/index.php

@@ -1,3 +1,8 @@
+<?php
+require_once "../public/_pdo.php";
+require_once "../path.php";
+require_once "../public/load_lang.php";
+?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <html>
 <head>
@@ -27,11 +32,9 @@
 	</style>
 </head>
 <body>
-<?php require_once '../lang/lang.php';?>
 <?php
-require_once "../public/_pdo.php";
-require_once "../path.php";
-require_once "../public/load_lang.php";
+require_once '../lang/lang.php';
+
 
 if (isset($_GET["language"])) {
     $language = $_GET["language"];
@@ -143,20 +146,20 @@ for ($i = 0; $i < count($boolList); $i++) {
 }
 
 //open database
-PDO_Connect("$db_file");
+PDO_Connect(_FILE_DB_STATISTICS_,_DB_USERNAME_,_DB_PASSWORD_);
 if ($spell == "") {
     echo ("<h3>" . $gui['group_by'] . ":$groupby</h3>");
-    $query = "SELECT count(*) FROM \"word\" WHERE (bookid in (" . $bookstring . ")) "; /*查總數*/
+    $query = "SELECT count(*) FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ")) "; /*查總數*/
     $count_word = PDO_FetchOne($query);
-    $query = "SELECT sum(count) FROM \"word\" WHERE (bookid in (" . $bookstring . ")) "; /*查總數,并分類匯總*/
+    $query = "SELECT sum(count) FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ")) "; /*查總數,并分類匯總*/
     $sum_word = PDO_FetchOne($query);
-    $query = "select count(*) from (SELECT count() FROM \"word\" WHERE (bookid in (" . $bookstring . ") and $groupby<>'') group by $groupby )"; /*查總數,并分類匯總*/
+    $query = "SELECT count(*) from (SELECT count() FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ") and $groupby<>'') group by $groupby ) as subtable"; /*查總數,并分類匯總*/
     $count_parent = PDO_FetchOne($query);
 
-    $query = "select sum(length) from (SELECT * FROM \"word\" WHERE (bookid in (" . $bookstring . ") and $groupby<>'') group by $groupby )"; /*查總數,并分類匯總*/
+    $query = "SELECT sum(length) from (SELECT * FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ") and $groupby<>'') group by $groupby ) as subtable"; /*查總數,并分類匯總*/
     $count_parent1 = PDO_FetchOne($query);
 
-    $query = "SELECT sum(count) FROM \"word\" WHERE (bookid in (" . $bookstring . ") and  $groupby<>'') "; /*查總數,并分類匯總*/
+    $query = "SELECT sum(count) FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ") and  $groupby<>'') "; /*查總數,并分類匯總*/
     $sum_parent = PDO_FetchOne($query);
     $format = number_format($count_word);
     echo $gui['vacab'] . ":$format<br>";
@@ -164,7 +167,7 @@ if ($spell == "") {
     echo "<b>$groupby</b>" . $gui['statistics'] . ":" . number_format($count_parent) . "<br> ";
     echo "<b>$groupby</b>字母" . $gui['statistics'] . ":" . number_format($count_parent1) . "<br> ";
     echo $gui['effective'] . ":" . number_format($sum_parent) . " <br>";
-    $query = "select * from (SELECT $groupby,sum(count) as wordsum FROM \"word\" WHERE (bookid in (" . $bookstring . ") and $groupby<>'') group by $groupby) order by wordsum DESC limit 0 ,4000"; /*查總數,并分類匯總*/
+    $query = "SELECT * from (SELECT $groupby,sum(count) as wordsum FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ") and $groupby<>'') as T group by $groupby) as T order by wordsum DESC limit 4000"; /*查總數,并分類匯總*/
     $Fetch = PDO_FetchAll($query);
     $iFetch = count($Fetch);
     echo "<table>";
@@ -188,18 +191,18 @@ if ($spell == "") {
 } else {
     echo ("<h3>Word: <spen style='color: var(--tool-link-hover-color);'>$spell</spen></h3>");
     $newSpell = $PDO->quote($spell);
-    $query = "SELECT count(*) FROM \"word\" WHERE (word $wordop $newSpell) "; /*查總词數*/
+    $query = "SELECT count(*) FROM "._TABLE_WORD_STATISTICS_." WHERE (word $wordop $newSpell) "; /*查總词數*/
     $count_word = PDO_FetchOne($query);
-    $query = "SELECT sum(count) FROM \"word\" WHERE (word $wordop $newSpell) "; /*查總數,并分類匯總*/
+    $query = "SELECT sum(count) FROM "._TABLE_WORD_STATISTICS_." WHERE (word $wordop $newSpell) "; /*查總數,并分類匯總*/
     $sum_word = PDO_FetchOne($query);
 
     echo "单词总个数:" . number_format($count_word) . "<br>";
     echo "单词总数:" . number_format($sum_word) . "<br>";
 
-    $query = "select count(*) from (SELECT bookid FROM \"word\" WHERE (word $wordop $newSpell) group by bookid) "; /*查總數,并分類匯總*/
+    $query = "SELECT count(*) from (SELECT bookid FROM "._TABLE_WORD_STATISTICS_." WHERE (word $wordop $newSpell) group by bookid) as T "; /*查總數,并分類匯總*/
     $in_book_count = PDO_FetchOne($query);
     echo "<p>In $in_book_count Books</p>";
-    $query = "select bookid,co,su from (SELECT bookid,sum(count) as su,count(*) co FROM \"word\" WHERE (word $wordop $newSpell) group by bookid) order by co DESC  limit 0 ,20"; /*查總數,并分類匯總*/
+    $query = "SELECT bookid,co,su from (SELECT bookid,sum(count) as su,count(*) co FROM "._TABLE_WORD_STATISTICS_." WHERE (word $wordop $newSpell) group by bookid) as T order by co DESC  limit 20"; /*查總數,并分類匯總*/
     $Fetch = PDO_FetchAll($query);
     $iFetch = count($Fetch);
     echo "<table>";
@@ -213,10 +216,10 @@ if ($spell == "") {
     }
     echo "</table>";
 
-    $query = "select count(*) from (SELECT bookid FROM \"word\" WHERE (word $wordop $newSpell) group by word) "; /*查總數,并分類匯總*/
+    $query = "SELECT count(*) from (SELECT word FROM "._TABLE_WORD_STATISTICS_." WHERE (word $wordop $newSpell) group by word) as T "; /*查總數,并分類匯總*/
     $word_count = PDO_FetchOne($query);
     echo "<p>$word_count Words</p>";
-    $query = "select word,co from (SELECT word,sum(count) co FROM \"word\" WHERE (word $wordop $newSpell) group by word) order by co DESC  limit 0 ,100"; /*查總數,并分類匯總*/
+    $query = "SELECT word,co from (SELECT word,sum(count) co FROM "._TABLE_WORD_STATISTICS_." WHERE (word $wordop $newSpell) group by word) as T order by co DESC  limit 100"; /*查總數,并分類匯總*/
     $Fetch = PDO_FetchAll($query);
     $iFetch = count($Fetch);
     echo "<table>";

+ 5 - 5
app/tools/pc_word_analysis.php

@@ -90,16 +90,16 @@ for ($i = 0; $i < count($boolList); $i++) {
 //open database
 PDO_Connect(_FILE_DB_STATISTICS_);
 if ($col == "parent") {
-    $query = "SELECT count(*) FROM \"word\" WHERE (bookid in (" . $bookstring . ")) "; /*查總數,并分類匯總*/
+    $query = "SELECT count(*) FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ")) "; /*查總數,并分類匯總*/
     $count_word = PDO_FetchOne($query);
-    $query = "SELECT sum(count) FROM \"word\" WHERE (bookid in (" . $bookstring . ")) "; /*查總數,并分類匯總*/
+    $query = "SELECT sum(count) FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ")) "; /*查總數,并分類匯總*/
     $sum_word = PDO_FetchOne($query);
-    $query = "select count(*) from (SELECT count() FROM \"word\" WHERE (bookid in (" . $bookstring . ") and parent<>'') group by parent )"; /*查總數,并分類匯總*/
+    $query = "select count(*) from (SELECT count() FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ") and parent<>'') group by parent )"; /*查總數,并分類匯總*/
     $count_parent = PDO_FetchOne($query);
-    $query = "SELECT sum(count) FROM \"word\" WHERE (bookid in (" . $bookstring . ") and  parent<>'') "; /*查總數,并分類匯總*/
+    $query = "SELECT sum(count) FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ") and  parent<>'') "; /*查總數,并分類匯總*/
     $sum_parent = PDO_FetchOne($query);
     echo "单词个数: $count_word<br>总词数: $sum_word<br> parent个数: $count_parent<br> 有parent的单词总数:$sum_parent <br>";
-    $query = "select * from (SELECT parent,sum(count) as wordsum FROM \"word\" WHERE (bookid in (" . $bookstring . ") and parent<>'') group by parent) order by wordsum DESC limit 0 ,2000"; /*查總數,并分類匯總*/
+    $query = "select * from (SELECT parent,sum(count) as wordsum FROM "._TABLE_WORD_STATISTICS_." WHERE (bookid in (" . $bookstring . ") and parent<>'') group by parent) order by wordsum DESC limit 0 ,2000"; /*查總數,并分類匯總*/
     $Fetch = PDO_FetchAll($query);
     $iFetch = count($Fetch);
     echo "<table>";

+ 1 - 1
app/users_guide/zh-cn/grammar_aor.md

@@ -1,4 +1,4 @@
-## 不定过去
+## 过去
 
 **动词**变位之一,巴利语中表达过去发生动作的时态。
 

+ 6 - 0
db/sqlite/bold/down.sql

@@ -0,0 +1,6 @@
+
+DROP INDEX IF EXISTS bold_bookpara ;
+DROP INDEX IF EXISTS bold_word ;
+DROP INDEX IF EXISTS bold_word_en ;
+
+DROP TABLE bold;

+ 23 - 0
db/sqlite/bold/up.sql

@@ -0,0 +1,23 @@
+--
+-- 由SQLiteStudio v3.1.1 产生的文件 周日 11月 21 21:37:23 2021
+--
+-- 文本编码:UTF-8
+--
+
+-- 表:bold
+CREATE TABLE bold (
+    id SERIAL PRIMARY KEY,
+    book      INTEGER NOT NULL,
+    paragraph INTEGER NOT NULL,
+    word      TEXT    NOT NULL,
+    word2     TEXT    NOT NULL,
+    word_en   TEXT,
+    pali      TEXT,
+    base      TEXT,
+	created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX bold_bookpara ON bold (book,paragraph);
+CREATE INDEX bold_word ON bold (word);
+CREATE INDEX bold_word_en ON bold (word_en);
+

+ 4 - 0
db/sqlite/word_statistics/down.sql

@@ -0,0 +1,4 @@
+-- This file should undo anything in `up.sql`
+DROP INDEX IF EXISTS word_statistics_bookid ;
+DROP INDEX IF EXISTS word_statistics_base ;
+DROP TABLE word_statistics ;

+ 19 - 0
db/sqlite/word_statistics/up.sql

@@ -0,0 +1,19 @@
+-- word_statistics
+CREATE TABLE word_statistics
+(
+	id SERIAL PRIMARY KEY, 
+	bookid INTEGER, 
+	word TEXT, 
+	count INTEGER, 
+	base TEXT, 
+	end1 TEXT, 
+	end2 TEXT, 
+	type INTEGER, 
+	length INTEGER,
+	created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+-- 索引:pali
+CREATE INDEX word_statistics_bookid ON word_statistics (bookid);
+CREATE INDEX word_statistics_base ON word_statistics (base);
+

+ 1 - 0
deploy/.gitignore

@@ -0,0 +1 @@
+/clients/

+ 0 - 0
deploy/.txt


+ 32 - 0
deploy/README.md

@@ -0,0 +1,32 @@
+# Deployment
+
+## Setup a cluster
+
+```bash
+# create cluster
+mkdir -p clients/CLUSTER/.ssh
+cd clients/CLUSTER
+# append your cluster hosts
+touch hosts
+# generate ssh key
+ssh-keygen -t ed25519 -f .ssh/id_ed25519
+# upload the ssh public key to target host
+ssh-copy-id -i .ssh/id_ed25519 USER@HOST
+```
+
+## Deploy
+
+```bash
+# test ssh connections
+peony -i staging ping.yml
+# run on all hosts
+peony -i staging pi.yml
+# run on only group
+peony -i staging pi.yml -l GROUP
+```
+
+## System image
+
+- [Raspberry Pi OS Lite](https://www.raspberrypi.com/software/operating-systems/)
+- [Armbian](https://www.armbian.com/download/)
+- [wiringPi for Orange Pi](https://github.com/orangepi-xunlong/WiringOP)

+ 9 - 0
deploy/group_vars/all.yml

@@ -0,0 +1,9 @@
+ansible_user: "deploy"
+ansible_python_interpreter: /usr/bin/python3
+ansible_ssh_private_key_file: "{{inventory_dir}}/.ssh/id_ed25519"
+#ansible_ssh_private_key_file: "{{inventory_dir}}/.ssh/id_rsa"
+
+app_deploy_target: "/opt/{{ app_vendor }}/{{ ansible_date_time.iso8601_basic }}"
+app_downloads: "{{ ansible_env.HOME }}/downloads"
+app_backup: "{{ ansible_env.HOME }}/backup"
+app_python_version: "3.11"

+ 2 - 0
deploy/group_vars/nano_pi.yml

@@ -0,0 +1,2 @@
+ansible_user: "pi"
+ansible_sudo_pass: "pi"

+ 1 - 0
deploy/group_vars/orange_pi.yml

@@ -0,0 +1 @@
+ansible_user: "root"

+ 1 - 0
deploy/group_vars/raspbarry_pi.yml

@@ -0,0 +1 @@
+ansible_user: "pi"

+ 71 - 0
deploy/migaration/word_statistics.php

@@ -0,0 +1,71 @@
+<?php
+require_once "../../app/path.php";
+
+#打开源数据库
+$PDO_SRC = new PDO(_SRC_DB_STATISTICS_,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_SRC->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+echo "open src".PHP_EOL;
+
+#打开目标数据库
+$PDO_DEST = new PDO(_FILE_DB_STATISTICS_,_DB_USERNAME_,_DB_PASSWORD_,array(PDO::ATTR_PERSISTENT=>true));
+$PDO_DEST->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
+echo "open dest".PHP_EOL;
+
+#删除目标数据库中所有数据
+$query = "DELETE FROM "._TABLE_WORD_STATISTICS_." WHERE true";
+$stmt = $PDO_DEST->prepare($query);
+if (!$stmt || ($stmt && $stmt->errorCode() != 0)) {
+    $error = $PDO_DEST->errorInfo();
+    echo "error - $error[2] ";
+	exit;
+}
+
+$stmt->execute();
+echo "delete dest".PHP_EOL;
+
+// 开始一个事务,关闭自动提交
+$count = 0;
+echo "begin Transaction".PHP_EOL;
+
+$PDO_DEST->beginTransaction();
+
+$query = "INSERT INTO "._TABLE_WORD_STATISTICS_." ( bookid , word , count , base , end1 , end2 , type , length ) VALUES ( ? , ? , ? , ? , ? , ? , ? , ? )";
+$stmtDEST = $PDO_DEST->prepare($query);
+
+#从源数据库中读取
+$query = "SELECT *  FROM "._SRC_TABLE_WORD_STATISTICS_." WHERE true ";
+$stmtSrc = $PDO_SRC->prepare($query);
+$stmtSrc->execute();
+
+while($srcData = $stmtSrc->fetch(PDO::FETCH_ASSOC)){
+	#插入目标表
+    $stmtDEST->execute(array(
+					$srcData["bookid"],
+					$srcData["word"],
+					(int)$srcData["count"],
+					$srcData["base"],
+					$srcData["end1"],
+					$srcData["end2"],
+					(int)$srcData["type"],
+					(int)$srcData["length"]
+				));
+	if (!$stmtDEST || ($stmtDEST && $stmtDEST->errorCode() != 0)) {
+		$error = $PDO_DEST->errorInfo();
+		echo "error - $error[2] ";
+		exit;
+	}			
+	$count++;
+	if($count%10000==0){
+		echo "finished $count".PHP_EOL;
+	}
+}
+
+// 提交更改
+$PDO_DEST->commit();
+echo "done".PHP_EOL;
+
+
+
+
+
+

+ 12 - 0
deploy/mint.yml

@@ -0,0 +1,12 @@
+- hosts: all
+  roles:
+    - os
+    - ubuntu
+    - python3
+    - php
+
+- hosts: db
+  roles:
+
+- hosts: www
+  roles:

+ 0 - 33
deploy/php.sh

@@ -1,33 +0,0 @@
-#!/bin/bash
-
-set -e
-
-export PHP_VERSION="8.0"
-
-declare -a plugins=(
-    "cli"
-    "fpm"
-    "xml"
-    # https://php.watch/versions/8.0/ext-json
-    # "json"
-    "imap"
-    "intl"
-    "mbstring"
-    "bz2"
-    "zip"
-    "curl"
-    "gd"
-    "imagick"
-    "mysql"
-    "pgsql"
-    "sqlite3"
-    "redis"
-    "bcmath"
-)
-
-for i in "${plugins[@]}"
-do
-    sudo apt install -y php${PHP_VERSION}-$i
-done
-
-echo 'done.'

+ 4 - 0
deploy/ping.yml

@@ -0,0 +1,4 @@
+- hosts: all
+  roles:
+    - ping
+

+ 21 - 0
deploy/roles/os/tasks/init.yml

@@ -0,0 +1,21 @@
+- name: create deploy folder
+  become: true
+  ansible.builtin.file:
+    path: "{{ app_deploy_target }}"
+    state: directory
+    owner: "{{ ansible_user }}"
+
+- name: create downloads folder
+  become: true
+  ansible.builtin.file:
+    path: "{{ app_downloads }}"
+    state: directory
+    owner: "{{ ansible_user }}"
+
+- name: create backup folder
+  become: true
+  ansible.builtin.file:
+    path: "{{ app_backup }}"
+    state: directory
+    owner: "{{ ansible_user }}"
+

+ 42 - 0
deploy/roles/os/tasks/main.yml

@@ -0,0 +1,42 @@
+- include: init.yml
+- include: sshd.yml
+- include: ulimits.yml
+
+- name: Setup sudo without password 
+  become: true
+  ansible.builtin.template:
+    src: sudo.conf.j2
+    dest: /etc/sudoers.d/100-{{ ansible_user }}
+    owner: root
+    group: root
+    mode: 0440
+  when: ansible_distribution != 'Raspbian' and ansible_user != 'root'
+
+- name: Reset root password
+  become: true
+  shell: echo "root:$(pwgen 32 1)" | chpasswd
+
+- name: Reset {{ ansible_user }} password
+  become: true
+  shell: echo "{{ ansible_user }}:$(pwgen 32 1)" | chpasswd
+  when: ansible_user != 'root'
+
+- name: Set timezone
+  become: true
+  shell: timedatectl set-timezone UTC
+
+- name: Setup journald storage 
+  become: true
+  lineinfile:
+    path: /etc/systemd/journald.conf
+    regexp: '^#Storage='
+    line: Storage=persistent
+
+# https://www.linode.com/docs/quick-answers/linux/how-to-use-journalctl/
+- name: Setup journald storage keep-free
+  become: true
+  lineinfile:
+    path: /etc/systemd/journald.conf
+    state: present
+    regexp: '^#SystemKeepFree='
+    line: SystemKeepFree=6%

+ 22 - 0
deploy/roles/os/tasks/sshd.yml

@@ -0,0 +1,22 @@
+- name: Backup sshd_config
+  become: true
+  copy:
+    src: /etc/ssh/sshd_config
+    dest: "{{ app_backup }}/etc_sshd_config"
+    remote_src: yes
+    backup: yes
+
+- name: Disable dns for sshd
+  become: true
+  lineinfile:
+    path: /etc/ssh/sshd_config
+    regexp: '^UseDNS '
+    line: UseDNS no
+
+- name: Disable GSS api auth for sshd
+  become: true
+  lineinfile:
+    path: /etc/ssh/sshd_config
+    regexp: '^GSSAPIAuthentication '
+    line: GSSAPIAuthentication no
+

+ 80 - 0
deploy/roles/os/tasks/ulimits.yml

@@ -0,0 +1,80 @@
+- name: Backup system.conf
+  become: true
+  copy:
+    src: /etc/systemd/system.conf
+    dest: "{{ app_backup }}/etc_systemd_system"
+    remote_src: yes
+    backup: yes
+
+- name: Setup nofile for system
+  become: true
+  lineinfile:
+    path: /etc/systemd/system.conf
+    regexp: "^DefaultLimitNOFILE="
+    line: DefaultLimitNOFILE=2097152
+
+- name: Setup nproc for system
+  become: true
+  lineinfile:
+    path: /etc/systemd/system.conf
+    regexp: "^DefaultLimitNPROC"
+    line: DefaultLimitNPROC=524288
+
+- name: Backup user.conf
+  become: true
+  copy:
+    src: /etc/systemd/user.conf
+    dest: "{{ app_backup }}/etc_systemd_user.conf"
+    remote_src: yes
+    backup: yes
+
+- name: Setup nofile for user
+  become: true
+  lineinfile:
+    path: /etc/systemd/user.conf
+    regexp: "^DefaultLimitNOFILE="
+    line: DefaultLimitNOFILE=1048576
+
+- name: Setup nproc for user
+  become: true
+  lineinfile:
+    path: /etc/systemd/user.conf
+    regexp: "^DefaultLimitNPROC"
+    line: DefaultLimitNPROC=262144
+
+- name: Backup limits.conf
+  become: true
+  copy:
+    src: /etc/security/limits.conf
+    dest: "{{ app_backup }}/etc_security_limits.conf"
+    remote_src: yes
+    backup: yes
+
+- name: Set user level ppen file limits for root
+  become: true
+  lineinfile:
+    path: /etc/security/limits.conf
+    line: root        soft nofile 10240
+
+- name: Set user level ppen file limits for {{ansible_user}}
+  become: true
+  lineinfile:
+    path: /etc/security/limits.conf
+    line: "{{ansible_user}}        soft nofile 10240"
+
+# https://docs.oracle.com/en/database/oracle/oracle-database/12.2/ladbi/changing-kernel-parameter-values.html#GUID-FB0CC366-61C9-4AA2-9BE7-233EB6810A31
+- name: Setup file max
+  become: true
+  lineinfile:
+    path: "/etc/sysctl.d/100-{{app_vendor}}.conf"
+    state: present
+    line: fs.file-max = 6815744
+    create: true
+
+- name: Setup file max
+  become: true
+  lineinfile:
+    path: "/etc/sysctl.d/100-{{app_vendor}}.conf"
+    state: present
+    line: fs.inotify.max_user_watches = 512000
+    create: true

+ 1 - 0
deploy/roles/os/templates/sudo.conf.j2

@@ -0,0 +1 @@
+{{ ansible_user }} ALL=(ALL) NOPASSWD:ALL

+ 32 - 0
deploy/roles/php/tasks/main.yml

@@ -0,0 +1,32 @@
+- name: Add php repository
+  become: true
+  ansible.builtin.apt_repository:
+    repo: ppa:ondrej/php
+
+- name: Install php packages
+  become: true
+  apt:
+    pkg:
+      - php-cli
+      - php-fpm
+      - php-xml
+      - php-imap
+      - php-intl
+      - php-mbstring
+      - php-bz2
+      - php-zip
+      - php-curl
+      - php-gd
+      - php-imagick
+      - php-mysql
+      - php-pgsql
+      - php-sqlite3
+      - php-redis
+      - php-bcmath
+
+# https://getcomposer.org/doc/00-intro.md#installation-linux-unix-macos
+- name: Download composer
+  get_url:
+    url: https://getcomposer.org/download/latest-stable/composer.phar
+    dest: "{{ ansible_env.HOME }}/.local/bin/composer"
+    mode: 0755

+ 6 - 0
deploy/roles/ping/tasks/main.yml

@@ -0,0 +1,6 @@
+- name: Test ssh connection
+  ping:
+
+- name: Show facts available on the system
+  ansible.builtin.debug:
+    var: ansible_facts

+ 30 - 0
deploy/roles/python3/roles/main.yml

@@ -0,0 +1,30 @@
+- name: Add python3 repository
+  become: true
+  ansible.builtin.apt_repository:
+    repo: ppa:deadsnakes/ppa
+
+- name: make sure {{ app_downloads }} exists
+  become: true
+  file:
+    state: absent
+    path: "{{ app_downloads }}"
+
+# https://pip.pypa.io/en/stable/installation/
+- name: Download get-pip
+  get_url:
+    url: https://bootstrap.pypa.io/get-pip.py
+    dest: "{{ app_downloads }}/get-pip.py"
+    mode: 0644
+
+- name: Run get-pip
+  ansible.builtin.command: "python3{{ app_python_version }} {{ app_downloads }}/get-pip.py"
+  args:
+    creates: "{{ ansible_env.HOME }}/.local/bin/pip"
+
+- name: Install python packages
+  pip:
+    name:
+      - cmake
+      - boto3
+    extra_args: --user
+    executable: "{{ ansible_env.HOME }}/.local/bin/pip"

+ 5 - 0
deploy/roles/reboot/tasks/main.yml

@@ -0,0 +1,5 @@
+
+- name: Reboot
+  become: true
+  reboot:
+    reboot_timeout: 120

+ 15 - 0
deploy/roles/ubuntu/tasks/armbian.yml

@@ -0,0 +1,15 @@
+- name: backup /boot/armbianEnv.txt
+  become: true
+  copy:
+    src: /boot/armbianEnv.txt
+    dest: "{{ app_backup }}/boot_armbianEnv_txt"
+    remote_src: yes
+    backup: yes
+  
+- name: enable uart for armbian
+  become: true
+  lineinfile:
+    path: /boot/armbianEnv.txt
+    regexp: '^overlays='
+    line: overlays=usbhost2 usbhost3 uart1 uart2 analog-codec
+

+ 14 - 0
deploy/roles/ubuntu/tasks/clean.yml

@@ -0,0 +1,14 @@
+- name: Remove useless packages from the cache
+  become: true
+  apt:
+    autoclean: yes
+
+- name: Remove dependencies that are no longer required
+  become: true
+  apt:
+    autoremove: yes
+
+- name: Force systemd to reread configs
+  become: true
+  systemd:
+    daemon_reload: yes

+ 60 - 0
deploy/roles/ubuntu/tasks/friendly-core.yml

@@ -0,0 +1,60 @@
+
+- name: backup serial-getty@ttyAMA0.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/serial-getty@ttyAMA0.service.d/autologin.conf
+    dest: "{{ app_backup }}/ttyAMA0_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for ttyAMA0
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/serial-getty@ttyAMA0.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '
+
+- name: backup getty@tty1.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/getty@tty1.service.d/autologin.conf
+    dest: "{{ app_backup }}/tty1_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for tty1
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/getty@tty1.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '
+
+- name: backup serial-getty@ttyS0.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf
+    dest: "{{ app_backup }}/ttyS0_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for ttyS0
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/serial-getty@ttyS0.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '
+
+- name: backup serial-getty@ttySAC0.service.d/autologin.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/systemd/system/serial-getty@ttySAC0.service.d/autologin.conf
+    dest: "{{ app_backup }}/ttySAC0_autologin_conf"
+    remote_src: yes
+    backup: yes
+
+- name: disable autologin for ttySAC0
+  become: true
+  ansible.builtin.replace:
+    path: /etc/systemd/system/serial-getty@ttySAC0.service.d/autologin.conf
+    regexp: ' --autologin pi '
+    replace: ' '

+ 38 - 0
deploy/roles/ubuntu/tasks/locales.yml

@@ -0,0 +1,38 @@
+- name: Backup locale.gen
+  become: true
+  copy:
+    src: /etc/locale.gen
+    dest: "{{ app_backup }}/etc_locale.gen"
+    remote_src: yes
+    backup: yes
+
+- name: Enable en-US locale
+  become: true
+  lineinfile:
+    path: /etc/locale.gen
+    state: present
+    line: en_US.UTF-8 UTF-8
+
+
+- name: Enable zh-CN locale
+  become: true
+  lineinfile:
+    path: /etc/locale.gen
+    state: present
+    line: zh_CN.UTF-8 UTF-8
+
+- name: Enable zh-TW locale
+  become: true
+  lineinfile:
+    path: /etc/locale.gen
+    state: present
+    line: zh_TW.UTF-8 UTF-8
+
+
+- name: Generate locales
+  become: true
+  shell: locale-gen
+
+- name: Use en_US as default locale
+  become: true
+  shell: update-locale LANG=en_US.UTF-8

+ 166 - 0
deploy/roles/ubuntu/tasks/main.yml

@@ -0,0 +1,166 @@
+# - name: Remove postfix at first
+#   become: true
+#   apt:
+#     name: postfix
+#     state: absent
+#     purge: yes
+
+# - name: Backup /etc/apt/sources.list.d
+#   become: true
+#   copy:
+#     src: /etc/apt/sources.list.d
+#     dest: "{{ app_backup }}/etc_apt_sources_list_d"
+#     remote_src: yes
+#     backup: yes
+
+# - name: Delete /etc/apt/sources.list.d
+#   become: true
+#   file:
+#     state: absent
+#     path: /etc/apt/sources.list.d
+
+- name: add PPA for Ubuntu Toolchain
+  become: true
+  ansible.builtin.apt_repository:
+    repo: ppa:ubuntu-toolchain-r/test
+  when: ansible_distribution == 'Ubuntu'
+
+- name: Update system
+  become: true
+  apt:
+    upgrade: yes
+    update_cache: yes
+    cache_valid_time: 3600
+
+- name: Install dependicy packages
+  become: true
+  apt:
+    pkg:
+      - apt-transport-https
+      - software-properties-common
+      - gnupg
+      - openssh-server
+      - openssh-client
+      - sshpass
+      - wpasupplicant
+      - rsync
+      - at
+      - sysstat
+      - libtool
+      - ethtool
+      - dnsutils
+      - dnsmasq
+      - uuid-runtime
+      - lshw
+      - tcpdump
+      - lm-sensors
+      - hddtemp
+      - dmidecode
+      - net-tools
+      - iputils-arping
+      - iputils-ping
+      - telnet
+      - vim
+      - git
+      - pwgen
+      - locales
+      - ntpdate
+      - imagemagick
+      - mpg123
+      - ffmpeg
+      - sqlite3
+      - tree
+      - alsa-utils
+      - pulseaudio
+      - zsh
+      - wget
+      - curl
+      - zip
+      - unzip
+      - nginx
+      - openvpn
+      - snmpd
+      - systemd-cron
+      - systemd-timesyncd
+      - screen
+      - tmux
+      - python3
+      - python3-pip
+      - python3-distutils
+      - python3-dev
+      - libpq5
+      
+
+- include: locales.yml
+
+- name: Set default editor to vim
+  become: true
+  shell: update-alternatives --set editor /usr/bin/vim.basic
+
+- name: Set timezone
+  become: true
+  shell: timedatectl set-timezone Asia/Shanghai
+
+- name: Set git rebase mode
+  become: true
+  shell: git config --global pull.rebase false
+
+- include: zsh.yml
+
+# ---------------------------------------------------
+
+- name: check if friendlyelec
+  ansible.builtin.stat:
+    path: /etc/friendlyelec-release
+  register: app_os_friendlyelec
+
+- include: friendly-core.yml
+  when: app_os_friendlyelec.stat.islnk is defined and app_os_friendlyelec.stat.isreg
+
+- name: check if armbian
+  ansible.builtin.stat:
+    path: /etc/armbian-release
+  register: app_os_armbian
+
+- include: armbian.yml
+  when: app_os_armbian.stat.islnk is defined and app_os_armbian.stat.isreg
+
+- include: raspbian.yml
+  when: ansible_distribution == 'Raspbian'
+
+- include: pi.yml
+  when: ansible_distribution == 'Raspbian' or (app_os_armbian.stat.islnk is defined and app_os_armbian.stat.isreg) or (app_os_friendlyelec.stat.islnk is defined and app_os_friendlyelec.stat.isreg)
+
+# ---------------------------------------------------
+
+- name: enable nginx service
+  become: true
+  ansible.builtin.systemd:
+    name: nginx
+    enabled: yes
+    masked: no
+
+
+- name: enable cron service
+  become: true
+  ansible.builtin.systemd:
+    name: cron-target
+    enabled: yes
+    masked: no
+
+- name: enable ssh service
+  become: true
+  ansible.builtin.systemd:
+    name: ssh
+    enabled: yes
+    masked: no
+
+- name: enable systemd-timesyncd service
+  become: true
+  ansible.builtin.systemd:
+    name: systemd-timesyncd
+    enabled: yes
+    masked: no
+
+
+- include: clean.yml

+ 133 - 0
deploy/roles/ubuntu/tasks/pi.yml

@@ -0,0 +1,133 @@
+- name: Install dependicy packages
+  become: true
+  apt:
+    pkg:
+      - espeak-ng
+
+# ------------------------------------------------
+
+- name: backup /etc/snmp/snmpd.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/snmp/snmpd.conf
+    dest: "{{ app_backup }}/etc_snmp_snmpd_conf"
+    remote_src: yes
+    backup: yes
+
+
+- name: enable snmpd agent
+  become: true
+  ansible.builtin.lineinfile:
+    path: /etc/snmp/snmpd.conf
+    regexp: '^agentAddress '
+    line: "agentAddress udp:161"
+
+- name: enable snmpd view
+  become: true
+  ansible.builtin.lineinfile:
+    path: /etc/snmp/snmpd.conf
+    line: "view systemonly included .1.3.6.1.4.1.2021"
+
+- name: enable snmpd service
+  become: true
+  ansible.builtin.systemd:
+    name: snmpd
+    enabled: yes
+    masked: no
+
+
+# --------------------------------------------
+
+- name: backup /etc/dhcp/dhclient.conf
+  become: true
+  ansible.builtin.copy:
+    src: /etc/dhcp/dhclient.conf
+    dest: "{{ app_backup }}/etc_dhcp_dhclient_conf"
+    remote_src: yes
+    backup: yes
+
+
+- name: enable option 72 for dhclient
+  become: true
+  ansible.builtin.lineinfile:
+    path: /etc/dhcp/dhclient.conf
+    line: "also request www-server;"
+
+
+# --------------------------------------------
+
+- name: delete /etc/systemd/network
+  become: true
+  ansible.builtin.file:
+    path: /etc/systemd/network
+    state: absent
+
+- name: create /etc/systemd/network
+  become: true
+  ansible.builtin.file:
+    path: /etc/systemd/network
+    state: directory
+
+- name: Create a symbolic link
+  become: true
+  ansible.builtin.file:
+    src: /run/systemd/resolve/resolv.conf
+    dest: /etc/resolv.conf
+    state: link
+
+- name: disable dnsmasq service
+  become: true
+  ansible.builtin.systemd:
+    name: dnsmasq
+    enabled: no
+    masked: yes
+
+
+- name: disable NetworkManager service
+  become: true
+  ansible.builtin.systemd:
+    name: NetworkManager
+    enabled: no
+    masked: yes
+
+- name: enable systemd-networkd service
+  become: true
+  ansible.builtin.systemd:
+    name: systemd-networkd
+    enabled: yes
+    masked: no
+
+- name: enable systemd-resolved service
+  become: true
+  ansible.builtin.systemd:
+    name: systemd-resolved
+    enabled: yes
+    masked: no
+
+- name: enable wpa_supplicant@wlan0service
+  become: true
+  ansible.builtin.systemd:
+    name: wpa_supplicant@wlan0
+    enabled: yes
+    masked: no
+
+- name: enable openvpn@client service
+  become: true
+  ansible.builtin.systemd:
+    name: openvpn@client
+    enabled: yes
+    masked: no
+
+
+- name: Reboot
+  become: true
+  reboot:
+    reboot_timeout: 120
+
+- name: enable pulseaudio service
+  become: true
+  ansible.builtin.systemd:
+    name: pulseaudio
+    enabled: yes
+    masked: no
+    scope: user

+ 52 - 0
deploy/roles/ubuntu/tasks/raspbian.yml

@@ -0,0 +1,52 @@
+# https://www.raspberrypi.org/documentation/configuration/uart.md
+
+- name: backup /boot/config.txt
+  become: true
+  ansible.builtin.copy:
+    src: /boot/config.txt
+    dest: "{{ app_backup }}/boot_config_txt"
+    remote_src: yes
+    backup: yes
+
+- name: enable uart
+  become: true
+  lineinfile:
+    path: /boot/config.txt
+    regexp: '^enable_uart='
+    line: enable_uart=1
+
+- name: disable bluetooth
+  become: true
+  lineinfile:
+    path: /boot/config.txt
+    regexp: '^dtoverlay='
+    line: dtoverlay=disable-bt
+
+- name: hidden splash message
+  become: true
+  lineinfile:
+    path: /boot/config.txt
+    regexp: '^disable_splash='
+    line: disable_splash=1 
+
+- name: backup /boot/cmdline.txt
+  become: true
+  ansible.builtin.copy:
+    src: /boot/cmdline.txt
+    dest: "{{ app_backup }}/boot_cmdline_txt"
+    remote_src: yes
+    backup: yes
+
+- name: disable debug port & logo
+  become: true
+  ansible.builtin.replace:
+    path: /boot/cmdline.txt
+    regexp: 'console=serial0,115200'
+    replace: 'loglevel=3 logo.nologo'
+
+- name: disable hciuart service
+  become: true
+  ansible.builtin.systemd:
+    name: hciuart
+    enabled: no
+    masked: yes

+ 26 - 0
deploy/roles/ubuntu/tasks/zsh.yml

@@ -0,0 +1,26 @@
+- name: Clone oh-my-zsh
+  git:
+    repo: https://github.com/robbyrussell/oh-my-zsh.git
+    dest: "{{ansible_env.HOME}}/.oh-my-zsh"
+
+# - name: Extract ohmyzsh
+#   unarchive:
+#     src: ohmyzsh-master.zip
+#     dest: "{{ansible_env.HOME}}/"
+
+# - name: Rename ohmyzsh
+#   command: mv ohmyzsh-master .oh-my-zsh
+#   args:
+#     chdir: "{{ansible_env.HOME}}"
+#     creates: .oh-my-zsh
+
+- name: Setup .zshrc
+  copy:
+    src: "{{ansible_env.HOME}}/.oh-my-zsh/templates/zshrc.zsh-template"
+    dest: "{{ansible_env.HOME}}/.zshrc"
+    remote_src: true
+    mode: 0600
+
+- name: Use zsh
+  become: true
+  shell: chsh -s /bin/zsh {{ansible_user}}

+ 1 - 0
deploy/staging/.gitignore

@@ -0,0 +1 @@
+/.ssh/

+ 14 - 0
deploy/staging/hosts

@@ -0,0 +1,14 @@
+[www]
+
+[db]
+
+[cache]
+
+[mq]
+
+
+[all:vars]
+app_vendor="iapt-platform.mint"
+; openssl rand -base64 32
+app_secret_key="4i3WKUvKtSGl59htK7XjUNsjalhkG5s7RJCmZruT2m4="
+

+ 4 - 7
docker/README.md

@@ -14,9 +14,9 @@
   # clear outdated images
   podman rmi -a -f
   # uncompress image files
-  cat palm.tar.xz.a* | tar xj
+  cat palm-spring.tar.xz.a* | tar xj
   # import new podman image
-  podman load -q -i mint-TIMESTAMP.tar  
+  podman load -q -i palm-spring-TIMESTAMP.tar  
   ```
 
 - Enjoy it!
@@ -25,11 +25,8 @@
   ![start](documents/start.png)
 
   ```bash
-  # for the first time start
-  ./docker/first.sh
-  # fot the next time start
-  ./docker/next.sh
-  
+  # start container
+  ./docker/start.sh
   # start servers
   > sudo supervisord -c /etc/supervisor/supervisord.conf
 

+ 0 - 2
docker/first.sh

@@ -1,2 +0,0 @@
-#!/bin/sh
-podman run --name mint -it --userns=keep-id --hostname=palm --user=$(id -ur):$(id -gr) --network host --events-backend=file -v $PWD/..:/workspace:z palm

+ 0 - 2
docker/next.sh

@@ -1,2 +0,0 @@
-#!/bin/sh
-podman start -i -a --events-backend=file mint

+ 10 - 0
docker/start.sh

@@ -0,0 +1,10 @@
+#!/bin/sh
+
+NAME=mint
+
+if podman container exists $NAME
+then
+    podman start -i -a --events-backend=file $NAME
+else
+    podman run --name $NAME -it --userns=keep-id --hostname=palm --user=$(id -ur):$(id -gr) --network host --events-backend=file -v $PWD:/workspace:z palm-spring
+fi