2013年7月24日 星期三

[sozi] Inkscape 的簡報外掛:sozi - Windows 7 安裝及注意事項

不小心誤入進入貴哥的 sozi 介紹文[3]

一試很開心。發現中文介紹大多是 linux,於是我分享一下我在 windows 7 下的使用心得。

 

安裝

在官方介紹裡[1],目前只支援 32-bit,所以!

  1. 請安裝 inkscape 32-bit[6] 版本。在 windows 下,會被安裝在 C:\Program Files (x86)\Inkscape\
  2. 為了要更換 inkscape 的 python 版本到 python 2.7,請先安裝 python 2.7 for windows 32-bit[7] 到系統中。預設是安裝到 C:\Python27
  3. 安裝 LXML for Python 2.7 and Windows 32-bit[8] http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml
  4. 安裝 PyGTK 2.24 的 all-in-one 安裝檔 for Python 2.7 and Windows 32-bit[10]
  5. 把 C:\Python27 複製到 C:\Program Files (x86)\Inkscape
  6. 把 C:\Program Files (x86)\Inkscape\Python 改名為 C:\Program Files (x86)\Inkscape\Python26
  7. 把 C:\Program Files (x86)\Inkscape\Python27 改名為 C:\Program Files (x86)\Inkscape\Python
  8. 把 sozi-release-[...].zip[11] 解開,放到 C:\Program Files (x86)\Inkscape\share\extensions

搞定。啟動或重開 inkscape 就可以在 「擴充功能」 裡看到 sozi 了。

 

意外

如果發現有字型問題怎辦?

請到 C:\Program Files (x86)\Inkscape\Python\Lib\site-packages\gtk-2.0\runtime\etc\gtk-2.0

找到 gtkrc,加入以下文字:

style "user-font"
{
    font_name="mingliu 11"
}
widget_class "*" style "user-font"

font_name 可改成你的系統中,找得到的字型的「英文名字」。
(所以寫 細明體 會沒有用)
後面的 11 是預設點數。請隨意。

 

重要

sozi 的編輯畫面不能讓我改 title 怎辦?

其實,不只是 title 不能改,有許多文字輸入框,數字輸入框,遊標根本進不去。
image

只能按左下角的 New,然後按確定。難道只能這樣使用 sozi,沒有辦法了嗎?

不是!這時只要換個視窗,再換回 sozi 視窗,就會變得可以輸入了。
舉例:在上圖中,滑鼠先點到 Timeout (seconds) 的 1.00 的框框裡。此時看不到遊標。然後,按下工作列的顯示桌面,再按工作列的 Sozi 視窗。你會發現遊標出來了。

image

然後整個畫面就都可以正常輸入。

 

注意

sozi 的官網有提到,因為 Inkscape 的 plugin 系統的設計關係,以下的畫面千萬不要去按取消。

image

我是沒按過取消會怎樣。人家都說不要按了。

 

參考:

1. http://sozi.baierouge.fr/wiki/en:install#installation_on_windows

2. http://people.ofset.org/~ckhung/b/svg/sozi.php

3. http://newtoypia.blogspot.tw/2012/11/sozi.html

4. 貴哥的簡報 http://people.ofset.org/~ckhung/mm/

5. 貴哥的進階技巧 http://user.frdm.info/ckhung/b/svg/sozi.php

6. Inkscape download http://downloads.sourceforge.net/inkscape/inkscape-0.48.4-1-win32.exe

7. python 2.7 for windows 32-bit http://python.org/ftp/python/2.7.5/python-2.7.5.msi

8. lxml-3.2.1.win32-py2.7.exe http://www.lfd.uci.edu/~gohlke/pythonlibs/bm67sm2y/lxml-3.2.1.win32-py2.7.exe

9. lxml http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml

10. pygtk-all-in-one-2.24.0.win32-py2.7.msi http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.24/pygtk-all-in-one-2.24.1.win32-py2.7.msi

