mdecourse / vecp2018 Goto Github PK
View Code? Open in Web Editor NEW車輛工程系大一計算機程式 (課程已經結束)
License: GNU Affero General Public License v3.0
車輛工程系大一計算機程式 (課程已經結束)
License: GNU Affero General Public License v3.0
請將下列六行程式複製到 http://mde.tw/vecp2018/lua/SchoolProject/ 中執行:
-- 利用 dofile() 從網頁中取得 star() 函式的定義, 並對應到 local 變數 star 中
local star = dofile("https://raw.githubusercontent.com/mdecourse/vecp2018_1/gh-pages/w5/star.lua").star
-- 有了 star 的函式定義, 可以直接以內定值呼叫 star() 執行繪圖
star()
-- 也可以修改輸入變數, 執行其他繪圖
star(100, 300, 300, 6, "rgb(200,0,0)", "rgb(0,0,200)", "stroke", 45 )
上述位於 Github 倉儲的 star.lua 程式碼寫法如下:
-- 導入 "js" 模組
local js = require "js"
-- global 就是 javascript 的 window
local global = js.global
local document = global.document
-- html 檔案中 canvas id 設為 "canvas"
local canvas = document:getElementById("canvas")
-- 將 ctx 設為 canvas 2d 繪圖畫布變數
local ctx = canvas:getContext("2d")
-- 乘上 deg 可轉為徑度單位
deg = math.pi / 180
-- 建立多邊形定點位置畫線函式
local function star(radius, xc, yc, n, fs, ss, fors, theta)
radius = radius or 50
xc = xc or 100
yc = yc or 100
n = n or 5
-- 屬性呼叫使用 . 而方法呼叫使用 :
-- 填色屬性
fs = fs or "rgb(200,0,0)"
-- 畫筆顏色屬性
ss = ss or "rgb(0,0,200)"
-- 內定為填色
fors = fors or "fill"
-- 旋轉角度
theta = theta or 0
ctx.fillStyle = fs
ctx.strokeStyle = ss
xi = xc + radius*math.cos((360/n)*deg+(90+theta)*deg)
yi = yc - radius*math.sin((360/n)*deg+(90+theta)*deg)
ctx:beginPath()
ctx:moveTo(xi,yi)
for i = 2, n+1 do
x = xc + radius*math.cos((360/n)*deg*i+(90+theta)*deg)
y = yc - radius*math.sin((360/n)*deg*i+(90+theta)*deg)
ctx:lineTo(x,y)
end
ctx:closePath()
if fors == "fill" then
ctx:fill()
else
ctx:stroke()
end
end
return {
star = star;
}
意即, 個人或團隊都可以擁有無限多的概念 (concept) 與無限多的知識 (knowledge), 學習的目的在確認個人或團隊的口袋中 ,到底有哪些概念? 有哪些知識? 簡單說 ,概念就是想法, 而且是當下還沒有知識可以落實的想法, 至於知識, 則是可以用來解決問題, 得到結果的方法集合.
只是, 概念與知識雖然可以無限多, 但工程師解題的過程卻通常有時效限制, 有可用資源的限制, 而且概念與知識都是時間的函式, 也就是說, 先前所獲得的知識, 在空間與時間的遷流變化下, 有可能無法真正落實解題, 而流為概念, 而先前的概念, 在相關知識與實際解題過程, 予以充實後, 可以累積許多有用的知識, 另外, 概念除了透過解題驗證, 可以成為知識外, 也可以觸發出更多概念, 反之, 知識一旦透過證實, 在當下無法解題, 就成為概念之外, 也可以將知識用於解題的過程中, 產生許多其他有用的知識, 相關轉換表示如下:
概念->概念 - 概念可以激發更多概念
知識->知識 - 知識的運用可以獲得更多知識
概念->知識 - 概念的落實當下 ,可以產生知識
知識->概念 - 知識用於解題當下, 若發現已不適用, 則成為概念
假如知識無窮多, 沒有落實不了的概念
產生概念雖不可受限, 但腳踏實地則需要能夠解決問題的知識
請在各組的雲端系統, 以線條畫上自己的學號最後兩個數字, 然後推到雲端系統後, 將連結回報至下方回應處.
kmol2_1805 - 7z 檔案 340 MB, 解壓縮後 1.2 GB, 用法與 kmol_level1 相同.
kmol2_1805 可攜系統中 V-rep 3.5 rev4 缺少兩個 dll:
vrep350_rev4_vcdlls.zip
各組組長必須利用 Gmail 帳號, 至 https://www.heroku.com/ 登記一組帳號, 並建立一個雲端應用程式, 應用程式名稱請選 vecp_組長學號, 之後所完成的雲端網站網址將為: https://vecp_組長學號.herokuapp.com
建立 heroku 帳號前, 必須先登入對應的 Gmail 帳號, heroku 帳號建立後, 必須在 Gmail 帳號中驗證後才可繼續使用 heroku 功能.
以 2015fallhw AT Gmail 郵箱建立的雲端範例網站為: http://a2015fallhw.herokuapp.com
確定各組已經利用組長 Gmail 郵箱登記 https://www.heroku.com/ 帳號後, 隨後登入 heroku 的帳號即為組長的 Gmail 郵箱, 密碼則為登記時所自選包含至少一個特殊符號的密碼.
假設第一組組長學號為 40628423, 且 Gmail 為 [email protected], 則預計建立的雲端應用程式名稱為 vecp-40628423, 之後設定完成的雲端網站將為: https://vecp-40628423.herokuapp.com
在命令列中輸入:
heroku login
系統將會回應 (以 [email protected] 帳號登入為例) :
Enter your Heroku credentials:
Email: [email protected]
Password: ********************
Logged in as [email protected]
登入後, heroku 會將登入資料存入 y:\home_netrc 檔案中, 之後對遠端 heroku 的對應倉儲進行操作
當組長在 heroku 建立應用程式後, 進入 settings 中下方複製該應用程式對應的 git 網址, 例如: 與 vecp-40628423 應用程式對應的 git 網址為: https://git.heroku.com/vecp-40628423.git
在近端隨身系統的命令列中, 更換目錄到 y:\tmp 目錄中, 以 git clone 指令, 取下遠端 heroku 應用程式的倉儲內容 (一開始為空倉儲):
git clone https://git.heroku.com/vecp-40628423.git
所取下的倉儲會以 vecp-40628423 目錄存檔, 空倉儲目錄中, 只會有一個 .git 目錄.
接下來, 以命令列, 在 y:\tmp 目錄中執行下列指令, 取下分組期末專案網站樣本:
git clone https://github.com/mdecourse/a2015fallhw
完成後, y:\tmp 目錄中會增加 vecp-40628423 目錄 (也就是各組所建立的 heroku 應用程式名稱), 以及 a2015fallhw 等兩個目錄, 接下來刪除 a2015fallhw 目錄中的 .git 目錄後, 將其餘的檔案複製到 vecp-40628423 目錄中.
接下來要操作 git 指令, 將各組 vecp-40628423 應用程式的近端內容, 提交推送到雲端, 這時需要先設定 git 使用者的對應資料, 必須在命令列中執行下列指令 (可以在 y:\tmp\vecp-40628423 目錄中執行):
git config --global user.email "[email protected]"
git config --global user.name "40628423"
完成上述指令後, git 會將身分設定資料存入 y:\home.gitconfig 檔案中.
接下來, 在 y:\tmp\vecp-40628423 目錄中執行:
git add .
git commit -m "initial add"
git push
以上指令執行後, 若一切正常, 遠端的 heroku 雲端系統將會啟動對應的應用程式, 完成後, 使用者就可以利用瀏覽器連線到: https://vecp-40628423.herokuapp.com 檢視所建立的雲端系統, 其內容將與 http://a2015fallhw.herokuapp.com 相同.
由於使用的 heroku 雲端帳號屬於免收費類別, 因此每月只提供約 20 天的連線用量, 若一定時間無連線需求, 雲端主機便會自動關機, 等待有連結要求時, 再同步開機, 而且若使用者透過瀏覽器更改網站內容, 每隔幾十分鐘網站內容將會自動回復為原始倉儲中的版本.
以下的 Lua 程式碼, 用來控制 https://github.com/mdecourse/vecp2018/blob/gh-pages/v-rep/YouBot_interactive.ttt, 是 V-rep 平台中的一個場景, 請試著從中找出已經看得懂的程式語法.
function deg2rad(deg)
return deg*math.pi/180
end
function rad2deg(rad)
return rad*180/math.pi
end
function nullFunc(arg)
return arg
end
function toggleRadians(ui,id,newVal)
if (newVal==2) then
angleTo = deg2rad
angleFrom = rad2deg
else
angleTo = nullFunc
angleFrom = nullFunc
end
end
applyJoints=function(jointHandles,joints)
for i=1,#jointHandles,1 do
simSetJointPosition(jointHandles[i],joints[i])
end
end
getJoints=function(jointHandles,angles)
angles={0,0,0,0,0,0,0,0}
for i=1,#jointHandles,1 do
angles[i]=simGetJointPosition(jointHandles[i])
end
return angles
end
updateActualText=function(jointHandles, angles)
local ang_str="( "
for i=1,#jointHandles,1 do
-- simExtCustomUI_setLabelText(ui,5000+i,string.format('Actual = %+6.3f', angles[i]))
ang_str=ang_str..string.format("%6.3f, ", angles[i])
end
ang_str=string.sub(ang_str,1,-3)
ang_str=ang_str.." )"
simExtCustomUI_setLabelText(ui,1237,ang_str)
end
function changeAllSliders(ui,q)
for i=1,#jh,1 do
simExtCustomUI_setSliderValue(ui,4000+i,q[i]*1000)
simExtCustomUI_setLabelText(ui,3000+i,string.format('Reference = %+6.3f',q[i]))
end
end
function sliderChange(ui,id,newVal)
for i=1,#jh,1 do
if (id==4000+i) then
simExtCustomUI_setLabelText(ui,3000+i,string.format('Reference = %+6.3f',newVal/1000))
ref_ang[i]=newVal/1000
break
end
end
end
function mysplit(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t,str)
end
return t
end
function fulljointEntry(ui,id,newVal)
if (newVal==enteredString) then
enteredString=newVal
out=string.format("Already processed and sent this string... try editing")
simExtCustomUI_setLabelText(ui, 1236, out)
return
end
enteredString=newVal
local q=mysplit(newVal,",")
local out=""
if (#q==0) then
out=string.format("No conversions completed <br> Are you separating with commas?")
simExtCustomUI_setLabelText(ui, 1236, out)
return
elseif (#q<#jh) then
out=string.format("Not enough configuration variables specified")
simExtCustomUI_setLabelText(ui, 1236, out)
return
elseif (#q>#jh) then
out=string.format("Too many configuration variables specified")
simExtCustomUI_setLabelText(ui, 1236, out)
return
end
for i=1,#q,1 do
qtest=tonumber(q[i])
if (qtest==nil) then
out=string.format("Could not convert entry number %d:<br> Entered='",i,q[i])..q[i].."'"
simExtCustomUI_setLabelText(ui, 1236, out)
return
else
q[i]=qtest
end
end
simExtCustomUI_setLabelText(ui, 1236, "Successful conversion:<br>"..newVal)
changeAllSliders(ui, q)
ref_ang = q
end
function jointEntry(ui,id,newVal)
angle = tonumber(newVal)
if (angle==nil) then
print("Could not convert number..."..newVal)
return
end
-- if (angle >= 2*math.pi) then
-- print("Clipping angle to 2pi")
-- angle = 2*math.pi
-- end
-- if (angle <= -2*math.pi) then
-- print("Clipping angle to -2pi")
-- angle = -2*math.pi
-- end
for i=1,#jh,1 do
if (id==7000+i) then
simExtCustomUI_setLabelText(ui,3000+i,string.format('Reference = %+6.3f',angle))
ref_ang[i]=angle
changeAllSliders(ui, ref_ang)
break
end
end
end
function eul2so3_xyzr(a,b,c)
-- Build empty array
R = {}
for i=1,3,1 do
R[i] = {}
for j=1,3,1 do
R[i][j] = 0
end
end
-- calculate constants
local c1,s1 = math.cos(a),math.sin(a)
local c2,s2 = math.cos(b),math.sin(b)
local c3,s3 = math.cos(c),math.sin(c)
-- fill out values:
-- https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
R[1][1] = c2*c3
R[1][2] = -c2*s3
R[1][3] = s2
R[2][1] = c1*s3+c3*s1*s2
R[2][2] = c1*c3-s1*s2*s3
R[2][3] = -c2*s1
R[3][1] = s1*s3-c1*c3*s2
R[3][2] = c3*s1+c1*s2*s3
R[3][3] = c1*c2
return R
end
function so3andp2se3(R,p)
local g = {}
for i=1,4,1 do
g[i] = {}
for j=1,4,1 do
if (i<=3) then
if (j<=3) then
g[i][j] = R[i][j]
else
g[i][j] = p[i]
end
else
if (j<=3) then
g[i][j] = 0
else
g[i][j] = 1
end
end
end
end
return g
end
function createSE3string(pos,ori)
-- first let's convert the orientation into an SE(3) matrix:
local R=eul2so3_xyzr(ori[1], ori[2], ori[3])
local g=so3andp2se3(R,pos)
local out="<b><big><tt>"
for i=1,4,1 do
out=out.."| "
for j=1,4,1 do
out=out..string.format(" %+6.3f",g[i][j])
end
out=out.." | <br>"
end
out=out.."</tt></big></b>"
return out
end
function calcSE3(ui, id, target, reference)
pos=simGetObjectPosition(target,reference)
ori=simGetObjectOrientation(target,reference)
if pos and ori then
out=createSE3string(pos,ori)
simExtCustomUI_setLabelText(ui,id,out)
end
end
function closeEventHandler(h)
simAddStatusbarMessage('Window '..h..' is closing...')
simExtCustomUI_hide(h)
end
if (sim_call_type==sim_childscriptcall_initialization) then
-- joint limits:
-- X: (-2, 2)
-- Y: (-2, 2)
-- Th: (-360, 360)
-- 1: (-168, 168)
-- 2: (-64, 89)
-- 3: (-150, 145)
-- 4: (-102, 102)
-- 5: (-160, 160)
xml = [[
<ui closeable="false" onclose="closeEventHandler" resizable="true">
<tabs>
<tab title="Enter Config and SE(3) Value">
<group>
<group layout="vbox">
<label text="<big> Configuration Entry:</big>" wordwrap="false" style="font-weight: bold;"/>
<label text="Enter 8 comma-separated angles" />
<edit value="" oneditingfinished="fulljointEntry" />
<label value="" wordwrap="false" />
<label text="<big> Current configuration:</big>" wordwrap="false" style="font-weight: bold;"/>
<group layout="vbox">
<label value="" id="1237" wordwrap="true" />
</group>
<label text="<big> Messages:</big>" wordwrap="false" style="font-weight: bold;"/>
<group layout="vbox">
<label value="" id="1236" wordwrap="true" />
</group>
</group>
<group>
<!-- <group> -->
<label text="<big> Current SE(3) (world to end-effector):</big>" wordwrap="false" style="font-weight: bold;"/>
<!-- <button text="Calculate SE(3) transform:" onclick="calcSE3" id="1235"/> -->
<label text="T(θ) = " wordwrap="false" />
<label text="" id="1234" wordwrap="false" />
<!-- </group> -->
<!-- <group> -->
<!-- <label text="<big> Settings:</big>" wordwrap="false" style="font-weight: bold;"/> -->
<!-- <checkbox text="Use degrees instead of radians?" checked="false" onchange="toggleRadians" /> -->
<!-- </group> -->
</group>
<group>
<!-- <group> -->
<label text="<big> Current SE(3) (world to youBot base):</big>" wordwrap="false" style="font-weight: bold;"/>
<!-- <button text="Calculate SE(3) transform:" onclick="calcSE3" id="1235"/> -->
<label text="T(θ) = " wordwrap="false" />
<label text="" id="1235" wordwrap="false" />
<!-- </group> -->
<!-- <group> -->
<!-- <label text="<big> Settings:</big>" wordwrap="false" style="font-weight: bold;"/> -->
<!-- <checkbox text="Use degrees instead of radians?" checked="false" onchange="toggleRadians" /> -->
<!-- </group> -->
</group>
<stretch />
</group>
</tab>
<tab title="Joint Angle Sliders">
<group layout="grid" >
<group>
<group layout="grid">
<label text="<big> Chassis X:</big>" id="6001" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3001" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5001" wordwrap="false" /> -->
</group>
<hslider id="4001" tick-position="above" tick-interval="333" minimum="-2000" maximum="2000" onchange="sliderChange" />
<group layout="grid">
<label text="Enter position (m):" />
<edit value="" id="7001" oneditingfinished="jointEntry" />
</group>
</group>
<group>
<group layout="grid">
<label text="<big> Arm 2:</big>" id="6005" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3005" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5005" wordwrap="false" /> -->
</group>
<hslider id="4005" tick-position="above" tick-interval="222" minimum="-1117" maximum="1553" onchange="sliderChange" />
<group layout="grid">
<label text="Enter joint angle (rad):" />
<edit value="" id="7005" oneditingfinished="jointEntry" />
</group>
</group>
<br/>
<group>
<group layout="grid">
<label text="<big> Chassis Y:</big>" id="6002" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3002" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5002" wordwrap="false" /> -->
</group>
<hslider id="4002" tick-position="above" tick-interval="333" minimum="-2000" maximum="2000" onchange="sliderChange" />
<group layout="grid">
<label text="Enter position (m):" />
<edit value="" id="7002" oneditingfinished="jointEntry" />
</group>
</group>
<group>
<group layout="grid">
<label text="<big> Arm 3:</big>" id="6006" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3006" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5006" wordwrap="false" /> -->
</group>
<hslider id="4006" tick-position="above" tick-interval="429" minimum="-2620" maximum="2530" onchange="sliderChange" />
<group layout="grid">
<label text="Enter joint angle (rad):" />
<edit value="" id="7006" oneditingfinished="jointEntry" />
</group>
</group>
<br/>
<group>
<group layout="grid">
<label text="<big> Chassis �:</big>" id="6003" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3003" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5003" wordwrap="false" /> -->
</group>
<hslider id="4003" tick-position="above" tick-interval="523" minimum="-3140" maximum="3140" onchange="sliderChange" />
<group layout="grid">
<label text="Enter joint angle (rad):" />
<edit value="" id="7003" oneditingfinished="jointEntry" />
</group>
</group>
<group>
<group layout="grid">
<label text="<big> Arm 4:</big>" id="6007" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3007" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5007" wordwrap="false" /> -->
</group>
<hslider id="4007" tick-position="above" tick-interval="296" minimum="-1780" maximum="1780" onchange="sliderChange" />
<group layout="grid">
<label text="Enter joint angle (rad):" />
<edit value="" id="7007" oneditingfinished="jointEntry" />
</group>
</group>
<br/>
<group>
<group layout="grid">
<label text="<big> Arm 1:</big>" id="6004" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3004" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5004" wordwrap="false" /> -->
</group>
<hslider id="4004" tick-position="above" tick-interval="488" minimum="-2932" maximum="2932" onchange="sliderChange" />
<group layout="grid">
<label text="Enter joint angle (rad):" />
<edit value="" id="7004" oneditingfinished="jointEntry" />
</group>
</group>
<group>
<group layout="grid">
<label text="<big> Arm 5:</big>" id="6008" wordwrap="false" style="font-weight: bold;"/>
<label text="Reference = 0.000" id="3008" wordwrap="false" />
<!-- <label text="Actual = 0.000" id="5008" wordwrap="false" /> -->
</group>
<hslider id="4008" tick-position="above" tick-interval="481" minimum="-2890" maximum="2890" onchange="sliderChange" />
<group layout="grid">
<label text="Enter joint angle (rad):" />
<edit value="" id="7008" oneditingfinished="jointEntry" />
</group>
</group>
</group>
</tab>
</tabs>
</ui>
]]
ui=simExtCustomUI_create(xml)
-- get joints:
jh={-1,-1,-1,-1,-1,-1,-1,-1}
jh[1]=simGetObjectHandle('World_X_Joint')
jh[2]=simGetObjectHandle('World_Y_Joint')
jh[3]=simGetObjectHandle('World_Th_Joint')
for i=4,#jh,1 do
jh[i]=simGetObjectHandle('Joint'..(i-3))
end
-- for i=1,#jh,1 do
-- print(string.format("jh[%d] = %d",i,jh[i]))
-- end
-- base=simGetObjectHandle('ArmBase_Frame')
world=simGetObjectHandle('WorldFrame')
base=simGetObjectHandle('BaseVisual')
ee=simGetObjectHandle('EE_Frame')
-- fill out initial string:
calcSE3(ui, 1234, ee, world)
calcSE3(ui, 1235, base, world)
-- array for reference angle
ref_ang={0,0,0,0,0,0,0,0}
-- array for storing when angles where manually entered
enteredString=""
-- angle parsing
toggleRadians(ui,0,0)
end
if (sim_call_type==sim_childscriptcall_actuation) then
applyJoints(jh, ref_ang)
-- array for actual angle
act_ang = getJoints(jh)
updateActualText(jh, act_ang)
calcSE3(ui, 1234, ee, world)
calcSE3(ui, 1235, base, world)
end
if (sim_call_type==sim_childscriptcall_sensing) then
end
if (sim_call_type==sim_childscriptcall_cleanup) then
simExtCustomUI_destroy(ui)
end
https://www.lua.org/pil/1.html
print("Hello World")
大家可以利用 http://mde.tw/vecp2018/lua/SchoolProject/ 練習簡單的 Lua 程式, 接下來練習函式的定義與在瀏覽器中取使用者輸入的用法:
-- 導入 js 模組
js = require("js")
-- 取得 window
window = js.global
-- defines a factorial function
function fact (n)
if n == 0 then
return 1
else
return n * fact(n-1)
end
end
-- 利用 window:prompt 方法回應取得使用者的輸入
a = window:prompt("enter a number:")
print(fact(a))
Lua 程式: https://github.com/mdecourse/vecp2018/blob/gh-pages/lua/lesson1_traffic_light.lua
V-rep 配合場景: https://github.com/mdecourse/vecp2018/blob/gh-pages/lua/lesson1_workingTrafficLight.ttt
學習目標:
下載簡易版隨身程式系統, 其中包含 SciTE 程式編輯與執行器, Lua 解譯器, Python 解譯器, 以及 V-rep 教育版程式套件, Fossil SCM, 以及 Solvespace 參數式繪圖程式, Zoomit, ShareX, ProcessExplorer, 並且學習如何使用 USB 上的隨身程式系統.
學習簡單的 Lua 程式語法, 並利用 V-rep 模擬系統練習各種語法的應用.
學習如何利用 Fossil SCM 在隨身碟中建立倉儲, 如何管理自己的計算機程式倉儲.
學習如何利用 Solvespace 建立簡單的 3D 幾何物件後, 輸入 V-rep 中, 並以 Lua 程式控制.
學習如何利用 ShareX 錄製 Windows 環境下的練習操作影片, 並如何將這些影片上傳到 Youtube.
請各組完成 Heroku 分組內容管理網站後, 將連結回報至下列 comment 中.
40628448
40628438
40628450
40628422
40628456
https://github.com/mdecourse/wcms-scrum3 是 http://wcms-scrum3.herokuapp.com/ 雲端網站的同步倉儲, http://wcms-scrum3.herokuapp.com/lua2 中所採行的 Lua 程式碼呼叫方式與原先 vecp2018 SchoolProject 中的方法不同, 是將所有的程式放在同一個檔案中, 而最新的做法則是分開各程式檔案, 並且可以直接以 URL 連結, 到特定目錄中擷取.
這裡要將最新作法從雲端移植到 Github Pages 中. 完成後:
http://mde.tw/vecp2018/lua/SchoolProject
可以透過 http://mde.tw/vecp2018/lua/SchoolProject/?filename=gear1 將 ext/gear1.lua 的內容執行後 (採用同名 function return 程式內容).
ven1a - 2018/03/02 起每週 (五) 晚上 10-11 節 (18:30-20:00)
課程介紹: 本課程名稱為計算機程式, 將分別利用 Lua, Python 與 C 說明計算機程式的基本功能.
第一週準備工作: 請各學員利用學校配發的 Gmail 帳號, 申請 Github 帳號, 登入 Github 後, 連結至 https://github.com/mdecourse/vecp2018/issues 後, 了解如何在各週上課內容 issues 中提出問題、心得與相關討論議題.
http://lua-users.org/wiki/ScopeTutorial
Python 機器人控制:
. https://github.com/clamesc/Training-Neural-Networks-for-Event-Based-End-to-End-Robot-Control
Lua 程式設計教學:
. Lua 簡介
. https://cwchen.tw/lua-prog/
. http://www.runoob.com/lua/lua-tutorial.html
. 從 Javascript 學 Lua
. http://lua-users.org/wiki/ObjectOrientationTutorial
Lua 應用:
. 基因演算與類神經網路應用
. 靜態網頁轉檔
V-rep 建模:
. https://www.jianshu.com/p/eb3f38c0c5fa
. https://github.com/Johan944/Need4Stek
. https://github.com/eligoldweber/DriverlessCarSimulation
. https://github.com/jokla/vrep_car_simulation
. https://github.com/Eric-Gonzalez/car-simulator
. https://github.com/AgrawalAmey/rl-car
碰撞檢測:
. https://github.com/vrld/HC
行走車: https://github.com/mdecourse/vecp2018/blob/gh-pages/final/vecp_w10_epuck_maze.ttt
請下載後, 以 V-rep 開啟後, 修改控制程式, 讓行走車可順利抵達目標點.
利用 https://www.msys2.org/ 編譯從 https://www.lua.org/download.html 下載的原始碼
mingw32-make mingw
就可以編譯取得 lua.exe, luac.exe 與 liblua.a, 接下來利用 SciTE 的 lua.properties 設定, 可以解譯 .lua 程式:
lua.properties 檔案:
# Define SciTE settings for Lua files.
# Lua 5.x highlighting is enabled by default. For other choices,
# including Lua 4 highlighting, see below.
file.patterns.lua=*.lua
*source.patterns.lua=$(file.patterns.lua);
shbang.lua=lua
filter.lua=Lua (lua)|$(file.patterns.lua)|
*filter.lua=$(filter.lua)
lexer.$(file.patterns.lua)=lua
*language.lua=Lu&a|lua||
word.chars.lua=$(chars.alpha)$(chars.numeric)$(chars.accented)_%
word.characters.$(file.patterns.lua)=$(word.chars.lua)
#### Lua 4.0.1
# Keywords
keywordclass.lua4=\
and break do else elseif \
end for function if in \
local nil not or repeat \
return then until while
# Basic Functions
keywordclass2.lua4=\
_ALERT assert call collectgarbage copytagmethods \
dofile dostring error foreach foreachi \
gcinfo getglobal getn gettagmethod globals \
newtag next print rawget rawset \
setglobal settag settagmethod sort tag \
tonumber tostring tinsert tremove type \
_VERSION _ERRORMESSAGE
# String Manipulation & Mathematical Functions
keywordclass3.lua4=\
strbyte strchar strfind strlen strlower \
strrep strsub strupper format gsub \
abs acos asin atan atan2 \
ceil cos deg exp floor \
log log10 max min mod \
rad sin sqrt tan frexp \
ldexp random randomseed PI
# Input and Output Facilities & System Facilities
keywordclass4.lua4=\
openfile closefile readfrom writeto appendto \
remove rename flush seek tmpname read write \
clock date execute exit getenv setlocale \
_INPUT _OUTPUT _STDIN _STDOUT _STDERR -- file descriptors
# Debug (not enabled by default)
keywordclass5.lua4=\
getinfo getlocal setlocal setcallhook setlinehook
#### Lua 5.0.3
# Keywords
keywordclass.lua50=$(keywordclass.lua4) false true
# Basic Functions
keywordclass2.lua5=\
assert collectgarbage dofile error _G \
getmetatable ipairs loadfile next pairs \
pcall print rawequal rawget rawset \
setmetatable tonumber tostring type _VERSION \
xpcall string table math coroutine io os debug
keywordclass2.lua50=$(keywordclass2.lua5) \
getfenv gcinfo loadlib loadstring require \
setfenv unpack _LOADED LUA_PATH _REQUIREDNAME
# String, Table , Mathematical, Bitwise
keywordclass3.lua5=\
string.byte string.char string.dump string.find string.format \
string.gsub string.len string.lower string.rep string.sub string.upper \
table.concat table.insert table.remove table.sort \
math.abs math.acos math.asin math.atan math.atan2 \
math.ceil math.cos math.deg math.exp math.floor \
math.frexp math.ldexp math.log math.max math.min \
math.pi math.pow math.rad math.random math.randomseed \
math.sin math.sqrt math.tan
keywordclass3.lua50=$(keywordclass3.lua5) \
string.gfind \
table.foreach table.foreachi table.getn table.setn \
math.mod math.log10
# Coroutine, Input/Output, System, Package
keywordclass4.lua50=\
coroutine.create coroutine.resume coroutine.status coroutine.wrap coroutine.yield \
io.close io.flush io.input io.lines io.open \
io.output io.read io.tmpfile io.type io.write \
io.stdin io.stdout io.stderr \
os.clock os.date os.difftime os.execute os.exit \
os.getenv os.remove os.rename os.setlocale os.time \
os.tmpname
# Debug (not enabled by default)
keywordclass5.lua50=\
debug.debug debug.gethook debug.getinfo debug.getlocal debug.getupvalue \
debug.setlocal debug.setupvalue debug.sethook debug.traceback
#### Lua 5.1.4
# Keywords
keywordclass.lua51=$(keywordclass.lua50)
# Basic Functions
keywordclass2.lua51=$(keywordclass2.lua5) \
getfenv load loadstring select \
setfenv unpack package
# String, Table , Mathematical, Bitwise
keywordclass3.lua51=$(keywordclass3.lua5) \
string.gmatch string.match string.reverse \
table.maxn \
math.cosh math.fmod math.huge math.log10 math.modf \
math.sinh math.tanh
# Coroutine, Input/Output, System, Package
keywordclass4.package=\
require package.cpath package.loaded \
package.loadlib package.path package.preload
keywordclass4.lua51=$(keywordclass4.lua50) \
coroutine.running io.popen \
module package.loaders package.seeall \
$(keywordclass4.package)
# Debug (not enabled by default)
keywordclass5.lua51=$(keywordclass5.lua50) \
debug.getfenv debug.getmetatable debug.getregistry debug.setfenv debug.setmetatable
#### Lua 5.2.0
# Keywords
keywordclass.lua52=$(keywordclass.lua50) goto
# Basic Functions
keywordclass2.lua52=$(keywordclass2.lua5) \
load rawlen select package bit32 _ENV
# String, Table , Mathematical, Bitwise
keywordclass3.bit32=\
bit32.arshift bit32.band bit32.bnot bit32.bor bit32.btest \
bit32.bxor bit32.extract bit32.replace bit32.lrotate bit32.lshift \
bit32.rrotate bit32.rshift
keywordclass3.lua52=$(keywordclass3.lua5) \
string.gmatch string.match string.reverse \
table.pack table.unpack \
math.cosh math.fmod math.huge math.modf math.sinh math.tanh \
$(keywordclass3.bit32)
# Coroutine, Input/Output, System, Package
keywordclass4.lua52=$(keywordclass4.lua50) \
coroutine.running io.popen \
package.config package.searchers package.searchpath \
$(keywordclass4.package)
# Debug (not enabled by default)
keywordclass5.lua52=$(keywordclass5.lua50) \
debug.getmetatable debug.getregistry debug.setmetatable \
debug.getuservalue debug.setuservalue debug.upvalueid debug.upvaluejoin
#### Lua 5.3.0
# Keywords
keywordclass.lua53=$(keywordclass.lua50) goto
# Basic Functions
keywordclass2.lua53=$(keywordclass2.lua5) \
load rawlen select package utf8 _ENV
# String, UTF8, Table , Mathematical
keywordclass3.utf8=\
utf8.char utf8.charpattern utf8.codes \
utf8.codepoint utf8.len utf8.offset
keywordclass3.lua53=\
string.byte string.char string.dump string.find string.format \
string.gmatch string.gsub string.len string.lower string.match \
string.pack string.packsize string.rep \
string.reverse string.sub string.unpack string.upper \
table.concat table.insert table.move table.pack \
table.remove table.sort table.unpack \
math.abs math.acos math.asin math.atan \
math.ceil math.cos math.deg math.exp \
math.floor math.fmod math.huge \
math.log math.max math.maxinteger math.min math.mininteger \
math.modf math.pi math.rad \
math.random math.randomseed math.sin \
math.sqrt math.tan \
math.tointeger math.type math.ult \
$(keywordclass3.utf8)
# Coroutine, Input/Output, System, Package
keywordclass4.lua53=$(keywordclass4.lua50) \
coroutine.isyieldable coroutine.running io.popen \
package.config package.searchers package.searchpath \
$(keywordclass4.package)
# Debug (not enabled by default)
keywordclass5.lua53=$(keywordclass5.lua52)
#### Lua 5.x
# Keywords
keywordclass.lua5x=$(keywordclass.lua53)
# Basic Functions
keywordclass2.lua5x=$(keywordclass2.lua5) \
getfenv gcinfo load loadlib loadstring \
require select setfenv unpack \
_LOADED LUA_PATH _REQUIREDNAME \
package rawlen package bit32 utf8 _ENV
# String, Table , Mathematical, Bitwise
keywordclass3.lua5x=$(keywordclass3.lua5) \
string.gfind string.gmatch string.match string.reverse \
string.pack string.packsize string.unpack \
table.foreach table.foreachi table.getn table.setn \
table.maxn table.pack table.unpack table.move \
math.cosh math.fmod math.huge math.log10 math.modf \
math.mod math.sinh math.tanh math.maxinteger math.mininteger \
math.tointeger math.type math.ult \
$(keywordclass3.bit32) \
$(keywordclass3.utf8)
# Coroutine, Input/Output, System, Package
keywordclass4.lua5x=$(keywordclass4.lua50) \
coroutine.isyieldable coroutine.running io.popen \
module package.loaders package.seeall \
package.config package.searchers package.searchpath \
$(keywordclass4.package)
# Debug (not enabled by default)
keywordclass5.lua5x=$(keywordclass5.lua50) \
debug.getfenv debug.getmetatable debug.getregistry debug.setfenv debug.setmetatable \
debug.getuservalue debug.setuservalue debug.upvalueid debug.upvaluejoin
# Keyword highlighting selection
# Options: lua4, lua50, lua51, lua52, lua53, lua5x (default)
# or enable everything like this: $(keywordclass.lua4)$(keywordclass.lua5x)
keywords.$(file.patterns.lua)=$(keywordclass.lua5x)
keywords2.$(file.patterns.lua)=$(keywordclass2.lua5x)
keywords3.$(file.patterns.lua)=$(keywordclass3.lua5x)
keywords4.$(file.patterns.lua)=$(keywordclass4.lua5x)
# Add keywords5, 6, 7 & 8 for user-defined libraries
#keywords5.$(file.patterns.lua)=
#keywords6.$(file.patterns.lua)=
#keywords7.$(file.patterns.lua)=
#keywords8.$(file.patterns.lua)=
#~ statement.indent.$(file.patterns.lua)=5 do else function then
#~ statement.lookback.$(file.patterns.lua)=20
indent.maintain.$(file.patterns.lua)=1
comment.block.lua=--~
comment.block.at.line.start.lua=1
# Lua styles
#Default
style.lua.32=$(font.code.base),fore:#000000
# White space: Visible only in View Whitespace mode (or if it has a back colour)
style.lua.0=fore:#FF0000
# Block comment (Lua 5.0)
style.lua.1=$(colour.code.comment.box),$(font.code.comment.box),back:#D0F0F0,eolfilled
# Line comment
style.lua.2=$(colour.code.comment.line),$(font.code.comment.line)
# Doc comment -- Not used in Lua (yet?)
style.lua.3=$(colour.notused),$(font.notused)
# Number
style.lua.4=$(colour.number)
# Keyword
style.lua.5=$(colour.keyword)
# (Double quoted) String
style.lua.6=$(colour.string)
# Character (Single quoted string)
style.lua.7=$(colour.char)
# Literal string
style.lua.8=$(colour.string),$(font.code.comment.box),back:#E0FFFF
# Preprocessor (obsolete in Lua 4.0 and up)
style.lua.9=$(colour.preproc)
# Operators
style.lua.10=$(colour.operator)
# Identifier (everything else...)
style.lua.11=
# End of line where string is not closed
style.lua.12=back:#E0C0E0,eolfilled
# Other keywords (bozo test colors, but toned down ;)
style.lua.13=$(style.lua.5),back:#F5FFF5
style.lua.14=$(style.lua.5),back:#F5F5FF
style.lua.15=$(style.lua.5),back:#FFF5F5
style.lua.16=$(style.lua.5),back:#FFF5FF
style.lua.17=$(style.lua.5),back:#FFFFF5
style.lua.18=$(style.lua.5),back:#FFA0A0
style.lua.19=$(style.lua.5),back:#FFF5F5
# Labels
style.lua.20=fore:#7F7F00
# Braces are only matched in operator style
braces.lua.style=10
# compatible with LuaBinaries for Lua 5.1; will work on both platforms.
command.compile.*.lua=y:\lua-5.3.4\bin\luac.exe -o "$(FileName).luc" "$(FileNameExt)"
# Lua 5.1
command.go.*.lua=y:\lua-5.3.4\bin\lua.exe "$(FileNameExt)"
# Lua 4.0
#command.go.*.lua=Lua-4.0.exe -c -f "$(FileNameExt)"
https://github.com/SCons/scons
從 https://github.com/fengari-lua/fengari-web 取得 fengari-web.js, 利用 https://ace.c9.io/ 當作編輯器, 可以組合成 https://github.com/davchoo/SchoolProject, 加以修改除錯後成為 http://mde.tw/vecp2018/lua/SchoolProject/
https://vecp-40628435.herokuapp.com/lua40628435
https://vecp-40628435.herokuapp.com/lua40628414
https://vecp-40628435.herokuapp.com/lua40628417
https://vecp-40628408.herokuapp.com/lua40628408
https://vecp-40628408.herokuapp.com/lua40628428
https://vecp-40628408.herokuapp.com/lua40628436
https://vecp-40628427.herokuapp.com/lua40628427
https://vecp-40628427.herokuapp.com/lua40628437
https://vecp-40628427.herokuapp.com/lua40628412
https://vecp-40328410.herokuapp.com/lua40328410
https://vecp-40328410.herokuapp.com/lua40628448
https://vecp-40328410.herokuapp.com/lua40328421
https://vecp-40628451.herokuapp.com/lua40628451
https://vecp-40628451.herokuapp.com/lua40628453
https://vecp-40628451.herokuapp.com/lua40628438
https://vecp-40628407.herokuapp.com/lua40628407
https://vecp-40628407.herokuapp.com/lua40628401
https://vecp-40628407.herokuapp.com/lua40628445
https://vecp-40628442.herokuapp.com/lua40628442
https://vecp-40628442.herokuapp.com/lua40628452
https://vecp-40628442.herokuapp.com/lua40628454
https://vecp-a40628440.herokuapp.com/lua40628440
https://vecp-a40628440.herokuapp.com/lua40628413
https://vecp-a40628440.herokuapp.com/lua40628450
https://vecp-40628418.herokuapp.com/lua40628418
https://vecp-40628418.herokuapp.com/lua40628411
https://vecp-40628418.herokuapp.com/lua40628421
https://vecp-40628431.herokuapp.com/lua40628431
https://vecp-40628431.herokuapp.com/lua40628424
https://vecp-40628431.herokuapp.com/lua40628425
https://vecp-40628405.herokuapp.com/lua40628405
https://vecp-40628405.herokuapp.com/lua40628410
https://vecp-40628405.herokuapp.com/lua40628416
https://vecp-40628404.herokuapp.com/lua40628404
https://vecp-40628404.herokuapp.com/lua40628422
https://vecp-40628404.herokuapp.com/lua40628456
第九週前以 3 人一組, 完成下列要求:
整理 #11 中所列出的 Lua 程式語法
利用 http://mde.tw/vecp2018/lua/SchoolProject/ 繪製虎尾科技大學校徽
利用 http://mde.tw/vecp2018/lua/SchoolProject/ 繪製美國國旗
請將上述內容寫在各組的 vecp2018 倉儲中
各組員完成期中報告後, 請將連結留在下列 comments 中.
http://mde.tw/vecp2018/lua/SchoolProject 之所以能讓使用者能夠直接在瀏覽器中執行簡單的 Lua 程式範例,
是因為利用 Javascript 重寫 Lua 解譯器, , 因此具有 Javascript 程式語言的特性, 其中包括 https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
所謂的 localStorage, 是能讓使用者透過 Javascript 程式, 將資料存在近端的瀏覽器中, 也能取出利用.
localStorage 典型的應用之一, 就是當使用者在 http://mde.tw/vecp2018/lua/SchoolProject 的編輯器中輸入 Lua 程式碼後, 按下執行時, editor.lua 就會將編輯器中的 Lua 程式碼放入與 "lua_src_id" 字串對應的 localStorage 儲存空間中, 且在載入頁面時就啟動執行的 ace/FileSaver.min.js 與 ace/filereader.js 及設定將程式碼存在近端的 Javascript, 就可儲存所執行的 Lua 程式內容.
index.html 內容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<title>How to program in Lua</title>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<!-- 導入 FileSaver 與 filereader -->
<script type="text/javascript" src="ace/FileSaver.min.js"></script>
<script type="text/javascript" src="ace/filereader.js"></script>
<script type="text/javascript">
function doSave(storage_id, filename){
var blob = new Blob([localStorage[storage_id]], {type: "text/plain;charset=utf-8"});
filename = document.getElementById(filename).value
saveAs(blob, filename+".lua");
}
</script>
</head>
<body>
<header>
<h1 class="center">Hello Lua!</h1>
<div class="repl-container">
<div class="row editor-container">
<div class="col-sm editor">print("Lua is fun!")</div>
<div class="col-sm output"></div>
</div>
<div class="row">
<button type="button" class="btn btn-primary btn-execute">Execute</button>
</div>
<form>
<label>Filename: <input type="text" id="lua_filename" placeholder="input file name"/>.lua</label>
<input type="submit" value="Save" onclick="doSave('lua_src_id', 'lua_filename');"/>
</form>
<br />
</div>
<script src="ace/ace.js"></script>
<script src="ace/mode-lua.js"></script>
<script src="fengari-web.js"></script>
<script src="editor.lua" type="application/lua" async></script>
<script src="editor.js"></script>
<br /><br />
<canvas id="canvas" width="600" height="600"></canvas>
</body>
</html>
editor.lua 內容如下:
local js = require "js"
local __G = _G
local load = load
local pack, unpack = table.pack, table.unpack
local tostring = tostring
local traceback = debug.traceback
local insert = table.insert
local document = js.global.document
local xpcall = xpcall
storage = js.global.localStorage
M = {} --All of the user globals
local newenv = setmetatable({}, {
__index = function(t, k)
local v = M[k]
if v == nil then return __G[k] end
return v;
end,
__newindex = M
})
function js.global.runLua(window, code, outputElm)
--Reset user global table to a clean state
--M = {}
M["_G"] = M
--Redirect print and error to output box
M.print = function(text)
local msgElm = document:createTextNode(text)
msgElm.className = "console-msg"
outputElm:appendChild(msgElm)
outputElm:appendChild(document:createElement("br"))
end
M.error = function(text)
local msgElm = document:createTextNode(text)
msgElm.className = "console-error"
outputElm:appendChild(msgElm)
outputElm:appendChild(document:createElement("br"))
end
--Clean output window
while (outputElm:hasChildNodes()) do
outputElm:removeChild(outputElm.firstChild);
end
--Finally load and run the code
storage:setItem("lua_src_id", tostring(code))
local fn, err = load(tostring(code), "sandbox", "bt", newenv)
if fn then
local results = pack(xpcall(fn, traceback))
if results[1] then
if results.n > 1 then
M.print(unpack(results, 2, results.n))
end
else
M.print(results[2])
end
else
M.error(err)
end
end
在 Firefox 中, 以 Preferences - General - Downloads 選擇"Always ask me where to save files"
在 Chrome 中, 以 Settings - Advanced - Downloads 選擇 Ask where to save each file before downloading
取自 https://gist.github.com/daurnimator/9dd8168ab14846e880e4b50546b39110#file-fengari-vue-lua
-- Load Vue library
package.loadlib("https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js", "*")
-- Get Object helper
local Object = dofile("https://gist.githubusercontent.com/daurnimator/5a7fa933e96e14333962093322e0ff95/raw/8c6968be0111c7becc485a692162ad100e87d9c7/Object.lua").Object
local myapp = js.new(js.global.Vue, Object{
el = "#foo";
template = [[
<div id="foo">{{message}}</div>
]];
data = Object{
message = "weeee";
}
})
myapp.message = "something else"
取自 https://gist.github.com/daurnimator/5a7fa933e96e14333962093322e0ff95#file-object-lua
local js = require "js"
-- Helper to copy lua table to a new JavaScript Object
-- e.g. Object{mykey="myvalue"}
local function Object(t)
local o = js.new(js.global.Object)
for k, v in pairs(t) do
assert(type(k) == "string" or js.typeof(k) == "symbol", "JavaScript only has string and symbol keys")
o[k] = v
end
return o
end
return {
Object = Object;
}
取自 https://gist.github.com/daurnimator/f5e872f0a988f7bbd025#file-exampleseval-in-lua
local http_request = require "http.request"
local http_util = require "http.util"
local request = http_request.new_from_uri("https://eval.in/")
request.headers:upsert(":method", "POST")
request.headers:upsert("content-type", "application/x-www-form-urlencoded")
request.follow_redirects = false
request:set_body(http_util.dict_to_query{utf8 = "λ", code = 'print("hello")', execute = "on", lang = "ruby/mri-2.2", input = ""})
local headers, stream = request:go()
stream:shutdown()
print(headers:get"location")
取自 https://gist.github.com/daurnimator/f1c7965b47a5658b88300403645541aa#file-tarantool_cqueues-lua
-- This code monkey patches cqueues primitives to allow for transparent use of cqueues inside of tarantool
local cqueues = require "cqueues"
local socket = require "socket" -- https://tarantool.org/en/doc/1.7/reference/reference_lua/socket.html (not luasocket)
local old_step; old_step = cqueues.interpose("step", function(self, timeout)
if cqueues.running() then
return old_step(self, timeout)
else
local t = self:timeout() or math.huge
if timeout then
t = math.min(t, timeout)
end
if t > 0.0 then
socket.iowait(self:pollfd(), self:events(), t)
end
return old_step(self, 0.0)
end
end)
取自 https://gist.github.com/daurnimator/f1c7965b47a5658b88300403645541aa#file-tarantool_http_server-lua
#!/usr/bin/env tarantool
require "tarantool_cqueues"
local fiber = require "fiber"
local http_headers = require "http.headers"
local http_server = require "http.server"
local http_util = require "http.util"
local function reply(myserver, stream) -- luacheck: ignore 212
-- Read in headers
local req_headers = assert(stream:get_headers())
local req_method = req_headers:get ":method"
-- Log request to stdout
assert(io.stdout:write(string.format('[%s] "%s %s HTTP/%g" "%s" "%s"\n',
os.date("%d/%b/%Y:%H:%M:%S %z"),
req_method or "",
req_headers:get(":path") or "",
stream.connection.version,
req_headers:get("referer") or "-",
req_headers:get("user-agent") or "-"
)))
-- Build response headers
local res_headers = http_headers.new()
res_headers:append(":status", "200")
res_headers:append("content-type", "text/plain")
-- Send headers to client; end the stream immediately if this was a HEAD request
assert(stream:write_headers(res_headers, req_method == "HEAD"))
if req_method ~= "HEAD" then
-- Send body, ending the stream
assert(stream:write_chunk("Hello world!\n", true))
end
end
local myserver = assert(http_server.listen {
host = "127.0.0.1";
port = 8000;
onstream = reply;
onerror = function(self, context, op, err)
local msg = op .. " on " .. tostring(context) .. " failed"
if err then
msg = msg .. ": " .. tostring(err)
end
assert(io.stderr:write(msg, "\n"))
end;
})
-- Override :add_stream to call onstream in a new fiber (instead of new cqueues coroutine)
function myserver:add_stream(stream)
fiber.create(function()
fiber.yield() -- want to be called from main loop; not from :add_stream callee
local ok, err = http_util.yieldable_pcall(self.onstream, self, stream)
stream:shutdown()
if not ok then
self:onerror()(self, stream, "onstream", err)
end
end)
end
-- Run server in its own tarantool fibre
fiber.create(function()
assert(myserver:loop())
end)
-- Start another fibre that just prints+sleeps in a loop to show off non-blocking-ness of http server
fiber.create(function()
for i=1, 100 do
print("HELLO ", i)
fiber.sleep(0.1)
end
end)
取自 https://gist.github.com/daurnimator/f1c7965b47a5658b88300403645541aa#file-tarantool_websocket-lua
#!/usr/bin/env tarantool
require "tarantool_cqueues"
local fiber = require "fiber"
package.loaded["http.client"] = nil -- tarantool has a namespace clash
local websocket = require "http.websocket"
fiber.create(function()
local ws = websocket.new_from_uri("wss://ws-feed.gdax.com")
assert(ws:connect())
assert(ws:send([[{"type": "subscribe", "product_id": "BTC-USD"}]]))
for _=1, 5 do
local data = assert(ws:receive())
print(data)
end
assert(ws:close())
end)
-- Start another fibre that just prints+sleeps in a loop to show off non-blocking-ness
fiber.create(function()
for i=1, 100 do
print("HELLO ", i)
fiber.sleep(0.1)
end
end)
取自 https://gist.github.com/daurnimator/72ff05933903af612bebc40aa145d519#file-dom-create-lua
local js = require "js"
local window = js.global
local document = window.document
local function setElement(elem, props)
for k, v in pairs(props) do
if type(k) == "number" then
-- skip
elseif type(v) == "table" then
local to = elem[k]
for kk, vv in pairs(v) do
to[kk] = vv
end
else
elem[k] = v
end
end
for _, v in ipairs(props) do
if type(v) == "string" then
v = document:createTextNode(v)
end
elem:appendChild(v)
end
return elem
end
local function createElement(name, props)
return setElement(document:createElement(name), props)
end
local dom = setmetatable({}, {
__index = function(t, k)
local v = function(props)
return setElement(document:createElement(k), props)
end
t[k] = v
return v
end;
})
setElement(document.body, {
dom.ul {
dom.li{style={color="red"}, "hi"};
dom.li{style={color="green"}, "world"};
};
})
取自 https://gist.github.com/daurnimator/c18b3732f452e58097c68a04f0dc2ac1#file-htmlgen-lua
local document = js.global.document;
local extra = {}
function extra:append(x)
self.__wrapped__:append(x)
return self
end
local function wrap(e)
return setmetatable({
__wrapped__ = e;
}, {
__index = function(e, k)
return extra[k] or e.__wrapped__[k]
end;
})
end
local function create(tag, attr)
local e = document:createElement(tag)
if attr then
for k, v in pairs(attr) do
e:setAttribute(k, v)
end
end
return wrap(e)
end
local _ENV = setmetatable({}, {
__index=function(_, k)
return _G[k] or function(a) return create(k, a) end
end;
})
print(div{id="foo"}:append("a").outerHTML)
取自 https://gist.github.com/daurnimator/45839b0d6bd4a94c58d2d942c04b6789#file-searchpath-lua
local DIRSEP = package.config:sub(1, 1)
local function is_readable(filename)
local fd = io.open(filename, "r")
if fd then
fd:close()
return true
else
return false
end
end
function searchpath(name, path, sep, rep)
assert(type(name) == "string")
assert(type(path) == "string")
if sep == nil then
sep = "%."
else
assert(type(sep) == "string")
sep = sep:gsub("[%%%^%$%(%)%.%[%]%*%+%-%?]", "%%%0") -- need to escape sep so it doesn't get interpreted as a pattern later
end
if rep == nil then
rep = DIRSEP
else
assert(type(rep) == "string")
end
if #sep > 0 then
name = name:gsub(sep, rep)
end
local msg = ""
local repl_name = name:gsub("%%", "%%%%")
for template in path:gmatch("[^;]+") do -- PATH_SEP
local filename = template:gsub("%?", repl_name) -- PATH_MARK
if is_readable(filename) then
return filename
end
msg = msg .. "\n\tno file '" .. filename .. "'"
end
return nil, msg
end
取自 https://gist.github.com/daurnimator/c712a77e312b4ad32f01d3cd412e21f9#file-awesome-cq-lua
local cqueues = require "cqueues"
local cq = cqueues.new()
_G.cq = cq
-- Until https://github.com/pavouk/lgi/issues/111 is fixed we can only use a timer
local cqtimer = gears.timer{timeout=0.01}
cqtimer:connect_signal("timeout", function()
local ok, err, errno, thd = cq:step(0)
if not ok then
naughty.notify({ preset = naughty.config.presets.critical,
title = "Oops, an error happened!",
text = debug.traceback(thd, err) })
end
end)
cqtimer:start()
取自 https://gist.github.com/daurnimator/be276c5d32329e2a9250f4aabeea48a8#file-gen_table-lua
local IDNA_map = {}
local highest
local version
for line in io.lines("IdnaMappingTable.txt") do
local rf, rb, what = line:match("^(%x+)%.%.(%x+) *; *([^#]*)")
if rf then
rf = tonumber(rf, 16)
rb = tonumber(rb, 16)
else
local c
c, what = line:match("^(%x+) *; *([^#]*)")
if c then
c = tonumber(c, 16)
rf = c
rb = c
else
local v = line:match("^# IdnaMappingTable%-(%d+%.%d+%.%d+)")
if v then
version = '"' .. v .. '"'
end
end
end
if what then
local map
what, map = what:match("^([%w_]+) *;?([%x ]*)")
if what == "disallowed" then
elseif what == "valid" or what == "disallowed_STD3_valid" then
for i=rf,rb do
IDNA_map[i] = string.format("%q", utf8.char(i)) -- "true"
if what == "disallowed_STD3_valid" then
IDNA_map[i] = "a and " .. IDNA_map[i] .. " or nil"
end
highest = i
end
elseif what == "mapped" or what == "disallowed_STD3_mapped" or what == "deviation" then
local t = {}
for cp in map:gmatch("%x+") do
table.insert(t, tonumber(cp, 16))
end
local s = utf8.char(table.unpack(t))
for i=rf,rb do
IDNA_map[i] = string.format("%q", s)
if what == "disallowed_STD3_mapped" then
IDNA_map[i] = "a and " .. IDNA_map[i] .. " or nil"
end
highest = i
end
elseif what == "ignored" then
for i=rf,rb do
IDNA_map[i] = '""'
highest = i
end
else
error("Unknown status value: " .. what)
end
end
end
print("return {\n\tunicode_version = " .. version .. ";\n\tget_map = function(a)\n\tlocal t = {")
local optimization_point = 0x2CEA1
for i=1, optimization_point, 16 do
local had_one = false
for c=i, math.min(optimization_point, i+15) do
local v = IDNA_map[c]
if v then
io.write(v, ";")
if #v > 10 then
io.write("\n")
had_one = false
else
had_one = true
end
else
had_one = true
io.write("nil;")
end
end
if had_one then
io.write("\n")
end
end
print("}")
for c=optimization_point+1, highest do
local v = IDNA_map[c]
if v then
print(string.format("t[0x%x]=%s", c, v))
end
end
print("\treturn t\n\tend;\n}")
取自 https://gist.github.com/daurnimator/192dc5b210718dd129cfc1e5986df97b#file-echo_server-lua
local port = arg[1] or "8000"
local nice_server = require "nice_server"
local timeout = 2
local function reply(resp)
local req_body = assert(resp.stream:get_body_as_string(timeout))
local req_body_type = resp.request_headers:get "content-type"
resp.headers:upsert(":status", "200")
resp.headers:append("content-type", req_body_type or "text/plain")
resp:set_body(req_body)
end
assert(nice_server.new {
host = "localhost";
port = port;
reply = reply;
}:loop())
取自 https://gist.github.com/daurnimator/192dc5b210718dd129cfc1e5986df97b#file-nice_server-lua
local cqueues = require "cqueues"
local cc = require "cqueues.condition"
local ce = require "cqueues.errno"
local new_headers = require "http.headers".new
local server = require "http.server"
local version = require "http.version"
local http_util = require "http.util"
local zlib = require "http.zlib"
local default_server = string.format("%s/%s", version.name, version.version)
local error_text = [[
<html>
<head>
<title>503 Internal Server Error</title>
</head>
<body>
An internal server error occured.
</body>
</html>
]]
local response_methods = {}
local response_mt = {
__index = response_methods;
__name = nil;
}
local function new_response(request_headers, stream)
local headers = new_headers();
-- Give some defaults
headers:append(":status", "503")
headers:append("server", default_server)
headers:append("date", http_util.imf_date())
return setmetatable({
request_headers = request_headers;
stream = stream;
-- Record peername upfront, as the client might disconnect before request is completed
peername = select(2, stream:peername());
headers = headers;
body = nil;
}, response_mt)
end
function response_methods:combined_log()
-- Log in "Combined Log Format"
-- https://httpd.apache.org/docs/2.2/logs.html#combined
return string.format('%s - - [%s] "%s %s HTTP/%g" %s %d "%s" "%s"',
self.peername or "-",
os.date("%d/%b/%Y:%H:%M:%S %z"),
self.request_headers:get(":method") or "",
self.request_headers:get(":path") or "",
self.stream.connection.version,
self.headers:get(":status") or "",
self.stream.stats_sent,
self.request_headers:get("referer") or "-",
self.request_headers:get("user-agent") or "-")
end
function response_methods:set_body(body)
self.body = body
local length
if type(self.body) == "string" then
length = #body
end
if length then
self.headers:upsert("content-length", string.format("%d", #body))
end
end
function response_methods:set_503()
local headers = new_headers()
headers:append(":status", "503")
headers:append("server", default_server)
headers:append("date", http_util.imf_date())
self.headers = headers
headers:append("content-type", "text/html")
self:set_body(error_text)
end
function response_methods:enable_compression()
if self.headers:has("content-encoding") then
return false
end
local deflater = zlib.deflate()
local new_body = deflater(self.body, true)
self.headers:append("content-encoding", "gzip")
self.body = new_body
return true
end
local function default_onerror(...)
io.stderr:write(string.format(...), "\n\n")
end
local function default_log(response)
io.stderr:write(response:combined_log(), "\n")
end
local function new(options)
local reply = assert(options.reply)
local onerror = options.onerror or default_onerror
local log = options.log or default_log
local myserver = server.listen(options)
local main_cq = cqueues.new()
main_cq:wrap(function()
local clients_cq = cqueues.new()
-- create a thread that waits forever so :loop doesn't return
local cond = cc.new()
clients_cq:wrap(function()
cond:wait()
end)
cqueues.running():wrap(function()
while true do
local _, err, _, thd = clients_cq:loop()
if thd == nil then -- non-thread specific error; something is terribly wrong
error(err)
end
onerror("client thread error: %s", debug.traceback(thd, err))
end
end)
assert(myserver:run(function(stream)
local req_headers, err, errno = stream:get_headers()
if req_headers == nil then
-- connection hit EOF before headers arrived
stream:shutdown()
if err ~= ce.EPIPE and errno ~= ce.ECONNRESET then
onerror("header error: %s", tostring(err))
end
return
end
local resp = new_response(req_headers, stream)
local ok, err2 = pcall(reply, resp) -- only works in 5.2+
if stream.state ~= "closed" and stream.state ~= "half closed (local)" then
if not ok then
resp:set_503()
end
local send_body = resp.body and req_headers:get ":method" ~= "HEAD"
stream:write_headers(resp.headers, not send_body)
if send_body then
stream:write_chunk(resp.body, true)
end
end
stream:shutdown()
if not ok then
onerror("stream error: %s", tostring(err2))
end
log(resp)
end, clients_cq))
end)
return main_cq
end
return {
new = new;
}
取自 https://gist.github.com/daurnimator/95e9137d617689444f396b6518fbfb7c#file-brightness-lua
local awful = require "awful"
local naughty = require "naughty"
local function get()
local fd = assert(io.popen("xbacklight -get"))
local n = assert(fd:read("*n"))
fd:close()
return n
end
local last
local function set(n)
n = math.floor(math.min(100, math.max(0, n)))
if os.execute(string.format("xbacklight -time %d -set %d", 0, n)) then
last = naughty.notify({
text = string.format("brightness is now %d%%", n);
replaces_id = last and last.id or nil;
})
end
end
root.keys(awful.util.table.join(root.keys(),
awful.key({}, "XF86MonBrightnessDown", function() set(get()-6) end),
awful.key({}, "XF86MonBrightnessUp", function() set(get()+6) end)
))
取自 https://gist.github.com/daurnimator/95e9137d617689444f396b6518fbfb7c#file-multimedia-lua
local awful = require "awful"
local function pianobar(cmd)
local pianobar_fifo = assert(io.open(os.getenv"HOME" .. "/.config/pianobar/ctl", "w"))
pianobar_fifo:setvbuf("no")
assert(pianobar_fifo:write(cmd))
pianobar_fifo:close()
end
root.keys(awful.util.table.join(root.keys(),
awful.key({}, "XF86AudioMute", function() os.execute("ponymix toggle") end),
awful.key({}, "XF86AudioLowerVolume", function() os.execute("ponymix decrease 5") end),
awful.key({}, "XF86AudioRaiseVolume", function() os.execute("ponymix increase 5") end),
--awful.key({}, "XF86AudioPrev", function() pianobar("p") end),
awful.key({}, "XF86AudioPlay", function()
if os.execute("pgrep pianobar") then
pianobar("p")
else
awful.spawn("urxvt -e pianobar")
end
end),
awful.key({}, "XF86AudioNext", function() pianobar("n") end)
))
取自 https://gist.github.com/daurnimator/95e9137d617689444f396b6518fbfb7c#file-rc-lua
-- Standard awesome library
local gears = require("gears")
local awful = require("awful")
require("awful.autofocus")
-- Widget and layout library
local wibox = require("wibox")
-- Theme handling library
local beautiful = require("beautiful")
-- Notification library
local naughty = require("naughty")
local menubar = require("menubar")
local hotkeys_popup = require("awful.hotkeys_popup").widget
local cqueues = require "cqueues"
local cq = cqueues.new()
_G.cq = cq
local cqtimer = gears.timer{timeout=0.01}
cqtimer:connect_signal("timeout", function()
local ok, err, errno, thd = cq:step(0)
if not ok then
naughty.notify({ preset = naughty.config.presets.critical,
title = "Oops, an error happened!",
text = debug.traceback(thd, err) })
end
end)
cqtimer:start()
-- {{{ Error handling
-- Check if awesome encountered an error during startup and fell back to
-- another config (This code will only ever execute for the fallback config)
if awesome.startup_errors then
naughty.notify {
preset = naughty.config.presets.critical;
title = "Oops, there were errors during startup!";
text = awesome.startup_errors;
}
end
-- Handle runtime errors after startup
do
local in_error = false
awesome.connect_signal("debug::error", function (err)
-- Make sure we don't go into an endless error loop
if in_error then return end
in_error = true
naughty.notify({ preset = naughty.config.presets.critical,
title = "Oops, an error happened!",
text = debug.traceback(err, 2) })
in_error = false
end)
end
-- }}}
function awful.util.get_themes_dir()
return awful.util.get_configuration_dir() .. "themes/"
end
-- {{{ Variable definitions
-- Themes define colours, icons, font and wallpapers.
beautiful.init(awful.util.get_themes_dir().."default/theme.lua")
-- This is used later as the default terminal and editor to run.
local terminal = "urxvt"
local editor = os.getenv("EDITOR") or "nano"
local editor_cmd = terminal .. " -e " .. editor
-- Default modkey.
-- Usually, Mod4 is the key with a logo between Control and Alt.
-- If you do not like this or do not have such a key,
-- I suggest you to remap Mod4 to another key using xmodmap or other tools.
-- However, you can use another modifier like Mod1, but it may interact with others.
local modkey = "Mod4"
local alt = "Mod1"
-- Table of layouts to cover with awful.layout.inc, order matters.
awful.layout.layouts = {
awful.layout.suit.tile.bottom,
awful.layout.suit.tile.top,
awful.layout.suit.tile,
awful.layout.suit.tile.left,
awful.layout.suit.fair,
awful.layout.suit.fair.horizontal,
awful.layout.suit.spiral,
awful.layout.suit.spiral.dwindle,
awful.layout.suit.max,
awful.layout.suit.max.fullscreen,
awful.layout.suit.magnifier,
awful.layout.suit.corner.nw,
awful.layout.suit.floating,
}
-- }}}
-- {{{ Helper functions
local function client_menu_toggle_fn()
local instance = nil
return function ()
if instance and instance.wibox.visible then
instance:hide()
instance = nil
else
instance = awful.menu.clients({ theme = { width = 250 } })
end
end
end
-- {{{ Menu
-- Create a laucher widget and a main menu
local myawesomemenu = {
{ "hotkeys", function() return false, hotkeys_popup.show_help end},
{ "manual", terminal .. " -e man awesome" },
{ "edit config", editor_cmd .. " " .. awesome.conffile },
{ "restart", awesome.restart },
{ "quit", function() awesome.quit() end}
}
local mymainmenu = awful.menu {
theme = {
width = 200;
};
items = {
{ "awesome", myawesomemenu, beautiful.awesome_icon };
{ "open terminal", terminal, "/usr/share/icons/Adwaita/256x256/apps/utilities-terminal.png" };
{ "File Browser", "thunar", "/usr/share/icons/hicolor/128x128/apps/Thunar.png" };
{ "Firefox", "firefox", "/usr/share/icons/hicolor/256x256/apps/firefox.png" };
{ "Chromium", "chromium","/usr/share/icons/hicolor/256x256/apps/chromium.png" };
{ "Gajim", "gajim", "/usr/share/icons/hicolor/scalable/apps/gajim.svg" };
{ "Liferea", "liferea", "/usr/share/icons/hicolor/scalable/apps/liferea.svg" };
{ "Sublime Text", "subl3", "/usr/share/icons/hicolor/256x256/apps/sublime-text.png" };
{ "Suspend", "systemctl suspend" };
{ "Reboot", "systemctl reboot" };
{ "Poweroff", "systemctl poweroff" };
};
}
local mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
menu = mymainmenu })
-- Menubar configuration
menubar.utils.terminal = terminal -- Set the terminal for applications that require it
-- }}}
-- Keyboard map indicator and switcher
local mykeyboardlayout = awful.widget.keyboardlayout()
-- {{{ Wibar
-- Create a textclock widget
local mytextclock = wibox.widget.textclock()
-- Create a wibox for each screen and add it
local taglist_buttons = awful.util.table.join(
awful.button({ }, 1, function(t) t:view_only() end),
awful.button({ modkey }, 1, function(t)
if client.focus then
client.focus:move_to_tag(t)
end
end),
awful.button({ }, 3, awful.tag.viewtoggle),
awful.button({ modkey }, 3, function(t)
if client.focus then
client.focus:toggle_tag(t)
end
end),
awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
)
local tasklist_buttons = awful.util.table.join(
awful.button({ }, 1, function (c)
if c == client.focus then
c.minimized = true
else
-- Without this, the following
-- :isvisible() makes no sense
c.minimized = false
if not c:isvisible() and c.first_tag then
c.first_tag:view_only()
end
-- This will also un-minimize
-- the client, if needed
client.focus = c
c:raise()
end
end),
awful.button({ }, 3, client_menu_toggle_fn()),
awful.button({ }, 4, function ()
awful.client.focus.byidx(1)
end),
awful.button({ }, 5, function ()
awful.client.focus.byidx(-1)
end)
)
local function set_wallpaper(s)
-- Wallpaper
if beautiful.wallpaper then
local wallpaper = beautiful.wallpaper
-- If wallpaper is a function, call it with the screen
if type(wallpaper) == "function" then
wallpaper = wallpaper(s)
end
gears.wallpaper.maximized(wallpaper, s, true)
end
end
-- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
screen.connect_signal("property::geometry", set_wallpaper)
awful.screen.connect_for_each_screen(function(s)
-- Wallpaper
set_wallpaper(s)
-- Each screen has its own tag table.
awful.tag({ "1", "2", "3", "4", "5", "6", "7", "8", "9" }, s, awful.layout.layouts[1])
-- Create a promptbox for each screen
s.mypromptbox = awful.widget.prompt()
-- Create an imagebox widget which will contains an icon indicating which layout we're using.
-- We need one layoutbox per screen.
s.mylayoutbox = awful.widget.layoutbox(s)
s.mylayoutbox:buttons(awful.util.table.join(
awful.button({ }, 1, function () awful.layout.inc(1) end),
awful.button({ }, 3, function () awful.layout.inc(-1) end),
awful.button({ }, 4, function () awful.layout.inc(1) end),
awful.button({ }, 5, function () awful.layout.inc(-1) end)))
-- Create a taglist widget
s.mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, taglist_buttons)
-- Create a tasklist widget
s.mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, tasklist_buttons)
-- Create the wibox
s.mywibox = awful.wibar({ position = "top", screen = s })
-- Add widgets to the wibox
s.mywibox:setup {
layout = wibox.layout.align.horizontal,
{ -- Left widgets
layout = wibox.layout.fixed.horizontal,
mylauncher,
s.mytaglist,
s.mypromptbox,
},
s.mytasklist, -- Middle widget
{ -- Right widgets
layout = wibox.layout.fixed.horizontal,
mykeyboardlayout,
wibox.widget.systray(),
mytextclock,
s.mylayoutbox,
},
}
end)
-- }}}
-- {{{ Mouse bindings
root.buttons(awful.util.table.join(
awful.button({ }, 3, function () mymainmenu:toggle() end),
awful.button({ }, 4, awful.tag.viewnext),
awful.button({ }, 5, awful.tag.viewprev)
))
-- }}}
-- {{{ Key bindings
local globalkeys = awful.util.table.join(
awful.key({ modkey, }, "s", hotkeys_popup.show_help,
{description="show help", group="awesome"}),
awful.key({ modkey, }, "Left", awful.tag.viewprev,
{description = "view previous", group = "tag"}),
awful.key({ modkey, }, "Right", awful.tag.viewnext,
{description = "view next", group = "tag"}),
awful.key({ modkey, }, "Escape", awful.tag.history.restore,
{description = "go back", group = "tag"}),
awful.key({ modkey, }, "j",
function ()
awful.client.focus.byidx( 1)
end,
{description = "focus next by index", group = "client"}
),
awful.key({ modkey, }, "k",
function ()
awful.client.focus.byidx(-1)
end,
{description = "focus previous by index", group = "client"}
),
awful.key({ modkey, }, "w", function () mymainmenu:show() end,
{description = "show main menu", group = "awesome"}),
-- Layout manipulation
awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( 1) end,
{description = "swap with next client by index", group = "client"}),
awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( -1) end,
{description = "swap with previous client by index", group = "client"}),
awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative( 1) end,
{description = "focus the next screen", group = "screen"}),
awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative(-1) end,
{description = "focus the previous screen", group = "screen"}),
awful.key({ modkey, }, "u", awful.client.urgent.jumpto,
{description = "jump to urgent client", group = "client"}),
awful.key({ modkey, }, "Tab",
function ()
awful.client.focus.history.previous()
if client.focus then
client.focus:raise()
end
end,
{description = "go back", group = "client"}),
-- Standard program
awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
{description = "open a terminal", group = "launcher"}),
awful.key({ modkey, "Control" }, "r", awesome.restart,
{description = "reload awesome", group = "awesome"}),
awful.key({ modkey, "Shift" }, "q", awesome.quit,
{description = "quit awesome", group = "awesome"}),
awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
{description = "increase master width factor", group = "layout"}),
awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
{description = "decrease master width factor", group = "layout"}),
awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
{description = "increase the number of master clients", group = "layout"}),
awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
{description = "decrease the number of master clients", group = "layout"}),
awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
{description = "increase the number of columns", group = "layout"}),
awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
{description = "decrease the number of columns", group = "layout"}),
awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
{description = "select next", group = "layout"}),
awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
{description = "select previous", group = "layout"}),
awful.key({ modkey, "Control" }, "n",
function ()
local c = awful.client.restore()
-- Focus restored client
if c then
client.focus = c
c:raise()
end
end,
{description = "restore minimized", group = "client"}),
-- Prompt
awful.key({ modkey }, "r", function () awful.screen.focused().mypromptbox:run() end,
{description = "run prompt", group = "launcher"}),
awful.key({ modkey }, "x",
function ()
awful.prompt.run {
prompt = "Run Lua code: ",
textbox = awful.screen.focused().mypromptbox.widget,
exe_callback = awful.util.eval,
history_path = awful.util.get_cache_dir() .. "/history_eval"
}
end,
{description = "lua execute prompt", group = "awesome"}),
-- Screensaver
awful.key({ modkey, alt}, "l", function() os.execute("slock") end,
{description = "lock the screen"}),
-- Screenshot
awful.key({ }, "Print", function() awful.spawn("xfce4-screenshooter") end,
{description = "take a screenshot"}),
-- Menubar
awful.key({ modkey, "Shift" }, "p", function() menubar.show() end,
{description = "show the menubar", group = "launcher"})
)
local clientkeys = awful.util.table.join(
awful.key({ modkey, }, "f",
function (c)
c.fullscreen = not c.fullscreen
c:raise()
end,
{description = "toggle fullscreen", group = "client"}),
awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
{description = "close", group = "client"}),
awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
{description = "toggle floating", group = "client"}),
awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
{description = "move to master", group = "client"}),
awful.key({ modkey, }, "o", function (c) c:move_to_screen() end,
{description = "move to screen", group = "client"}),
awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
{description = "toggle keep on top", group = "client"}),
awful.key({ modkey, }, "n",
function (c)
-- The client currently has the input focus, so it cannot be
-- minimized, since minimized clients can't have the focus.
c.minimized = true
end,
{description = "minimize", group = "client"}),
awful.key({ modkey, }, "m",
function (c)
c.maximized = not c.maximized
c:raise()
end,
{description = "maximize", group = "client"})
)
-- Bind all key numbers to tags.
-- Be careful: we use keycodes to make it works on any keyboard layout.
-- This should map on the top row of your keyboard, usually 1 to 9.
for i = 1, 9 do
globalkeys = awful.util.table.join(globalkeys,
-- View tag only.
awful.key({ modkey }, "#" .. i + 9,
function ()
local screen = awful.screen.focused()
local tag = screen.tags[i]
if tag then
tag:view_only()
end
end,
{description = "view tag #"..i, group = "tag"}),
-- Toggle tag display.
awful.key({ modkey, "Control" }, "#" .. i + 9,
function ()
local screen = awful.screen.focused()
local tag = screen.tags[i]
if tag then
awful.tag.viewtoggle(tag)
end
end,
{description = "toggle tag #" .. i, group = "tag"}),
-- Move client to tag.
awful.key({ modkey, "Shift" }, "#" .. i + 9,
function ()
if client.focus then
local tag = client.focus.screen.tags[i]
if tag then
client.focus:move_to_tag(tag)
end
end
end,
{description = "move focused client to tag #"..i, group = "tag"}),
-- Toggle tag on focused client.
awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
function ()
if client.focus then
local tag = client.focus.screen.tags[i]
if tag then
client.focus:toggle_tag(tag)
end
end
end,
{description = "toggle focused client on tag #" .. i, group = "tag"})
)
end
local clientbuttons = awful.util.table.join(
awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
awful.button({ modkey }, 1, awful.mouse.client.move),
awful.button({ modkey }, 3, awful.mouse.client.resize))
-- Set keys
root.keys(globalkeys)
-- }}}
-- {{{ Rules
-- Rules to apply to new clients (through the "manage" signal).
awful.rules.rules = {
-- All clients will match this rule.
{
rule = { },
properties = {
border_width = beautiful.border_width,
border_color = beautiful.border_normal,
focus = awful.client.focus.filter,
raise = true,
keys = clientkeys,
buttons = clientbuttons,
screen = awful.screen.preferred,
placement = awful.placement.no_overlap+awful.placement.no_offscreen
}
},
-- Floating clients.
{
rule_any = {
instance = {
"DTA", -- Firefox addon DownThemAll.
"copyq", -- Includes session name in class.
},
class = {
"Arandr",
"Gpick",
"Kruler",
"MessageWin", -- kalarm.
"Sxiv",
"Wpa_gui",
"pinentry",
"veromix",
"xtightvncviewer",
},
name = {
"Event Tester", -- xev.
},
role = {
"AlarmWindow", -- Thunderbird's calendar.
"pop-up", -- e.g. Google Chrome's (detached) Developer Tools.
}
},
properties = { floating = true }
},
-- Add titlebars to normal clients and dialogs
{
rule_any = {type = { "normal", "dialog" } },
properties = { titlebars_enabled = true }
},
-- Set Firefox to always map on the tag named "2" on screen 1.
-- { rule = { class = "Firefox" },
-- properties = { screen = 1, tag = "2" } },
}
-- }}}
-- {{{ Signals
-- Signal function to execute when a new client appears.
client.connect_signal("manage", function (c)
-- Set the windows at the slave,
-- i.e. put it at the end of others instead of setting it master.
-- if not awesome.startup then awful.client.setslave(c) end
if awesome.startup and
not c.size_hints.user_position
and not c.size_hints.program_position then
-- Prevent clients from being unreachable after screen count changes.
awful.placement.no_offscreen(c)
end
end)
-- Add a titlebar if titlebars_enabled is set to true in the rules.
client.connect_signal("request::titlebars", function(c)
-- buttons for the titlebar
local buttons = awful.util.table.join(
awful.button({ }, 1, function()
client.focus = c
c:raise()
awful.mouse.client.move(c)
end),
awful.button({ }, 3, function()
client.focus = c
c:raise()
awful.mouse.client.resize(c)
end)
)
awful.titlebar(c, {size=30;}):setup {
{ -- Left
awful.titlebar.widget.iconwidget(c),
buttons = buttons,
layout = wibox.layout.fixed.horizontal
},
{ -- Middle
{ -- Title
align = "center",
widget = awful.titlebar.widget.titlewidget(c)
},
buttons = buttons,
layout = wibox.layout.flex.horizontal
},
{ -- Right
awful.titlebar.widget.floatingbutton (c),
awful.titlebar.widget.maximizedbutton(c),
awful.titlebar.widget.stickybutton (c),
awful.titlebar.widget.ontopbutton (c),
awful.titlebar.widget.closebutton (c),
layout = wibox.layout.fixed.horizontal()
},
layout = wibox.layout.align.horizontal
}
end)
-- Enable sloppy focus, so that focus follows mouse.
client.connect_signal("mouse::enter", function(c)
if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
and awful.client.focus.filter(c) then
client.focus = c
end
end)
client.connect_signal("focus", function(c) c.border_color = beautiful.border_focus end)
client.connect_signal("unfocus", function(c) c.border_color = beautiful.border_normal end)
-- }}}
local function running(prog)
return not not os.execute("pgrep -u " .. os.getenv "USER" .. " " .. prog)
end
if not running("thunar") then
awful.spawn("thunar --daemon")
end
if not running("pasystray") then
awful.spawn("pasystray")
end
if not running("nm-applet") then
awful.spawn("nm-applet --sm-disable")
end
if not running("system-config-printer-applet") then
awful.spawn("system-config-printer-applet")
end
dofile(awful.util.getdir("config") .. "/multimedia.lua")
dofile(awful.util.getdir("config") .. "/brightness.lua")
取自 https://gist.github.com/daurnimator/a19e633032c2dc5086ea63323d6a24b6#file-cleverbot-lua
-- API figured out from https://github.com/pierredavidbelanger/chatter-bot-api/blob/master/python/chatterbotapi.py
local request = require "http.request"
local http_util = require "http.util"
local digest = require "openssl.digest"
local function hex(str)
return (str:gsub(".", function(c)
return string.format("%0x", string.byte(c))
end))
end
local function md5hex(str)
return hex(digest.new("md5"):final(str))
end
local function uri_encode_with_plus(str)
return http_util.encodeURIComponent(str):gsub("%%20", "+")
end
local methods = {}
local mt = {
__name = "cleverbot";
__index = methods;
}
local function new()
return setmetatable({
base_uri = "http://www.cleverbot.com/";
service_uri = "http://www.cleverbot.com/webservicemin?uc=165&";
hash_pos = 35;
cookie = {};
current_state = "";
}, mt)
end
function methods:get_cookie()
local req = request.new_from_uri(self.base_uri)
local headers, stream = assert(req:go())
stream:shutdown()
assert(headers:get(":status") == "200")
local set_cookie = headers:get("set-cookie")
local key, value = set_cookie:match("([^%s;=]+)=?([^%s;]*)")
self.cookie[key] = value
end
function methods:think(thought)
if next(self.cookie) == nil then
self:get_cookie()
end
local req = request.new_from_uri(self.service_uri)
req.headers:upsert(":method", "POST")
do
local cookie = {}
for k, v in pairs(self.cookie) do
cookie[#cookie+1] = k .. "=" .. v
end
cookie = table.concat(cookie, "; ")
req.headers:upsert("cookie", cookie)
end
req.headers:upsert("content-type", "application/x-www-form-urlencoded")
local current_query = "stimulus="..uri_encode_with_plus(thought)
.. self.current_state
.. "&islearning=1&icognoid=wsf&"
local icognocheck = md5hex(current_query:sub(10, self.hash_pos))
req:set_body(current_query .. "icognocheck="..icognocheck)
local headers, stream = assert(req:go())
local response_body = stream:get_body_as_string()
if headers:get(":status") ~= "200" then
error(response_body)
end
stream:shutdown()
local set_cookie = headers:get("set-cookie")
if set_cookie then
local key, value = set_cookie:match("([^%s;=]+)=?([^%s;]*)")
self.cookie[key] = value
end
local iter = response_body:gmatch("([^\r]*)\r")
local text = iter()
self.current_state = "&sessionid=" .. uri_encode_with_plus(iter())
.. "&logurl=" .. uri_encode_with_plus(iter())
.. "&vText8=" .. uri_encode_with_plus(iter())
.. "&vText7=" .. uri_encode_with_plus(iter())
.. "&vText6=" .. uri_encode_with_plus(iter())
.. "&vText5=" .. uri_encode_with_plus(iter())
.. "&vText4=" .. uri_encode_with_plus(iter())
.. "&vText3=" .. uri_encode_with_plus(iter())
.. "&vText2=" .. uri_encode_with_plus(iter())
.. "&prevref=" .. uri_encode_with_plus(iter())
return text
end
return {
new = new;
}
取自 https://gist.github.com/daurnimator/23e36762dc62198da8804350df654ecf#file-init-lua
local cqueues = require "cqueues"
local unpack = table.unpack or unpack
local pack = table.pack or function(...) return {n=select("#", ...), ...} end
local POLLIN, POLLOUT, POLLPRI = 1, 2, 4
-- a tostring() that can't throw
local function safe_tostring(t)
local ok, s = pcall(tostring, t)
if not ok then
return "(null)"
else
return s
end
end
local function each_arg(...)
return function(args, last)
if last == args.n then return nil end
local i = last + 1
return i, args[i]
end, pack(...), 0
end
local methods = {}
local mt = {
__name = "lua cqueue";
__index = methods;
}
local function thread_add_head(thread, head)
thread.prev = head
thread.next = head.next
if head.next then
head.next.prev = thread
end
head.next = thread
end
local function thread_del(thread)
local prev, next = thread.prev, thread.next
prev.next = next
if next then
next.prev = prev
end
-- thread.prev, thread.next = nil, nil -- not needed but catches programming errors
end
local function thread_move(thread, head)
-- Remove from old list
thread_del(thread)
-- Add to new list
thread_add_head(thread, head)
end
local _POLL = {} -- something unique
-- Table of scheduler objects
local cstack = setmetatable({}, {__mode="kv"})
-- The currently running scheduler
local cstack_running = nil
local function cstack_push(new)
new.running = cstack_running
cstack_running = new
end
local function cstack_pop()
cstack_running = cstack_running.running
end
local timer_methods = {}
local timer_mt = {
__name = "timer collection";
__index = timer_methods;
}
local function new_timers()
return setmetatable({}, timer_mt)
end
function timer_methods:add(ob, deadline)
self[ob] = deadline
end
function timer_methods:remove(ob)
self[ob] = nil
end
function timer_methods:min()
local min = math.huge
for _, deadline in pairs(self) do
if deadline < min then
min = deadline
end
end
if min == math.huge then
return nil
else
return min
end
end
timer_methods.each = pairs
local condition_methods = {}
local condition_mt = {
__name = "condition";
__index = condition_methods;
}
local function new_condition(lifo)
return setmetatable({
lifo = lifo;
head = 1;
tail = 0;
}, condition_mt)
end
do
local function check(self, why, ...)
if self == why then
return true, ...
else
return false, why, ...
end
end
function condition_methods:wait(...)
return check(self, coroutine.yield(_POLL, self, ...))
end
end
local function condition_add(self, fn)
if self.lifo then
local i = self.head - 1
self[i] = fn
self.head = i
else
local i = self.tail + 1
self[i] = fn
self.tail = i
end
end
function condition_methods:signal(max)
if max then
max = math.min(self.tail, self.head + max)
else
max = self.tail
end
for i=self.head, max do
local event = self[i]
event.pending = true
thread_move(event.thread, event.thread.scheduler.pending)
-- TODO: wakeup
end
end
function condition_methods:pollfd()
return self
end
function condition_methods:events()
return nil
end
function condition_methods:timeout()
return nil
end
local function new()
local self = setmetatable({
thread_count = 0; -- count of items in polling+pending
polling = {next=nil}; -- linked list of threads
pending = {next=nil}; -- linked list of threads
current = nil; -- current coroutine
running = nil; -- linked list of cqueues
timers = new_timers();
}, mt)
cstack[self] = true
return self
end
function methods.interpose(key, func)
local old = methods[key]
methods[key] = func
return old
end
-- local monotonic_clock = 0
-- local function monotime()
-- monotonic_clock = monotonic_clock + 1
-- return monotonic_clock
-- end
local monotime = cqueues.monotime
local function running()
local is_caller
if cstack_running then
is_caller = cstack_running.current == coroutine.running()
else
is_caller = false
end
return cstack_running, is_caller
end
local function cancel(...)
for cq in pairs(cstack) do
cq:cancel(...)
end
end
local function reset()
for cq in pairs(cstack) do
cq:reset()
end
end
local poller = new()
local function poll(...)
if running() then
return coroutine.yield(_POLL, ...)
else
local tuple
poller:wrap(function (...)
tuple = { poll(...) }
end, ...)
-- NOTE: must step twice, once to call poll and
-- again to wake up
assert(poller:step())
assert(poller:step())
return unpack(tuple or {})
end
end
local function sleep(timeout)
poll(timeout)
end
do
local handle_resume
local function do_resume(self, thread, ...)
cstack_push(self)
self.current = thread.co
return handle_resume(self, thread, coroutine.resume(thread.co, ...))
end
local function cleanup(self, thread, ...)
thread_del(thread)
self.thread_count = self.thread_count - 1
return ...
end
function handle_resume(self, thread, ok, first, ...)
self.current = nil
cstack_pop()
if not ok then
return cleanup(self, thread, nil, first, nil, thread.co)
elseif coroutine.status(thread.co) == "dead" then
return cleanup(self, thread, true)
else
if first == _POLL then
local now = monotime()
local thread_timeout = math.huge
for _, v in each_arg(...) do
local pollfd, events, timeout, cond = nil, 0, nil, nil
if type(v) == "number" then
timeout = v
elseif getmetatable(v) == condition_mt then
cond = v
elseif v ~= nil then
if v.pollfd ~= nil then
pollfd = v.pollfd
if type(pollfd) == "function" then
local pcall_ok, err = pcall(pollfd, v)
if not pcall_ok then
return cleanup(self, thread, nil, "error calling method pollfd: " .. safe_tostring(err))
end
pollfd = err
end
if type(pollfd) == "number" then
if pollfd == -1 then
pollfd = nil
end
elseif getmetatable(pollfd) == condition_mt then
pollfd, cond = nil, pollfd
elseif pollfd ~= nil then
return cleanup(self, thread, nil, "invalid pollfd (expected nil, number or condition)", nil, thread.co, v)
end
end
if v.events ~= nil then
events = v.events
if type(events) == "function" then
local pcall_ok, err = pcall(events, v)
if not pcall_ok then
return cleanup(self, thread, nil, "error calling method events: " .. safe_tostring(err))
end
events = err
end
if events == nil then
events = 0
elseif type(events) == "string" then
local e = 0
if events:match "r" then
e = e + POLLIN
end
if events:match "w" then
e = e + POLLOUT
end
if events:match "p" then
e = e + POLLPRI
end
events = e
elseif type(events) ~= "number" then
return cleanup(self, thread, nil, "invalid events (expected nil, number or string)", nil, thread.co, v, pollfd)
end
end
if v.timeout ~= nil then
timeout = v.timeout
if type(timeout) == "function" then
local pcall_ok, err = pcall(timeout, v)
if not pcall_ok then
return cleanup(self, thread, nil, "error calling method timeout: " .. safe_tostring(err))
end
timeout = err
end
end
end
if timeout == nil then
timeout = math.huge
elseif type(timeout) ~= "number" then
return cleanup(self, thread, nil, "invalid timeout (expected nil or number)", nil, thread.co, v, pollfd)
end
if timeout < math.huge or cond or (pollfd and events ~= 0) then
local event = {
thread = thread;
value = v;
deadline = now + timeout;
pending = false;
}
table.insert(thread.events, event)
if cond then
condition_add(cond, event)
end
if pollfd then
error("NYI pollfd")
end
if timeout then
thread_timeout = math.min(timeout, thread_timeout)
end
end
end
if thread.events[1] ~= nil or thread_timeout ~= math.huge then
if thread_timeout ~= math.huge then
-- add thread to timers
self.timers:add(thread, now+thread_timeout)
end
thread_move(thread, self.polling)
end
return true
else
return do_resume(self, thread, coroutine.yield(first, ...))
end
end
end
function methods:step(timeout)
if running() then
poll(self, timeout)
timeout = 0.0
end
assert(self.current == nil, "cannot step live cqueue")
if self.pending.next then
timeout = 0
else
timeout = timeout or math.huge
local t = self.timers:min()
if t then
timeout = math.min(timeout, t-monotime())
end
end
-- Find out what in self.polling is ready; take up to 'timeout'
if timeout > 0 then
print("WAITING FOR", timeout)
cqueues.sleep(timeout)
print("WAITED")
end
-- Move them to .pending list
local now = monotime()
for thread, deadline in self.timers:each() do
if deadline <= now then
for _, event in ipairs(thread.events) do
if event.deadline <= now then
event.pending = true
end
end
thread_move(thread, self.pending)
end
end
-- Run pending threads
local thread = self.pending.next
while thread do
local next_thread = thread.next -- Save next one incase current gets moved
local polled_ready, i = {}, 0
for _, v in ipairs(thread.events) do
if v.pending then
i = i + 1
polled_ready[i] = v.value
end
end
self.timers:remove(thread)
local ok, err, errno, thd, ob, fd = do_resume(self, thread, unpack(polled_ready, 1, i))
if not ok then
return nil, err, errno, thd, ob, fd
end
thread = next_thread
end
return true
end
end
function methods:attach(co)
assert(type(co) == "thread")
local thread = {co = co; events = {}; scheduler = self; next = nil; prev = nil}
thread_add_head(thread, self.pending)
self.thread_count = self.thread_count + 1
-- tryalert
return self
end
function methods:wrap(func, ...)
local co = coroutine.create(function(...)
coroutine.yield()
return func(...)
end)
coroutine.resume(co, ...)
local thread = {co = co; events = {}; scheduler = self; next = nil; prev = nil}
thread_add_head(thread, self.pending)
self.thread_count = self.thread_count + 1
-- tryalert
return self
end
function methods:empty()
return self.thread_count == 0
end
function methods:count()
return self.thread_count
end
function methods:cancel(...)
for _, v in each_arg(...) do
if type(v) ~= "number" then
v = v.pollfd
if type(v.pollfd) == "function" then
local ok, err = pcall(v.pollfd, v)
if not ok then
error("error calling method pollfd: "..safe_tostring(err))
end
v = err
end
if type(v) ~= "number" then
error("error loading field pollfd")
end
end
--
end
end
-- function methods:reset()
-- -- Move polling list to pending
-- local n = #self.pending
-- local e = #self.polling
-- for i=1, e do
-- self.pending[n+i] = self.polling[i]
-- self.polling[i] = nil
-- end
-- end
-- function methods:pollfd()
-- return nil
-- end
function methods:events()
return "r"
end
function methods:timeout()
if self.pending.next then
return 0
else
local t = self.timers:min()
if t then
return t - monotime()
else
return nil
end
end
end
local function todeadline(timeout)
-- special case 0 timeout to avoid monotime call in totimeout
return timeout and (timeout > 0 and monotime() + timeout or 0) or nil
end -- todeadline
local function totimeout(deadline)
if not deadline then
return nil, false
elseif deadline == 0 then
return 0, true
else
local curtime = monotime()
if curtime < deadline then
return deadline - curtime, false
else
return 0, true
end
end
end
function methods:loop(timeout)
local function checkstep(self, deadline, ok, ...)
local timeout, expired = totimeout(deadline)
if not ok then
return false, ...
elseif expired or self:empty() then
return true
else
return checkstep(self, deadline, self:step(timeout))
end
end
local deadline = todeadline(timeout)
return checkstep(self, deadline, self:step(timeout))
end
function methods:errors(timeout)
local deadline = todeadline(timeout)
return function ()
local timeout = totimeout(deadline)
return select(2, self:loop(timeout))
end
end
return {
_POLL = _POLL;
new = new;
running = running;
cancel = cancel;
reset = reset;
monotime = monotime;
poll = poll;
sleep = sleep;
}
在學習一套程式語言的過程, 了解各種程式語言各有其適用情境, 應該是個不錯的開始, 無論您從大一就開始學習 C 或 C++ 或 C# 或 Python 或 Java 或 Javascript 或 Ruby 或 swift 或 Lua 或其他計算機程式語言, 其終極目的應該只有一個, 就是逐步認清, 未來將會有更多的事物是必須仰賴計算機程式完成, 單單一種程式語言無法滿足所有工作 (當然 http://www.red-lang.org/ (源自 rebol,快速瀏覽 red 程式語言) 的開發群可能不太同意這種論調), 但是就在 2018 年第一季, 「單單一種程式語言無法滿足所有工作」這句話, 應該還算適用的.
因此, 假如您得知其他同年的計算機程式課程, 正在教導上述其他各種程式語言, 要記住, 只要能夠用來解題的程式語言, 都值得學習, 在本課程, 我們先設法學會使用 Lua 程式語言.
有興趣的話, 也可以參考一下: https://haxe.org/ (還有 https://en.wikipedia.org/wiki/Haxe)
從 http://lua.space/webdev/why-we-rewrote-lua-in-js, 我們也知道, https://fengari.io/ 利用 Javascript 重寫了 Lua 程式語言, 讓我們可賴以在瀏覽器中直接執行 Lua 程式.
意思是說 ,假如我們會配置 https://fengari.io/, 就可以直接在 web based 環境 ,直接練習 Lua 程式語法.
安裝的方法: https://github.com/fengari-lua/fengari-web
參考資料: https://youtu.be/xrLIgmd8xik
因為 David Choo 已經在一個月前完成 https://github.com/davchoo/SchoolProject, 我們只要將這個專案配置到課程倉儲中, 大家就可以直接在 http://mde.tw/vecp2018/lua/SchoolProject/ 中練習簡單的 Lua 程式語法了.
從第二週的課程內容中, 我們已經知道 Lua 基本重複迴圈用法, 如下:
-- lua test
--[[ 這是 Lua 程式的多行註解
Sc1.exe 是以副檔名 .lua 辨識程式語法, 將本程式放入編輯器後, 以 Tools->Go 執行
]]
for i = 1,10 do
print(i .. "沒有問題")
end
那麼, 各組應該可以利用 http://mde.tw/vecp2018/lua/SchoolProject/ 寫一個能夠從 1 累加到 10, 並將結果印出的程式吧!
/* Hello World program */
// Sc1.exe 是以副檔名 .c 辨識程式語法, 將本程式放入編輯器後, 以 Tools->Go 執行
#include<stdio.h>
main()
{
int i;
for (i=0; i<10; i++){
printf("Hello World\n");
}
}
# 單行註解
''' 多行註解,
Sc1.exe 是以副檔名 .py 辨識程式語法, 將本程式放入編輯器後, 以 Tools->Go 執行
'''
for 索引 in range(10):
print("可以")
-- lua test
--[[ 這是 Lua 程式的多行註解
Sc1.exe 是以副檔名 .lua 辨識程式語法, 將本程式放入編輯器後, 以 Tools->Go 執行
]]
for i = 1,10 do
print(i, "沒有問題")
end
接下來將利用初步了解 Lua 程式語言, 以及 Lua 變數 scope 用法 進入 Lua 的程式世界
本課程將利用 Solvespace 建立汽車相關零組件, 導入 V-rep 後, 以 Lua 及 Python 程式進行控制.
2017 Spring 計算機程式: http://mde.tw/2017springvcp/blog/2017spring-ve-cp.html
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.