一般安裝 Dropbox 之後, Finder 中會自動整合其功能
像是在資料夾上按右健可以直接在 Dropbox 網頁中打開、取得 Public Path 等等功能
但是我使用 Path Finder 他並沒有幫我把外掛安裝好
要自己從 Dropbox.app/Contents/Resources/DropboxPlugin.plugin
複製到 ~/Library/Contextual Menu Items
複製後重新啟動 Path Finder 就可以看到整合的功能了
2011年2月11日星期五
Path Finder 整合 Dropbox 功能
2011年1月13日星期四
在 Rails3 中使用 jQuery
Rails3 預設也是使用 Prototype.js
在產生 rails 專案時,輸入 rails your_project -J 則不會產生 Prototype.js 的檔案
用官方提供的 jQuery js driver : http://github.com/rails/jquery-ujs/blob/master/src/rails.js
取代 /public/javascripts/rails.js 這個檔案
在需要使用的 layout header 中使用
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js" %>
<%= javascript_include_tag 'rails' %>
或是自己導入路徑中的 jQuery 檔案
2011年1月5日星期三
使用 rvm 管理 ruby 版本
$ bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head ) # 安裝 rvm rvm list # 查看目前安裝的 ruby 版本 rvm info # 查看目前使用的環境訊息 rvm list known # 列出可以安裝的版本 rvm install ruby-1.9.2-head # 安裝指定版本 rvm use ruby-1.9.2-head # 目前環境使用指定版本 rvm use ruby-1.9.2-head --default # 預設使用指定版本 rvm system # 使用回系統預設版本 rvm reset # 預設使用系統版本安裝後要在 .bashrc 或是啟動 shell 會執行的檔案中加入
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"確保每次進入 shell 都會讀取 rvm 設定的狀態
2010年12月25日星期六
Java 時間轉換的時區問題
其實是在寫 Android 軟體時發現的問題
因為把時間在 SQLite 中以字串儲存,取出來的時候要轉換成 Date 物件。我是使用 SimpleDateFormat 的物件來做轉換,之前因為只把轉換出來的時間物件拿來計算時間差距,所以沒發現轉換出來的時間和字串表示的時間不同!今天用的時候著實嚇一跳…
原來 SimpleDateFormat 在轉換的過程會考慮到系統目前的時區,所以
"2010-12-25T08:00:00+08:00" 會轉換成 "2010-12-25 00:00:00 CST"
我的時區是 Asia/Taipei GMT+8,所以就這樣活生生被吃了八個小時
所以之後再用 Date.getTime() 等 function 時取得的時間就和字串表示的時間不同了!
我目前最簡單的解決方式就是指定 SimpleDateFormat 的時區,來得到和字串表面相同的 Date 物件
SimpleDateFormat dateFormat;
dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 指定格式
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); // 指定時區
dateFormat.parse("2010-12-25");
這樣就沒問題了,否則上述範例中,被吃了八小時日期會來到 2010-12-24 !
2010年12月19日星期日
設定 Apache 簡易密碼認證
久久設定一次就會忘記 (汗…)
設定 Apache 簡易密碼認證,這樣要先輸入帳號密碼才能看到網頁內容
基本設定不贅述,在設定文件中找到想要設定的目錄
<Directory /var/www/html>
AllowOverride FileInfo AuthConfig Limit
Options MultiViews SymLinksIfOwnerMatch
<Limit GET POST OPTIONS PROPFIND>
Order allow, deny
Allow from all
</Limit>
<Limit PUT DELETE PATCH PROPPATCH MKCOL COPY MOVE LOCK UNLOCK>
Order deny, allow
Deny from all
</Limit>
</Directory>
注意一定要 AllowOverride AuthConfig如果要設定某些 request 的限制,也要 AllowOverride Limit
再來到要限制存取的目錄中新增 .htaccess 檔
AuthName "Section Name" AuthType Basic AuthUserFile /var/www/html/.htpasswd Require valid-userAuthUserFile 路徑檔名可以隨便取,也可以放在其它地方
最後是新增 AuthUserFile,路徑就是上面設定的
使用指令:htpasswd filename username
2010年12月18日星期六
解決 Android 模擬器無法上網 - 更改 DNS 設定
也不知道為什麼,好像是升級了新的 SDK 之後模擬器就突然無法上網
其實之前發生過,但是今天有人突然問我我又忘記怎麼設定了,趕緊筆記一下!
我自己遇到的問題是因為模擬器中的 DNS 設定錯誤,所以當然對應不到 IP
所以把 DNS 設定成正確的就可以了!
使用 SDK 中附的工具: adb
./adb shell
$ getprop # 查看屬性設定
[net.dns1]: [192.168.2.1] # 某一筆是 net.dns1 就是目前的設定
$ setprop net.dns1 192.168.2.1 # 設定成可以用的 DNS
# 不知道就用 Google 的吧 "8.8.8.8"
$ exit
設定完成應該就可以直接上網了
2010年12月9日星期四
Google App Engine 簡易筆記
最近在開發手機軟體,背後需要有資料儲存的支援,這時候就覺得 Google App Engine 算蠻不錯的,因為免費且給的資源夠多!如果用 Python 或是 Java 開發沒有問題,也可以接受它特有的 Datastore ,那 GAE 真的是不錯的選擇,來記一些之後還可能會用到的筆記。
Datastore:
其實 GAE 也是遵從 MVC 的架構來開發,加上有豐富的說明文件開發上並不困難,比較難以適應的就是 Datastore 的部份,因為它不是關聯式資料庫,所以一開始資料庫的規劃上就要有不同的規劃方式,像是沒有關聯鍵這種東西,查詢語法無法 join 、查詢結果無法 count 、無法大量刪除資料等等…,這邊只筆記使用方式,其他關於 GAE Datastore 的介紹很多了,就不贅述
from google.appengine.ext import db
class Pet(db.Model):
name = db.StringProperty(required=True)
type = db.StringProperty(required=True, choices=set(["cat", "dog", "bird"]))
birthdate = db.DateProperty()
weight_in_pounds = db.IntegerProperty()
spayed_or_neutered = db.BooleanProperty()
owner = db.UserProperty(required=True)
和一般資料庫的使用不同,不是先建立 Table ,而是先將 Model 建立出來,當第一筆資料輸入資料庫後 Table 就會自動產生了。上面的是官方文件的範例,比較要注意的是資料型態的部份,可以先查一下有哪些可以用的資料型態,有一些比較特別的資料型態其實很好用,像是 GeoPtProperty 表示地理位置等等…Model 定義好之後,當需要建立資料時只要產生相對的實體就可以指定內容,如果定義時有加上 required=True 的參數則為必填的欄位,要在建立實體時就輸入。建立完成後使用 put() function 就會輸入到資料庫中了。
from google.appengine.api import users
pet = Pet(name="Fluffy",
type="cat",
owner=users.get_current_user())
pet.weight_in_pounds = 24
pet.put()
比較重要的是可以利用 ReferenceProperty 建立 One-to-One 的關係,下面範例假設一個人可以有很多隻寵物:class Owner(db.Model):
name = db.StringProperty(required=True)
class Pet(db.Model):
name = db.StringProperty(required=True)
owner = db.ReferenceProperty(Owner, collection_name='pets')
jeffean = Owner(name='Jeff Tsai')
jeffean.put()
pet1 = Pet(name="Jimmy", owner=jeffean)
pet1.put()
pet2 = Pet(name="Anfa", owner=jeffean)
pet2.put()
# 列出某個人所有的寵物
for pet in jeffean.pets:
print 'name: %s' % pet.name
另外可以利用 ListProperty 來做 Many-to-Many 的關係,下面是用文章和標籤的關係當範例:class Post(db.Model):
title = db.StringProperty(required=True)
tags = db.ListProperty(db.Key)
class Tag(db.Model):
name = db.StringProperty(required=True)
@property
def posts(self):
return Post.gql('WHERE tags = :1', self.key())
# 建立 entity
tag1 = Tag(name='food')
tag1.put()
tag2 = Tag(name='travel')
tag2.put()
post1 = Post(title='Blah')
post1.tags.append(tag1.key())
post1.tags.append(tag2.key())
post1.put()
# 從 Post 取得它所有標籤:
tags = db.get(post1.tags)
for tag in tags:
print 'Tag: %s' % tag.name
# 查看某個標籤中有什麼文章:
for post in tag1.posts:
print 'Title: %s' % post.title
雖然上面有用到查詢,但是還是寫一下查詢的說明。下面的範例展示如何對資料庫做查詢以及放入篩選條件,比較特別的是刪除資料也得像這樣做,無法像以往下 SQL 的 DETET 語法可以做大量刪除。class Song(db.Model):
title = db.StringProperty()
composer = db.StringProperty()
date = db.DateTimeProperty()
query = db.Query(Song)
query = Song.all() # 與上一行意思其實相同
query = GqlQuery("SELECT * FROM Song WHERE composer = 'Lennon, John'") # 也可以這樣
query = Song.gql("WHERE composer = 'Lennon, John'") # 這樣也可以
query.filter('title =', 'Imagine')
query.order('-date')
query.ancestor(key)
results = query.fetch(limit=5)
for song in results:
print song.title
for song in query: # 和上一個迴圈相同意思但是沒限制數量
print song.title
song.delete()
另外每筆資料都有自己獨特的 key ,但是無法排序,雖然也會自動有 id 的欄位但是數字也不是壘加的,可以用來做選擇單一筆資料時的查詢依據,但要取得最新的 N 筆資料來排序,我自己的作法是用一個 modify = db.DateTimeProperty(auto_now = True) 的欄位,這樣輸入資料會自動記下現在的時間,方便我要取得最新資料時的篩選條件,或許有更好的方法但是我目前是這樣做啦。最後來筆記一下取得 key 和 id 的方式:
query = Song.all() for song in query: print song.key() print song.key().id()
Template 系統:
因為一個站內的網頁常常有很多重複的部份,像是 footer 或是選單,沒有 tempalte 每一頁都重複寫的話,一來麻煩二來要改的時候更麻煩!而 App Engine 支援的 template 系統有很多種,而 gae 預設的 webapp 架構中本來就包含了 django 的 template 系統了,官方的說明文件也是以此為範例:
import os
from google.appengine.ext.webapp import template
class MainPage(webapp.RequestHandler):
def get(self):
greetings_query = Greeting.all().order('-date')
greetings = greetings_query.fetch(10)
if users.get_current_user():
url = users.create_logout_url(self.request.uri)
url_linktext = 'Logout'
else:
url = users.create_login_url(self.request.uri)
url_linktext = 'Login'
template_values = {
'greetings': greetings,
'url': url,
'url_linktext': url_linktext,
}
path = os.path.join(os.path.dirname(__file__), 'index.html')
self.response.out.write(template.render(path, template_values))
後端程式碼的重點就是把資料裝入 dictionary 的資料結構裡面,並且用 template.render() 這個 function 把整個資料結構送給 template 的檔案就可以了,而不是直接用 response.out.write() 寫出。按照以上範例,則要另外產生一個 index.html 的 template 檔案。基本上 template 也是一個 html 檔,但是在裡面可以用 {{ var }} 的方式將後方傳送來的變數給印出,也可以配合 django template 的 loop 和 filter 使用。和 PHP 不一樣的是,這裡插入的不是 Python 的程式碼,而是 django template 規範出來的語法,可以參考 django 的官方文件。另外 template 中可以自行定義出 block ,並且在其他的樣板檔案中繼承以及修改:
base.html:
<html>
<body>
{% for greeting in greetings %}
{% if greeting.author %}
<b>{{ greeting.author.nickname }}</b> wrote:
{% else %}
An anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content|escape }}</blockquote>
{% endfor %}
<form action="/sign" method="post">
<div><textarea name="content" rows="3" cols="60"></textarea></div>
<div><input type="submit" value="Sign Guestbook"></div>
</form>
<a href="{{ url }}">{{ url_linktext }}</a>
</body>
</html>
繼承以上 template 並且修改部分區塊:{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