11. sozi-release-13.05-21064303.zip http://sozi.baierouge.fr/wiki/_media/dl:sozi-release-13.05-21064303.zip

2013年7月18日 星期四

[git][dulwich]在 windows 才會有的權限認定問題

前一陣子試著使用 dulwich 來操作 .git 裡面的資料,例如上傳到 changeset 到 remote、下載 changeset 到 local。看起來都很正常。但是,把檔案從 .git 裡面拿出來放,就會判定某些檔案被改變,我去檢查內容,自己使用 sha,md5 對兩個檔案檢查,結果顯示兩個檔案內容完全一樣。我想,dulwich 這麼多人用,難道我又遇到「沒人會遇到」的問題嗎?

另外我使用 tortoisegit 來檢查其內容,一樣也是說相同,但是用 dulwich 拉回來的 .git,跟 tortoisegit 拉回來的 .git 對於相同檔案,卻是一個說相同,一個說有改變。這可搞死我了,難道要放棄使用 dulwich 嗎?

後來翻到一個舊的 tortoisegit 的 issue:https://code.google.com/p/tortoisegit/issues/detail?id=812

Allow to change git file permission mask / attributes (especially executable bit)

才知道,dulwich 可能也是中同一個招數。git 是有檢查 Read, Write, Execute vs User, Group, Other 的。於是就可以解釋,為何只要是 script 或是 linux 的執行檔才會出現內容相同,但被判定有改變。在 windows 的檔案權限是 666,跟原來的不一樣了,也沒辦法改成 755。不曉得 tortoisegit 怎麼解決這問題的…。我這裡暫時停止研究了。

[git]學習 TortoiseGit - revert

原本有在用 hg,還以為會很順利地就會使用 git。

結果,等到真正開始管專案,第一個遇到的就是,revert 呢?

因為原本很習慣地,只要有臨時改過某個檔,要回到原狀,就很簡單地「指」著那個檔按右鍵,選revert

image

在下圖按下 revert 就解決了。

image 

但是,在 tortoisegit 我眼花啦~~~~~!!

我找了兩天啊!可說是上天下海用 google 去找,怎麼沒有人會有這種問題呢?

大概沒有人跟我一樣眼睛被蚵仔擋到,就在這兒啊,怎麼會有人要問這種問題呢?

image

其實還真有…

http://stackoverflow.com/questions/8011538/git-pulling-only-certain-files

2013年7月16日 星期二

[javascript]javascript如何列舉dictionary所有的key?

繼上次對於 dictionary 的操作,還少了一件事。那就是列舉所有的 key 值。

這件事沒法子由 instance 的 method 來找,於是使用 Object.keys() 這個功能來處理。

var a = {'key1':'a','key2':'b','key3':'c'};

var b = Object.keys(a)

console.log(b)

//會得到 ["key1", "key2", "key3"]

參考:

http://stackoverflow.com/questions/10654992/how-to-get-collection-of-keys-in-javascript-dictionary

2013年7月10日 星期三

[webapi]微軟 ASP.NET Web API Self Host 的應用(2)

(本篇程式是用 vb.net 寫成)

前一篇留下一個問題,若是要提供服務 .html, .js, .css, .jpg, .png, .gif ... 等等,我想到的辦法是自行撰寫程式來處理。在參考了[1] 的 route 用法,我在 config.Routes.MapHttpRoute 多加 4 個 route。img、css、js 分別提供 圖檔、css、js 三大類檔案的服務。而 default 則是提供第一個頁面的服務。

config.Routes.MapHttpRoute("img", "img/{name}", New With {.controller = "Img", .action = "g"})
config.Routes.MapHttpRoute("css", "css/{name}", New With {.controller = "Css", .action = "g"})
config.Routes.MapHttpRoute("js", "js/{name}", New With {.controller = "Js", .action = "g"})
config.Routes.MapHttpRoute("API", "{controller}/{action}/{id}", New With {.id = RouteParameter.Optional}) ' vs2010 just can not IntelliSense....
config.Routes.MapHttpRoute("default", "", New With {.controller = "Home", .action = "g"})

接下來則是加入 ImgController, CssController, JsController, HomeController 這四個 class

Public Class ImgController
    Inherits ApiController
    Dim accept_type As Dictionary(Of String, String) = New Dictionary(Of String, String) From {{".jpg", "jpg"}, {".png", "png"}, {".gif", "gif"}}
    <HttpGet()> Public Function g(ByVal name As String) As HttpResponseMessage
        Dim content As New StreamContent(New System.IO.FileStream(Request.RequestUri.LocalPath.Substring(1), IO.FileMode.Open))
        Dim ext As String = System.IO.Path.GetExtension(Request.RequestUri.LocalPath).ToLower()
        If accept_type.ContainsKey(ext) Then
            content.Headers.ContentType = New MediaTypeHeaderValue("image/" & ext)
        End If
        Dim response = New HttpResponseMessage() With {.Content = content}
        'response.Headers.CacheControl = New CacheControlHeaderValue() With {.MaxAge = New TimeSpan(1, 0, 0)}
        Return response
    End Function
End Class

Public Class CssController
    Inherits ApiController
    <HttpGet()> Public Function g(ByVal name As String) As HttpResponseMessage
        Dim content As New StreamContent(New System.IO.FileStream(Request.RequestUri.LocalPath.Substring(1), IO.FileMode.Open))
        content.Headers.ContentType = New MediaTypeHeaderValue("text/css")
        Dim response = New HttpResponseMessage() With {.Content = content}
        'response.Headers.CacheControl = New CacheControlHeaderValue() With {.MaxAge = New TimeSpan(1, 0, 0)}
        Return response
    End Function
End Class

Public Class JsController
    Inherits ApiController
    <HttpGet()> Public Function g(ByVal name As String) As HttpResponseMessage
        Dim content As New StreamContent(New System.IO.FileStream(Request.RequestUri.LocalPath.Substring(1), IO.FileMode.Open))
        content.Headers.ContentType = New MediaTypeHeaderValue("text/javascript")
        Dim response = New HttpResponseMessage() With {.Content = content}
        'response.Headers.CacheControl = New CacheControlHeaderValue() With {.MaxAge = New TimeSpan(1, 0, 0)}
        Return response
    End Function
End Class

Public Class HomeController
    Inherits ApiController
    <HttpGet()> Public Function g() As HttpResponseMessage

        Dim content As New StreamContent(New System.IO.FileStream("html/first.html", IO.FileMode.Open))
        content.Headers.ContentType = New MediaTypeHeaderValue("text/html")
        Dim response As New HttpResponseMessage() With {.Content = content}
        Return response
    End Function
End Class

 

接下來,就是把測試用的 first.html, .css, .js, .png 放到 html, css, js, img 目錄去。

以下是 first.html

<!doctype html>
<html>
<head></head>
<title>web browser</title>
<body>
<link href="css/site.css" rel="stylesheet" />
<script src="js/jquery.js" type="text/javascript" ></script>

<script type="text/javascript">
$(document).ready(function(){
//alert("jquery alert works")
});
</script>
<p>
this is html test
</p>
<p>
<input type="text" id="txtboxTest" />
</p>
<p>
<button id="btnTest">click me</button>
</p>
<script type="text/javascript"> $(document).ready(function(){
$('#btnTest').click(function(){
$('#txtboxTest').val('jquery click works!');
})
}); </script>
<p>
<img class="imgstyle" src="img/glyphicons-halflings.png" />
</p>
</body>
</html>

以下是 site.css

body { background-color: #0000ff }
.imgstyle {border:2px solid #00ffff;background-color: #ffffff}

而 jquery 及 png 圖檔還請自行準備。執行後,以 IE 來看。

image

下圖是用 chrome 來開。

image

這樣的程度,應該可以處理小小應用程式的需求,使用 SPA (Single Page Application) 的觀念來做,也就不需要多個 html 檔。若有其他需要,只需新增 route 及 controller 即可。

但是,這樣的程式,拿給我爸這種老人家,要先點一個執行檔,再開瀏覽器,然後輸入網址,他一定會嫌。在黑大的文章[2]底下有個留言說:

# GATTACA said on 04 June, 2013 10:44 PM
SignalR也有SelfHost可用啊,

ip過濾也可以只限自己127.0.0.1連線,

我現在所有單機版的操作介面都只剩下一個填滿的WebBrowser,啟動後再去讀Html檔案進來;

美工依照原本的WinForm排版Html順便美化,

程式設計師再去填SignalR JavaScript Client與Knockout ViewModel,

如果有用到COM元件,其callback事件處理後透過SignalR更新到Html上,也沒有背景執行緒更新主執行緒WinForm畫面的問題;

雖然是較極端的做法,但是可以擺脫微軟悲情的UI更迭(MFC->WinForm->WPF...),

避免程式設計師將業務邏輯綁死到UI元件上,

Html美工又很好找,

可說是利大於弊啊

對啊,這樣就會跟 app.js 一樣,看起來像是原生桌面程式有什麼不好的呢?

原來的程式執行起來長這樣,看來就想把它關掉。

image

現在,請在 Form1 加上一個 WebBrowser。然後在 httpserver.OpenAsync.Wait() 這一句的後面,加上

WebBrowser1.Navigate(http://localhost:32767)

在程式裡調好 Form1 寬度及寬度。接著在 WebBrowser1_DocumentTitleChanged 加上

Private Sub WebBrowser1_DocumentTitleChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles WebBrowser1.DocumentTitleChanged
    Me.Text = WebBrowser1.DocumentTitle
End Sub

執行程式就得到:

image

嗯,我現在感覺滿意耶。

我猜想這概念已經存在這麼久,.NET 的社群裡也許已經有類似的程式。

我這隻程式應該只是個幼稚園。

如果想要程式的話,我最近會整理放上 github 讓大家下載來用。

更新,程式在此:https://github.com/rickyteng/washapp

現在要說有什麼缺點的話,應該就是想把 webbrowser 換成 chrome 或 firefox 的引擎,html5 支援比較高。還有用 vb.net 寫 web api 的 route 及 對應的 controller,好像不如 c# 的簡易,c# 可以用 Get 當 function 名字,看起來若不特別指定,action 就是呼叫 Get(),vb.net 的我找不到對應的寫法,所以寫起來有點醜醜的。

終於用三天把兩個月來研究的「用 web 技術寫桌面程式」,的主題弄出一個段落。雖然,其實是 windows 桌面,因為使用者都在 windows 上,我技術上最後也跨不出 windows 平台。接下來就該寫出些有用的東西吧?

 

 

參考:

1. https://github.com/darrelmiller/HypermediaApiSite

2. http://blog2.darkthread.net/post-2013-06-04-self-host-web-api.aspx

[webapi]微軟 ASP.NET Web API Self Host 的應用(1)

(本篇程式是用 vb.net 寫成)

因為瀏覽器的能力大增,現在許多 GUI 的彩色糖果(新功能)都在瀏覽器上簡單易用。憑藉著 javascript 及瀏覽器就能做到原生桌面程式的事,而且不用在 c++ 裡打滾,也不用在意平台,真是一個全新的世界的來臨。

最早,mozilla 就試著使用 XUL 想要進入桌面程式,Google 也趁著 chrome 已融入大家的生活中的時機,推出 Chrome App。XUL 算是只使用前端瀏覽器引擎配合自有原生執行程式,Chrome App 則是採取與chrome 共生的執行環境來使用作業系統資源。接下來,有其他的人,想出自帶 server 端的方式來實現使用瀏覽器當 GUI 的解決方法,例如 app.js,利用 node.js 來當做程式的後端。

在黑暗執行緒看到的兩篇文章[1], [2]。才知道微軟出了個套件 ASP.NET Web API Self Host,可以當做 server 端的程式,可寫成 Console 程式,也可以寫成 WinForm。而這套件正好可以與 Chrome App、app.js 所提供的後端支援的功能相同。於是,我也來試試看是否能做出些什麼 app 來…。因為黑大已經示範了寫成 console 的程式,我就來試試 WinForm 的程式。黑大用的是 c#,我就來試試 vb.net 吧。

我還是一步步把畫面剪下來,免得以後我自己忘記,所以落落長。初學者才需要這樣。

首先,開啟一個 WinForm 的專案。

image

先存檔,然後開啟 NuGet。安裝 ASP.NET Web API Self Host。

image

以下是看到相依套件的授權。

image

實際安裝的套件如下:

image

接下來,安排程式碼。首先,在 Form1.vb 的最前面,加入 imports: (這樣可以少打幾個字。)

Imports System.Web.Http
Imports System.Web.Http.SelfHost

然後,加入兩個 form1 的變數,如下:

Dim config As HttpSelfHostConfiguration
Dim httpserver As HttpSelfHostServer

然後,加入一個 sub,是啟動 host 的部份,如下:

Sub hostinit()
    config = New HttpSelfHostConfiguration("http://localhost:32767")

    config.Routes.MapHttpRoute("API", "{controller}/{action}/{id}", New With {.id = RouteParameter.Optional}) ' vs2010 just can not IntelliSense....

    httpserver = New HttpSelfHostServer(config)

    'http://blog2.darkthread.net/post-2013-06-04-self-host-web-api.aspx
    httpserver.OpenAsync.Wait()
End Sub

選擇 Form1 的 New 事件,加入 hostinit(),使得 Form1 一出現就會接受來自 localhost:32767 的 request

Public Sub New()

     ' 此為設計工具所需的呼叫。
     InitializeComponent()

     ' 在 InitializeComponent() 呼叫之後加入任何初始設定。
     hostinit()
End Sub

在 Form1 的結束時,也要關掉 32767 的監聽。

Protected Overrides Sub Finalize()
    httpserver.CloseAsync.Wait()
    MyBase.Finalize()
End Sub

最後,也要加上 Controller 的物件,BlahController 來接受 request。(不要放在 Form1 裡面。我是放在另一個檔案 BlahController.vb)

Imports System.Web.Http
Public Class BlahController
    Inherits ApiController
    <HttpGet()> Public Function getDate() As String
        Return System.DateTime.Today.ToString("yyyy/MM/dd")
    End Function
End Class

完成了程式碼的安排後,還要記得黑大提醒的一件事,在 Windows 7、Windows 2008 這些作業系統開發時,因為權限控管較嚴,開 port 監聽需要較高權限來開放。我選擇了用 netsh 這個方法來開放權限。先開啟命令列(記得要用 administrator 權限開啟命令列)

netsh http add urlacl url=http://+:32767/ user=machine\username

記得上面的 machine 及 username 要換成你的電腦名稱及當下登入的使用者名稱。

接下來就可以試著啟動程式,開啟瀏覽器,輸入:

http://localhost:32767/Blah/getDate

如果瀏覽器的是 IE,會是這樣的結果:

image

按下開啟,內容是:

image

如果是用 chrome 的話,則會是:

image

 

出現了兩個不同的回傳內容。

 

接下來開始跟黑大不一樣了。

 

我們要開始問,如果我們要能夠服務 .html, .js, .css, .jpg, .png, .gif ... 等等一般的 web server 可以服務的檔案,該怎麼辦?

 

參考

1. 黑暗執行緒,不用IIS也能執行ASP.NET Web API,http://blog2.darkthread.net/post-2013-06-04-self-host-web-api.aspx
2. 黑暗執行緒,【範例】呼叫Self-Hosted ASP.NET Web API,http://blog2.darkthread.net/post-2013-06-05-post-to-web-api.aspx

3. http://www.dotnetcurry.com/ShowArticle.aspx?ID=896

4. http://stackoverflow.com/questions/17450846/is-it-possible-to-serve-a-web-page-from-a-self-hosted-web-api-in-a-windows-servi

5. https://github.com/darrelmiller/HypermediaApiSite

6. GetManifestResourceStream http://msdn.microsoft.com/en-us/library/System.Reflection.Assembly.aspx

7. return 405 while get .js http://stackoverflow.com/questions/17170277/jquery-get-returns-404-undefined-from-self-hosting-web-api

8. http://www.codeproject.com/Articles/455565/How-to-access-Manifest-Embedded-resources-from-an


類似 app.js 的平台,我試過的有:

google chrome packaged apps

appjs

還沒試過的平台:

node-webkit https://github.com/rogerwang/node-webkit

xul https://developer.mozilla.org/en/docs/XUL

Appcelerator Titanium http://en.wikipedia.org/wiki/Appcelerator_Titanium

Ember.js http://emberjs.com/

NACL https://developers.google.com/native-client/

 

VB.NET 的 IntelliSense 看不到 .Routes.MapHttpRoute 但 CS 可以。又多了一個換 CS 的理由。(逃)
http://forums.asp.net/t/1819836.aspx/1

2013年7月8日 星期一

[gae]增加對 svg 的支援

GAE 對於 svg 的支援,是把它當做 octet stream(application/octet-stream) 來處理。如果是這樣,當網址的結尾是 foo.svg 這種,就會得到下載的視窗,而不是想像的顯示圖案。

若是要讓它可以是顯示圖案,要讓 server 可以在 mime type 指定成 image/svg+xml。

因此,就要在 app.yaml 告訴 GAE 了。

以下是範例:[參考1]

- url: /svg/(.*\.svg)
  static_files: svg/\1
  upload: svg/(.*\.svg)
  mime_type: image/svg+xml

 

以下就是我測試用的 svg,是用 sozi 做的。使用 chrome, firefox 可以看。

http://rickystockinfo.appspot.com/svg/aot.svg

參考:

1. http://ryanarn.blogspot.tw/2011/04/using-googles-app-engine-to-serve-svg.html

2013年7月7日 星期日

[nuget]我與 NuGet 初見面

大名鼎鼎的 NuGet,是 Microsoft 開發平台(包含 .NET)的 package manager。因為 Microsoft 開發有太多方便的套件可用,以往都是開發者自行在網路上下載、安裝,難免會有安裝維護上的困擾。而現在透 NuGet,不但方便一般開發者,有統一的搜尋、下載、安裝介面,也方便套件開發者的散佈、維護。

我直到現在才裝來用,因為…我一直使用 VS2008。在沒有 VS2010 (含)以上的狀況,是有提供指令方式。

最近換了 VS2010,按照 http://docs.nuget.org/docs/start-here/installing-nuget 的說明把 NuGet 裝上。

從 工具 > 擴充管理員 把擴充管理員打開,在右上角有搜尋框,輸入 NuGet,就可以選擇 NuGet 套件管理員來安裝。

安裝完會要你重開一次 VS2010。

接下來呢?

假設你的 Window Form 程式 需要一個 json 套件叫做 Json.NET。先建立一個新的專案,在方案總管那裡點右鍵,就會看到「管理 NuGet 套件」。執行前要先確定專案檔已經儲存。

image

等待一些時間,會出現主畫面,搜尋、選擇 Json.NET

image

按安裝就解決了 Json.NET 的下載及安裝了。酷!

以上,是使用 VS2010 Premium 版。

我另外使用 VS2010 C# Express Edition,但是在 Extension Manager 卻找不到 NuGet Package Manager。會不會是有什麼設定要改的呢?

如果有人也是 Express Edition,可以使用 NuGet 的請教教我,感恩。

image