2011-12-21 19:03

[轉載] Aptana Scripting 一個背景處理的範例

轉載自:Monkeying with Eclipse | Info Support

/*
 * Menu: Info Support > Find commented code
 * Kudos: Peter Hendriks
 * License: EPL 1.0
 * DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript
 */
function main() {
    loadBundle("org.eclipse.core.jobs");

    var ProgressMonitorDialog = Packages.org.eclipse.jface.dialogs.ProgressMonitorDialog;
    var IRunnableWithProgress = Packages.org.eclipse.jface.operation.IRunnableWithProgress;

    var runnableWithProgress = new IRunnableWithProgress({ run: runCommentSearch });
    new ProgressMonitorDialog(window.getShell()).run(true, true, runnableWithProgress);

    window.getActivePage().showView("org.eclipse.ui.views.TaskList");
}

function runCommentSearch(monitor) {
    var files = resources.filesMatching(".*\\.java");
    monitor.beginTask("Searching for commented code...", files.length);
    try {
        var match;
        for each( file in files ) {
            monitor.subTask(file.getEclipseObject().getName());
            file.removeMyTasks();
            var previousLineCodeComment = false;
            for each( line in file.lines ) {
                if (monitor.isCanceled()) {
                    return;
                }
                if (match = line.string.match(/^.*\/\/.*[;{}]\s*$/)) {
                    if (!previousLineCodeComment) {
                        line.addMyTask("Commented code: " + match[0]);
                    }
                    previousLineCodeComment = true;
                } else {
                    previousLineCodeComment = false;
                }
            }
            monitor.worked(1);
        }
    } finally {
        monitor.done();
    }
}
2011-12-21 18:58

Aptana Scripting - Find TODOs 範例中的參數

/*
 * Menu: Editors > Find TODOs
 * Kudos: Ingo Muschenetz
 * License: EPL 1.0
 * DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript
 */

function main() {
    var files = resources.filesMatching(".*\\.js");
    var match;

    for each( file in files ) {
        file.removeMyTasks( );
        for each( line in file.lines ) {
            if (match = line.string.match(/\/\/TODO: (.*)/)) {
                line.addMyTask( match[1] );
            }
        }
    }
    window.getActivePage().showView("org.eclipse.ui.views.TaskList");
}

只列出當前文件的方法
var files = resources.filesMatching('.*/'+editors.activeEditor.textEditor.titleToolTip);

resources 部分的方法
filesMatching(".*\\.js")
filesMatchingForProject("Project Name",".*\\.js")
filesMatchingIgnoreCase(".*\\.js")
filesMatchingForProjectIgnoreCase("Project Name",".*\\.js")

file 部分的方法
size
lines
removeMyTasks()

line 部分的方法
lineNumber
string
addMyTask('Task String')
2011-12-21 18:46

Aptana Scripting 學習筆記

  • 在任何一個專案的頂層目錄,建立一個名稱為 scripts 或 monkey 的目錄
  • 在此目錄下建立副檔名為 *.js 或 *.em 的 JavaScript 的文件

一個空白文件的內容如下:
/*
 * Menu: Samples > Execute Snippet
 * Key: M1+M2+M3+F
 * Kudos: Jax Hu
 * License: EPL 1.0
 * DOM: http://download.eclipse.org/technology/dash/update/org.eclipse.eclipsemonkey.lang.javascript
 */

function main(){
}


快捷鍵的代號對應:
M1Control/Command
M2Shift
M3Alt/Option


一個可以用來顯示物件成員的函數:
/**顯示物件的成員
 * @param {Object} val 物件
 */
function var_dump(val){
    var name, value, temp=[];

    for (name in val) {
        try {
            value = (val[name]+'').
                replace("function",'<b style="color:#00f;">$&</b>');
        }catch (e) {
            value = (e+'').fontcolor('red');
        }
        temp.push('<b style="color:#707;">'+name+'</b> = '+value);
    }

    webView = views.getView("var_dump");
    webView.showView(true);
    webView.setTitle('var_dump');
    webView.setHTML(temp.join("<hr/>").fixed());
}


常用方法以及數值:
/*當前文件的位置
 * => D:/WorkSpace/my_project/test.js */
location

/*當前文件的名稱
 * => test.js */
editors.activeEditor.title

/*當前的文件內容*/
editors.activeEditor.source

/*當前文件的 URI 位址*/
editors.activeEditor.uri

/*儲存當前文件*/
editors.activeEditor.save();

/*對當前文件-開啟另存新檔的對話匡*/
editors.activeEditor.textEditor.doSaveAs()

/*對當前文件的目錄路徑
 * => D:/WorkSpace/my_project */
editors.activeEditor.textEditor.editorInput.file.parent.location

/*目前開啟的所有文件*/
editors.all[];

/*儲存全部編輯器,傳入 true 會開啟存檔提示*/
window.workbench.saveAllEditors(false);

/*重新開啟 Eclipse*/
window.workbench.restart();

/*關閉 Eclipse*/
window.workbench.close();

/* 開新的編輯器,可以透過這個開啟空白文件,或是已經存在的檔案,
 * 之後 editors.activeEditor 會轉到這個文件上 */
fileUtils.open('textile_to_redmine.txt');

/*取得當前的專案名稱*/
editors.activeEditor.textEditor.editorInput.file.project.name;

/*取得所有的專案*/
Packages.org.eclipse.core.resources.ResourcesPlugin.workspace.root.projects;
editors.activeEditor.textEditor.editorInput.file.workspace.root.projects


建立一個新的視圖,或開啟已存在的視圖:
webView = views.getView("my_view_name");

/*顯示視圖*/
webView.showView(true);

/*設定標題*/
webView.setTitle("My View Title");

/*設定內容的HTML*/
webView.setHTML('<h1>OK</h1>');

/*或指定內容的網址*/
webView.url = "http://www.google.com";
webView.addEventListener("LocationChanging", function(event){
    var location = event.innerEvent.location;

    // Print out the location to the Java console
    Packages.java.lang.System.out.println("You clicked on: " + location);
});


替換選擇的文字區段:
/*選擇的起始位置*/
var starting = editors.activeEditor.selectionRange.startingOffset;

/*選擇的結束位置*/
var ending = editors.activeEditor.selectionRange.endingOffset;

/*選擇的文字內容*/
var text = editors.activeEditor.source.substring(starting, ending);

/*文字跳脫處理,或其他自訂的處理*/
text = escape(text);

/*替換選擇的文字*/
editors.activeEditor.applyEdit(starting, ending-starting, text);

/*重新選擇文字區段*/
editors.activeEditor.selectAndReveal(starting, text.length);


檔案存取:
var file = new File("myFile.txt");
file.createNewFile();
file.write("Date: ");
var text = file.readLines();


Web 資料請求的方式:
var req = new WebRequest();
req.open("GET", "http://xml.weather.yahoo.com/forecastrss?p=94103");
var text = req.send();
2011-12-21 15:05

[轉載] Aptana Scripting File.js Class Document

轉載自:Koders Code Search: File.js - JavaScript
/**
 * File.js
 *
 * Adding this file to your Active Libraries will give you code assist for the
 * Aptana Studio scripting engine.
 *
 * @author Kevin Lindsey
 * @version 1.0
 */

/**
 * This object represents a file or a directory in the file system
 *
 * @constructor
 * @param {String} name
 *      The relative or absolute path to a file or directory
 */
function File(name) {}

/*
 * Properties
 *

/**
 * Get the absolute path for this file or directory
 *
 * @type {String} Returns the absolute path to this file or directory
 */
File.prototype.absolutePath = "";

/**
 * Get the file's base name. This is the filename only without the extension.
 * If the file does not have an extension, then this will return the full
 * name
 *
 * @type {String} Returns this file's base name
 */
File.prototype.baseName = "";

/**
 * Determine if this file is readable
 * 
 * @type {Boolean} Returns true if this File is readable
 */
File.prototype.canRead = false;

/**
 * Determine if ths file is writable
 * 
 * @type {Boolean} Returns true if this File is writable
 */
File.prototype.canWrite = false;

/**
 * Determine if this file or directory exists in the file system
 *
 * @type {Boolean} Returns true if this File exists in the file system
 */
File.prototype.exists = false;

/**
 * Returns the file extension of this File
 *
 * @type {String} Returns the last instance of "." and the text after it.
 *      An empty string will be returned if no extension if found. The return
 *      value includes the '.'
 */
File.prototype.extension = "";

/**
 * Determines if thie File is a file in the file system
 *
 * @type {Boolean} Returns true if this File is a file in the file system
 */
File.prototype.isFile = false;

/**
 * Determines if this File is a directory in the file system
 *
 * @type {Boolean} Returns true if this File is a directory in the file
 *      system
 */
File.prototype.isDirectory = false;

/**
 * Returns a list of File objects for all files in the File. This is equivalent
 * to listing out all files in a directory
 *
 * @type {Array} Returns an array of File objects, one for each file and
 *      directory in this File
 */
File.prototype.list = [];

/**
 * Returns the file's name without path information
 *
 * @type {String} Returns the file's name
 */
File.prototype.name = "";

/**
 * Returns a new File object of this object's parent directory
 *
 * @type {File} Returns this file's parent File
 */
File.prototype.parentFile = {};

/**
 * Returns the character used to separate directories on the underlying OS
 *
 * @type {String} Returns the directory separator
 */
File.prototype.separator = "";

/*
 * Methods
 */

/**
 * Create a new file in the file system at the location specified by this
 * object
 *
 * @return {Boolean} Returns true if the file was created successfully.
 */
File.prototype.createNewFile = function() {};

/**
 * Return all lines from this File's text file
 * 
 * @return {Array} Returns an array of strings, one for each line in the file.
 */
File.prototype.readLines = function() {};


//eof
2011-12-21 15:05

[轉載] Aptana Scripting PrintStream.js Class Document

轉載自:Koders Code Search: PrintStream.js - JavaScript
/**
 * PrintStream.js
 *
 * Adding this file to your Active Libraries will give you code assist for the
 * Aptana Studio scripting engine.
 *
 * @author Kevin Lindsey
 * @version 1.0
 */

/**
 * This object represents an underlying Java PrintStream
 *
 * @constructor
 *
 /
function PrintStream() {}

/*
 * Methods
 */

/**
 * Print the given text to the underlying stream
 *
 * @param {String} text
 *      The text to send to the stream
 */
PrintStream.prototype.print = function(text) {};

/**
 * Print the given text to the underlying stream followed by end-of-line
 *
 * @param {String} text
 *      The text to send to the stream
 */
PrintStream.prototype.println = function(text) {};


//eof
2011-12-21 15:04

[轉載] Aptana Scripting Editor.js Class Document

轉載自:Koders Code Search: Editor.js - JavaScript
/**
 * Editor.js
 *
 * Adding this file to your Active Libraries will give you code assist for the
 * Aptana Studio scripting engine.
 *
 * @author Kevin Lindsey
 * @version 1.0
 */

/**
 * Editor
 *
 * @constructor
 * @extends {EventTarget}
 */
function Editor() {}

/*
 * Properties
 */

/**
 * Get/set the position of the cursor in this editor
 * 
 * @type {Number} The current cursor offset position
 */
Editor.prototype.currentOffset = 0;

/**
 * Get the File object that this editor is editing
 *
 * @type {File} Returns a File object or undefined
 */
Editor.prototype.file = {};

/**
 * Get the language MIME type for this editor
 * 
 * @type {String} Returns this editors language type
 */
Editor.prototype.language = "";

/**
 * Get the lexemes associated with this editor
 *
 * @type {Array} Returns an array of Lexemes
 */
Editor.prototype.lexemes = [];

/**
 * Get the line delimiter for this editor
 * 
 * @type {String} Returns the editor's line terminator
 */
Editor.prototype.lineDelimiter = "";

/**
 * Get the source associated with this editor
 *
 * @type {String} Returns the source text in this editor
 */
Editor.prototype.source = "";

/**
 * Get the length of the source in this editor
 * 
 * @type {Number} Returns the number of characters in this editor's document
 */
Editor.prototype.sourceLength = 0;

/**
 * Get the number of columns in a tab
 * 
 * @type {Number} Returns the number of spaces that equal one tab
 */
Editor.prototype.tabWidth = 0;

/**
 * Get the zero-based line number of the line at the top of the editor
 * 
 * @type {Number} The top-most line's index
 */
Editor.prototype.topIndex = 0;

/**
 * Get/set the editor's word wrap setting. Setting this to true turns on word
 * wrapping.
 * 
 * @type {Boolean} The word wrap setting.
 */
Editor.prototype.wordWrap = false;

/*
 * Methods
 */
 
/**
 * Apply an edit to the current document. This function allows you to delete
 * and insert text in one operation, if desired.
 *
 * @param {Number} offset
 *      The offset within the source where this edit is to take place
 * @param {Number} deleteLength
 *      The number of characters to remove before inserting the new text
 * @param {String} insertText
 *      The new text to insert at the given offset
 */
Editor.prototype.applyEdit = function(offset, deleteLength, insertText) {};

/**
 * Get the zero-based line number at the specified character offset
 * 
 * @param {Number} offset
 *       The character offset within the editor's document
 */
Editor.prototype.getLineAtOffset = function(offset) {};

/**
 * Scroll the editor to bring the current selection or caret position into
 * view.
 */
Editor.prototype.showSelection = function() {};


//eof
2011-12-21 15:04

[轉載] Aptana Scripting Global.js Document

轉載自:Koders Code Search: Global.js - JavaScript
/**
 * Global.js
 *
 * Adding this file to your Active Libraries will give you code assist for the
 * Aptana Studio scripting engine.
 *
 * @author Kevin Lindsey
 * @version 1.0
 */
 
/*
 * Properties
 */

/**
 * Retrieve the Editors object to access editors and editor events
 *
 * @type {Editors} Returns the global Editors object
 */
var editors = {};

/**
 * Retrieve the error print stream.
 *
 * @type {PrintStream} Returns the output stream used to display errors
 */
var err = {};

/**
 * This is a reference to the only instance of this object. All scripts run in
 * their own protected scope. However, this Global is accessible from all
 * scripts. Properties placed on "global" will be accessible to all scripts
 *
 * @type {Global} Returns a reference to the global scope
 */
var global = {};

/**
 * Retrieve the Menus object to access menus and menu events
 *
 * @type {Menus} Returns the global Menus object
 */
var menus = {};

/**
 * Retrieve the standard output print stream.
 *
 * @type {PrintStream} Returns the standard output stream
 */
var out = {};

/**
 * Retrieve the View object to access views and view events
 *
 * @type {Views} Returns the global Views object
 */
var views = {};

/*
 * Methods
 */

/**
 * Display an alert dialog with the given message
 *
 * @param {String} message
 *      The message to display in the dialog
 */
var alert = function(message) {};

/**
 * Execute a string in the current shell. This is experimental and may be
 * removed in a future version of the scripting environment
 *
 * @param {String} command
 *      The command to execute in the shell
 * @return {Object} Returns an object with the following properties: code,
 *      stdout, stderr. Code is the return code from the command. Stdout
 *      contains any text that was emitted to standard out while it was
 *      executing. Likewise, stderr contains any errors that were emitted.
 */
var execute = function(command) {};

/**
 * Call Java's System.getProperty.
 *
 * @param {String} property
 *      The name of the property to retrieve
 * @return {String} Returns the specified property value or the string
 *      "undefined" if the property does not exist
 */
var getProperty = function(property) {};

/**
 * Include a JavaScript file into the current script's scope. this is used to 
 * load dependent libraries into the script that invokes this function.
 * 
 * @param {String} filename
 *      The name of the file to include in the script
 */
var include = function(filename) {};

/**
 * Load a library into the scripting environment. Each script loaded with this
 * function will be assigned a unique ID and, if it exists, the init() function
 * will be invoked. This gives each script the ability to initialize itself and
 * to setup any event listeners it wishes to subscribe to.
 *
 * Each script will exist in its own scope; however, this Global is also
 * included in the scope chain. All variables and functions defined in the
 * script will not collide with any other scripts.
 *
 * Shared properties can be placed on the "global" property. All scripts loaded
 * via this function will then be able to see those properties. This can be
 * used to share data between scripts.
 *
 * @param {String} filename
 *      The file system path to the script to load
 * @return {String} Returns a unique string identifier for the loaded script.
 *      This identifier can be used later to invoke functions within the
 *      script; however, this is more for internal use at this point. If the
 *      script fails to load, this will return undefined.
 */
var loadBundle = function(filename) {};


//eof
2011-12-21 15:04

[轉載] Aptana Scripting Editors.js Class Document

轉載自:Koders Code Search: Editors.js - JavaScript
/**
 * Editors.js
 *
 * Adding this file to your Active Libraries will give you code assist for the
 * Aptana Studio scripting engine.
 *
 * @author Kevin Lindsey
 * @version 1.0
 */

/**
 * Editors
 *
 * @constructor
 */
function Editors(){}

/*
 * Properties
 */

/**
 * Get all editors currently being displayed
 *
 * @type {Array} Returns an array of Editor instances, one for each open editor
 */
Editors.prototype.all = [];

/**
 * Get the currently active editor
 *
 * @type {Editor} Returns the currently active editor or undefined if no editor is open
 */
Editors.prototype.activeEditor = {};

/*
 * Methods
 */

/**
 * Get the object that represents all editors of a given type. This is
 * typically used to register event handlers for a given event type for
 * all editors of a specified language.
 *
 * @param {String} type
 *      The editor type to retrieve. Currently, this is the MIME type for the
 *      language the editor supports.
 * @return {EditorType} Returns the editor type for the given MIME type or
 *      undefined if no editor type exists for the given MIME type
 */
Editors.prototype.getEditorType = function(type) {};

/**
 * Open the specified filename in a new editor
 *
 * @param {String} filename
 *      The name of the file to open in the file system
 * @return {Editor} Returns a new Editor object for the newly opened editor
 */
Editors.prototype.open = function(filename) {};


//eof
2011-12-21 14:32

[PHP] 兩種 while 的應用

滿足其中一個條件,就再來一次
<?php
$a = 'OK';
while(true){
    if($a == "OK"){
        var_dump('OK');        
        $a = "NO";
        continue;
        
    }elseif($a == "NO"){
        var_dump('NO');        
        $a = "XXX";
        continue;

    }else{
        var_dump('default');        
    }
    
    break;        
}


滿足其中一個條件,就跳過之後的判斷,同樣的程式流,也可以在 function 中用 return 做到。
<?php
$a = 'OK';
do{
    if($a == "OK"){
        echo 'OK'; break;
    }    
        
    if($a == "NO"){
        echo 'NO'; break;
    }        
    
    if($a == "Off"){
        echo 'NO'; break;
    }        

}while(false);
2011-12-16 15:04

Sphinx 增量索引的方法

之前有寫過一篇 MySQL 全文檢索引擎 - Sphinx 的文章,最近又把它拿出來用了,不過當時即時更新索引的問題,如今則找到解決的方法了,透過更新增量索引的方式達到即時更新。

簡單的說就是利用兩個索引表的合併查詢來做到,一個是完整的索引表,一個是針對當日資料變動的增量索引。

部分的設定檔如下:
# ...

source _source_base
{
    # 來源-共用的設定
}

source people_full : _source_base
{
    sql_query      = \
        SELECT \
            people_profile.id, \
            people_profile.main_name \
        FROM people_profile
        
    sql_query_killlist = \
        SELECT id FROM people_profile \
        WHERE update_date >= CURDATE()
}

# 增量索引來源,這邊只會抓出當日變動的資料
# 建議在 update_date 欄位加上 MySQL INDEX
source people_delta : people_full
{
    sql_query      = \
        SELECT \
            people_profile.id, \
            people_profile.main_name \
        FROM people_profile \
        WHERE people_profile.update_date >= CURDATE()
}


index _index_base
{
    # 索引-共用的設定
}

index people_full : _index_base
{
    source          = people_full
    path            = /var/lib/sphinxsearch/data/people_full
}

# 增量索引
index people_delta : _index_base
{
    source          = people_delta
    path            = /var/lib/sphinxsearch/data/people_delta
}

# 透過 distributed 類型來合併索引
index people
{
    type            = distributed
    local           = people_full
    local           = people_delta
}

# ...


建立 SphinxSE 表
特別注意在 CONNECTION 中所指定索引表為 people。
CREATE TABLE people_sphinx(
    id BIGINT UNSIGNED NOT NULL   COMMENT '搜尋結果的 Id',
    weight INT NOT NULL           COMMENT '搜尋結果的權重',
    query VARCHAR(3072) NOT NULL  COMMENT '搜尋的查詢條件',
  
    INDEX(query)
)ENGINE=SPHINX 
CONNECTION="sphinx://localhost:9312/people" 
COMMENT='People Sphinx搜尋連接介面';


SQL 的查詢測試
這裡使用 INNER JOIN 方式作查詢,這樣對於刪除資料的變動,就不會出現在查詢結果中。
SELECT A.id, A.main_name, B.weight
FROM people_sphinx B
INNER JOIN people_profile A
USING(id) 
WHERE B.query='馬丁尼茲;mode=any;limit=1000'


透過 PHP 更新增量索引
在資料 INSERT 或 UPDATE 時,去呼叫索引更新,這樣在第一時間就可以更新索引。
shell_exec('sudo indexer --quiet --rotate people_delta 2>&1');

如果 Server 是 Ubuntu,請記得在 vim /etc/sudoers 中賦予 apache 使用 indexer 的權限。
www-data ALL=(root) NOPASSWD: /usr/bin/indexer


在 crontab 中加上排程
利用離峰時間來更新完整的索引表,由於刪除資料的變動需要更新完整索引表才有辦法移除。
00 00 * * * indexer --quiet --rotate --all > /dev/null 2>&1
2011-12-16 13:01

[轉載][MySQL] Replication option binlog_format

轉載自:MYSQL5.1复制参数binlog_format

MySQL 5.1 中,在復制方面的改進就是引進了新的複制技術:基於行的複制。 簡言之,這種新技術就是關注表中發生變化的記錄,而非以前的照抄binlog 模式。 從MySQL 5.1.12 開始,可以用以下三種模式來實現:基於SQL語句的複制(statement-based replication, SBR),基於行的複制(row-based replication, RBR),混合模式複制(mixed-based replication, MBR)。 相應地,binlog的格式也有三種:STATEMENT,ROW,MIXED。 MBR 模式中,SBR 模式是默認的。


在運行時可以動態低改變binlog的格式,除了以下幾種情況:
  1. 存儲過程或者觸發器中間
  2. 啟用了NDB
  3. 當前會話試用RBR 模式,並且已打開了臨時表


如果binlog採用了MIXED 模式,那麼在以下幾種情況下會自動將binlog的模式由SBR 模式改成RBR 模式。
  1. 當DML語句更新一個NDB表時
  2. 當函數中包含UUID() 時
  3. 2個及以上包含AUTO_INCREMENT 字段的表被更新時
  4. 行任何INSERT DELAYED 語句時
  5. 用UDF 時
  6. 視圖中必須要求使用RBR 時,例如創建視圖是使用了UUID() 函數


設定主從復制模式的方法非常簡單,只要在以前設定複製配置的基礎上,再加一個參數:
binlog_format="STATEMENT" 
#binlog_format="ROW" 
#binlog_format="MIXED"


當然了,也可以在運行時動態修改binlog的格式。 例如
mysql> SET SESSION binlog_format = 'STATEMENT'; 
mysql> SET SESSION binlog_format = 'ROW'; 
mysql> SET SESSION binlog_format = 'MIXED'; 

mysql> SET GLOBAL binlog_format = 'STATEMENT'; 
mysql> SET GLOBAL binlog_format = 'ROW'; 
mysql> SET GLOBAL binlog_format = 'MIXED'; 


現在來比較以下SBR 和RBR 2中模式各自的優缺點

SBR 的優點:
  1. 歷史悠久,技術成熟
  2. binlog文件較小
  3. binlog中包含了所有數據庫更改信息,可以據此來審核數據庫的安全等情況
  4. binlog可以用於實時的還原,而不僅僅用於復制
  5. 主從版本可以不一樣,從服務器版本可以比主服務器版本高

SBR 的缺點:
  1. 不是所有的UPDATE語句都能被複製,尤其是包含不確定操作的時候。
  2. 調用具有不確定因素的UDF 時復制也可能出問題
  3. 使用以下函數的語句也無法被複製:
    • LOAD_FILE()
    • UUID()
    • USER()
    • FOUND_ROWS()
    • SYSDATE() (除非啟動時啟用了--sysdate-is-now 選項)
  4. INSERT ... SELECT 會產生比RBR 更多的行級鎖
  5. 複製需要進行全表掃描(WHERE 語句中沒有使用到索引)的UPDATE 時,需要比RBR 請求更多的行級鎖
  6. 對於有AUTO_INCREMENT 字段的InnoDB表而言,INSERT 語句會阻塞其他INSERT 語句
  7. 對於一些複雜的語句,在從服務器上的耗資源情況會更嚴重,而RBR 模式下,只會對那個發生變化的記錄產生影響
  8. 存儲函數(不是存儲過程)在被調用的同時也會執行一次NOW() 函數,這個可以說是壞事也可能是好事
  9. 確定了的UDF 也需要在從服務器上執行
  10. 數據表必須幾乎和主服務器保持一致才行,否則可能會導致複製出錯
  11. 執行複雜語句如果出錯的話,會消耗更多資源


RBR 的優點:
  1. 任何情況都可以被複製,這對複制來說是最安全可靠的
  2. 和其他大多數數據庫系統的複制技術一樣
  3. 多數情況下,從服務器上的表如果有主鍵的話,複製就會快了很多
  4. 複製以下幾種語句時的行鎖更少:
    • INSERT ... SELECT
    • 包含AUTO_INCREMENT 字段的INSERT
    • 沒有附帶條件或者並沒有修改很多記錄的UPDATE 或DELETE 語句
  5. 執行INSERT,UPDATE,DELETE 語句時鎖更少
  6. 從服務器上採用多線程來執行複製成為可能

RBR 的缺點:
  1. binlog 大了很多
  2. 複雜的回滾時binlog 中會包含大量的數據
  3. 主服務器上執行UPDATE 語句時,所有發生變化的記錄都會寫到binlog 中,而SBR 只會寫一次,這會導致頻繁發生binlog 的並發寫問題
  4. UDF 產生的大BLOB 值會導致複製變慢
  5. 無法從binlog 中看到都複製了寫什麼語句
  6. 當在非事務表上執行一段堆積的SQL語句時,最好採用SBR 模式,否則很容易導致主從服務器的數據不一致情況發生


另外,針對系統庫 mysql 裡面的表發生變化時的處理規則如下:
  1. 如果是採用INSERT,UPDATE,DELETE 直接操作表的情況,則日誌格式根據binlog_format 的設定而記錄
  2. 如果是採用GRANT,REVOKE,SET PASSWORD 等管理語句來做的話,那麼無論如何都採用SBR 模式記錄

注:採用RBR 模式後,能解決很多原先出現的主鍵重複問題
2011-12-16 12:41

[MySQL] Replication Master to Slave

Master上的設定

my.cnf
# 主機ID,不可以重複,範圍 0~4294967295
server-id       = 1

# Log 的名稱或路徑,只有名稱會將檔案放在 datadir 下
log_bin         = mysql-bin

# Log 的格式{ROW,STATEMENT,MIXED},最低支援版本 5.1.8  
binlog_format = MIXED

# 需要同步的資料庫,多個寫多行
binlog_do_db    = test
binlog_do_db    = mydb

# 針對 InnoDB 且有用 transaction 的設定
innodb_flush_log_at_trx_commit=1
sync_binlog=1 

進入Master mysql
mysql -u root -p

建立同步連接帳號 db_sync,密碼12345,給 slave_host,
mysql> GRANT REPLICATION SLAVE ON *.* TO 'db_sync''slave_host' IDENTIFIED BY '12345';

鎖定資料庫寫入
mysql> FLUSH TABLES WITH READ LOCK;

取得 MASTER 上的 Log File 名稱與 Position 編號,這個編號代表當前的 Log 戳記
mysql> SHOW MASTER STATUS\G;
File:mysql-bin.000010
Position:106
Binlog_Do_DB:test,mydb
Binlog_Ignore_DB:

離開 mysql
mysql> quit

匯出 MASTER 上的資料
mysqldump -uroot -p --flush-logs --opt --master-data test > test.sql

解除鎖定
mysql -u root -p -e UNLOCK TABLES;



Slave上的設定

my.cnf
# 主機ID,不可以重複,範圍 0~4294967295
server-id       = 2

# 需要同步的資料庫,或指定的資料表
replicate_wild_do_table = test.%
replicate_wild_do_table = mydb.category
replicate_wild_do_table = mydb.blog

# 與 Master 斷線後,重新嘗試連接的時間(sec) 
master-connect-retry = 60

匯入資料
mysql -uroot -p test < test.sql

進入 Slave mysql
mysql -uroot -p

停止跟清除之前的 SLAVE 連接
mysql> STOP SLAVE; RESET SLAVE;

設定Slave 與 Master 的連接
mysql> CHANGE MASTER TO
    MASTER_HOST='master_host',
    MASTER_USER='db_sync',
    MASTER_PASSWORD='12345',
    MASTER_LOG_FILE='mysql-bin.000011',
    MASTER_LOG_POS=106;

啟動 SLAVE 的連接
mysql> START SLAVE;

察看連接狀態
mysql> SHOW SLAVE STATUS\G;
Slave_IO_State:Connecting to master
Master_Host:master_host
Master_User:db_sync
Master_Port:3306
Connect_Retry:60
Master_Log_File:mysql-bin.000011
Read_Master_Log_Pos:106
Relay_Log_File:master_host-relay-bin.000011
Relay_Log_Pos:4
Relay_Master_Log_File:mysql-bin.000011
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:test.%,mydb.category,mydb.blog
Replicate_Wild_Ignore_Table:
Last_Errno:0
Last_Error:
Skip_Counter:0
Exec_Master_Log_Pos:106
Relay_Log_Space:106
Until_Condition:None
Until_Log_File:
Until_Log_Pos:0
Master_SSL_Allowed:No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master:0

接著到 Master 上新增一筆資料測試看看吧!


參考文章:
MYSQL 主从服务器配置
mysql主从同步快速设置
MySQL 設定 Replication (Master – Slave)
多主一从mysql replication同步表的大胆尝试
MySQL复制的数据库过滤若干问题
MYSQL5.1复制参数binlog_format
2011-12-16 06:49

[PHP] 縮圖方式的比較

這兩種的缺點是,都會根據圖片的像素大小,而佔用PHP的記憶體,會造成 Fatal error: Out of memory 的錯誤出現,有一種狀況是一個 3MB 大小的 JPEG 實際的像素大小卻是 128MB,再來 GD 支援的圖片類型有限,大約就是四五種常用類型。

優點是指需要安裝 GD 套件,這個套件不管是在 Windows 或 Linux 上很容易找到跟安裝,在處理圖片的類型明確跟尺寸不大的情況下,使用這兩個函數是不錯的。

為了改善 imageCopyResampled 效率,可以利用 imageCopyResized 做預先縮圖,例如要縮圖的大小為 100*100 時,可以先將圖片縮小成四倍或八倍,如 400*400 或 800*800,可改善超大圖造成的效率不好。

  • ImageMagick + Imagick 使用外部的程式來處理圖片,使用指令的方式或透過 Imagick 套件來處理縮圖。
缺點是透過指令的方式很不友善,且容易受到系統權限的限制,而 Imagick 套件在 Windows 上不容易找到合適的 DLL。

優點是支援下面多種格式,效率快且沒有記憶體錯誤的問題。
3FR, A, AI, ART, ARW, AVI, AVS, B, BGR, BGRA, BMP, BMP2, BMP3, BRF, BRG, C, CAL, CALS, CAPTION, CIN, CIP, CLIP, CMYK, CMYKA, CR2, CRW, CUR, CUT, DCM, DCR, DCX, DDS, DFONT, DJVU, DNG, DOT, DPX, EPDF, EPI, EPS, EPS2, EPS3, EPSF, EPSI, EPT, EPT2, EPT3, ERF, EXR, FAX, FITS, FRACTAL, FTS, G, G3, GBR, GIF, GIF87, GRADIENT, GRAY, GRB, GROUP4, HALD, HISTOGRAM, HRZ, HTM, HTML, ICB, ICO, ICON, INFO, INLINE, IPL, ISOBRL, J2C, JNG, JP2, JPC, JPEG, JPG, JPX, K, K25, KDC, LABEL, M, M2V, M4V, MAP, MAT, MATTE, MIFF, MNG, MONO, MOV, MP4, MPC, MPEG, MPG, MRW, MSL, MSVG, MTV, MVG, NEF, NULL, O, ORF, OTB, OTF, PAL, PALM, PAM, PATTERN, PBM, PCD, PCDS, PCL, PCT, PCX, PDB, PDF, PDFA, PEF, PES, PFA, PFB, PFM, PGM, PGX, PICON, PICT, PIX, PJPEG, PLASMA, PNG, PNG24, PNG32, PNG8, PNM, PPM, PREVIEW, PS, PS2, PS3, PSB, PSD, PTIF, PWP, R, RADIAL-GRADIENT, RAF, RAS, RBG, RGB, RGBA, RGBO, RLA, RLE, SCR, SCT, SFW, SGI, SHTML, SR2, SRF, STEGANO, SUN, SVG, SVGZ, TEXT, TGA, THUMBNAIL, TIFF, TIFF64, TILE, TIM, TTC, TTF, TXT, UBRL, UIL, UYVY, VDA, VICAR, VID, VIFF, VST, WBMP, WMF, WMV, WMZ, WPG, X, X3F, XBM, XC, XCF, XPM, XPS, XV, XWD, Y, YCbCr, YCbCrA, YUV
2011-12-15 18:51

[PHP] Documentor (phpdoc) 備忘

Linux 安裝指令
sudo pear install -o PhpDocumentor


Windows 安裝指令
C:\wamp\bin\php\php5.2.4\pear.bat install -o PhpDocumentor


使用方式
phpdoc --parseprivate \
    --output HTML:frames:earthli \
    --ignore Smarty/ \
    --directory /var/www/lib,/var/www/data_mod,/var/www/etc \
    --target /var/www/docs


phpdoc 參數說明
-f--filename要解析的檔案名稱,可使用 ‘,’分隔多個檔案 “file1,file2”,可以包含完整路徑和使用 * ? 萬用符號。
-d--directory要解析的目錄路徑,可使用 ‘,’分隔多個目錄路徑 “directory1,directory2”。
-t--target指定要輸出的目錄。
-i--ignore要忽略的檔案名稱,可使用 ‘,’分隔多個檔案 “file1,file2”,可以使用 * ? 萬用符號。
-is--ignoresymlinks忽略系統連結的檔案或目錄,預設是關閉的。
-it--ignore-tags忽略解析的標籤。 @package, @subpackage, @access, @ignore 可能是無法忽視。
-q--quiet不顯示解析/轉換的訊息,在 cron 排程時可以選擇開啟,預設是關閉的。
-ti--title產生出的文件的標題,預設為 ‘Generated Documentation’。
-h--help顯示幫助訊息。
-pp--parseprivate將私有(private)成員函式或私有變數也都加入程式文件裡。不然產生出的文件裡只會有公開(public)和保護(protected)的成員函式和變數。
-o--output設置輸出文件的格式
  • HTML:frames:* - 包含iframe的HTML格式
  • HTML:frames:default – Javadoc風格的文檔模板,很少有格式
  • HTML:frames:earthli – 漂亮的模板(作者:Marco von Ballmoos)
  • HTML:frames:l0l33t – 流行模板
  • HTML:frames:phpdoc.de – 類似於phpdoc.de的PHPDoc輸出
  • HTML:frames:phphtmllib – 非常棒的用戶貢獻模板
  • HTML:frames:phpedit – 基於PHPEdit Help Generator的文檔
  • HTML:Smarty:* - 不使用iframe的HTML格式
  • HTML:Smarty:default – 使用css控制的黑體模板
  • HTML:Smarty:HandS – 基於PHP的格式,但是經過優化,帶有logo圖片
  • HTML:Smarty:PHP – 風格接近PHP官網
  • CHM:default:* - 輸出CHM幫助文檔
  • CHM:default:default – windows幫助文檔,基於HTML:frames:l0l33t
  • PDF:default:* - PDF格式
  • PDF:default:default – 標準純文本PDF格式
  • XML:DocBook:* - 以DocBook格式輸出的XML
  • XML:DocBook/peardoc2:default – 可以被編譯成peardoc的文檔
-j--javadocdesc相容 JavaDoc 的格式,預設是關閉的


中文亂碼的問題
新版的 phpdoc 輸出的格式已經是 UTF-8 了,所以只要在目錄下增加一個 .htaccess 文件,然後內容為:
AddCharset UTF-8 .html


參考文件:
多采多姿的程式筆記: phpDocumentor筆記 - 0 立即體驗
phpDocumentor Tutorial
phpDocumentor学习记录
2011-12-14 21:02

[轉載] Linux Rsync 參數說明

轉載自: Rsync 中文參數說明

內容開始
rsync 資料同步敘述:
rsync和rcp的模式很相似,不過rsync有需多參數可以使用來加速檔案傳送.
rsync遠端更新協定(remote-update protocol)可以透過網路來傳輸兩端檔案不同的地方.語法:
rsync [OPTION]... SRC [SRC]... DEST
rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST
rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST
rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/DEST
rsync [OPTION]... [USER@]HOST:SRC [DEST]
rsync [OPTION]... [USER@]HOST::SRC [DEST]
rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]


rsyncd 的設定檔:
/usr/local/etc/rsyncd.conf

說明:
[ohaha]: rsync區段的設定名稱
path: 備份資料存放的路徑
auth users: 連結rsync服務的帳號
uid,gid: 採用何種身分進行檔案存取
secerts file: 帳號密碼檔位置
read only: 是否唯讀


參數:
-h,--help顯示rsync求助資訊.
--version顯示rsync版本.
-v,--verbose複雜的輸出訊息.
-q,--quiet安靜模式,幾乎沒有訊息產生.常用在以cron執行rsync.
-I,--ignore-times通常rsync為了加快速度會忽略同樣檔案大小且同樣存取時間點的檔案. 可以透過此參數關閉此快速檢查.
--size-onlyrsync只檢查檔案大小是否改變,不管時間存取點是否改變. 通常用在mirror,且對方時間不太正確時.
-c,--checksum在傳送之前透過128bit的md4檢查碼來檢查所有要傳送的檔案.(會拖慢速度.)
-a,--archivearchive mode 權限保存模式,相當於 -rlptgoD 參數. 很快速的保存幾乎所有的權限設定,除了硬式連結(透過-H設定).
-r,--recursive複製所有下層的資料(遞迴)
-R,--relative使用相對路徑.
如: rsync foo/bar/foo.c remote:/tmp/ 在遠端產生/tmp/foo.c檔案
rsync -R foo/bar/foo.c remote:/tmp/ 在遠端產生/tmp/foo/bar/foo.c 檔案
-R,--relative不使用相對路徑.
-b,--backup目的地端先前已經存在的檔案在傳輸或刪除前會被備份.
--backup-dir=DIR設定備份的資料夾.
--suffix=SUFFIX指定備份的檔案名稱字尾形式(預設為~).
-K,--keep-dirlinks接收方將連結到資料夾的檔案視為資料夾處理
-l,--links複製所有的連結
-H,--hard-links保留硬式連結
-p,--perms保留檔案權限
-o,--owner保留檔案擁有者(root only)
-g,--group保留檔案群組
-D,--devices保留device資訊(root only)
-t,--times保留時間點
-n,--dry-run不實際執行傳送,只顯示將會有的傳輸動作
-S,--sparse嘗試去處理稀疏的檔案,讓這些檔案在目的端佔去較少的磁碟空間.
-W,--whole-file複製所有的檔案,不額外作檢查.
--no-whole-file關閉 --whole-file 參數
-x,--one-file-system不要跨越檔案系統分界(只在一個檔案系統處理)
-B,--block-size=SIZE強制透過rsync程式去比對修復block-sizeforce
-e--rsh=COMMAND定義所使用的remote shell
--rsync-path=PATH定義rsync在遠端機器存放資料的路徑
--existing只比對更新目的端已經存在的檔案
--ignore-existing忽略目的端已經存在的檔案(也就是不更新)
--delete刪除傳送端已經不存在,而目的端存在的檔案
--delete-excluded除了把傳送端已經不存在,而目的端存在的檔案刪除之外, 也刪除 --exclude 參數所包含的檔案.
--delete-afterrsync預設會在檔案傳送前進行相關刪除動作確保接收端有足夠的檔案空間, 但可以透過 --delete-after 讓刪除動作在檔案傳送後再行刪除.
--ignore-errors忽略任何錯誤既使是I/O error 也進行 --delete 刪除動作.
--max-delete=NUM定義rsync不要刪除超過 NUM 個檔案.
--partialrsync若遇到傳輸過程中斷時,會把那些已經傳輸的檔案刪除.
在某種狀況下保留那些部分傳送的檔案是令人高興的.
你可以透過 --partial 參數達到這個目的.
--partial-dir=DIR在 --partial 參數啟動時,你還可以定義rsync把那些部分傳送的檔案
寫入定義的資料夾,而非直接寫入目的端.需要注意的是, 此資料夾不應該被其他使用者可以寫入.(如:/tmp)
--force當目的端資料夾被傳送端非資料夾名稱覆蓋時,強制rsync刪除資料夾, 即使該資料夾不是空的.
--numeric-ids不將傳送端檔案的uid及gid值,與目的端的使用者/群組進行配對. 若傳送端並沒有uid及gid的對應名稱(如:原帳號群組被刪除的遺留檔案), 或目的端沒有相對應的帳號/群組,保留數字型態的uid/gid
--timeout=TIMEOUT設定 I/O 逾時的時間(秒). 超過這個秒數而沒有資料傳送,rsync將會結束. 預設為0,也就是沒有定義逾時時間.
-T,--temp-dir=DIR定義rsync在接收端產生暫時性的複製檔案時使用資料夾暫存. 預設是直接在接收端資料夾直接產生暫存檔案.
--compare-dest=DIR定義rsync在目的端建立資料夾來比對傳送過來的檔案.
--link-dest=DIR與 --compare-dest 相同,但同時會針對無法改變的檔案建立硬式連結.
-z,--compress壓縮模式,當資料在傳送到目的端進行檔案壓縮.
-P-P參數和 --partial --progress 相同.只是為了把參數簡單化.
-C,--cvs-exclude排除那些通常不希望傳送的檔案.定義的方式與CVS傳送相同:
RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state
.nse_depinfo *~ *$ *.old *.bak *.BAK *.orig *.rej
*.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/
符合以上條件的都會被忽略而不傳送.
--exclude=PATTER符合PATTERN(規則表示式)樣式的檔案不進行傳送
--exclude-from=FILE和--exclude參數相同,不過是把不進行傳送的檔案事先寫入某一檔案. 執行時,透過此參數讓rsync讀取. (; #開頭的行列或空白行會被rsync忽略)
--include=PATTERN定義rsync不要排除符合pattern樣式的檔案.
--include-from=FILE和--include參數相同,只不過把要包含的檔案寫到某一檔案.
--files-from=FILE把要傳送的檔案名稱都精確的寫入某一檔案,讓rsync讀取. 如: rsync -a --files-from=/tmp/foo /usr remote:/backup
-0--from0定義檔案所要讀取的檔案是null字元結尾.
--version顯示版本訊息.
--daemon定義rsync以daemon型態執行.
--no-detach當以daemon型態執行時,不要進行分裂且變成背景程序.
--address=ADDRESS定義所要連結(bind)的ip位址或是host名稱(daemon限定)
--config=FILE定義所要讀取的設定檔rsyncd.conf位置(daemon限定) 預設值為 /usr/local/etc/rsyncd.conf
--port=PORT定義rsyncd(daemon)要執行的port(預設為tcp 873)
--blocking-io使用blocking I/O連結遠端的shell,如rsh , remsh
--no-blocking-io使用non-blocking連結遠端的shell,如ssh (預設值)
--stats顯示檔案傳送時的資訊狀態
--progress顯示傳送的進度.(給檔案傳送時,怕無聊的人用的..)
--log-format=FORMAT定義log的格式(在rsyncd.conf設定)
--password-file=FILE從檔案讀取與遠端rsync伺服器連結的密碼
--bwlimit=KBPS定義傳輸頻寬的大小(KBytes/秒)
--write-batch=FILE把紀錄資料寫入一個檔案(給其他相同環境且相同需求的機器使用)
--read-batch=FILE透過讀取紀錄檔案來進行傳輸.(檔案由 --write-batch 參數產生)
--checksum-seed=NUM定義檔案 checksum-seed 的大小(byte)
-4--ipv4使用IPv4協定
-6--ipv6使用IPv6協定
2011-12-14 16:22

[PHP] 取得用戶真實 IP

轉載自:精進你的程式碼 - 從取得用戶端 IP 的函式談起

<?php
function get_client_ip(){
    foreach (array(
        'HTTP_CLIENT_IP',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED',
        'HTTP_X_CLUSTER_CLIENT_IP',
        'HTTP_FORWARDED_FOR',
        'HTTP_FORWARDED',
        'REMOTE_ADDR'
    ) as $key) {
        if(!array_key_exists($key, $_SERVER)){ continue; }
        
        foreach (explode(',', $_SERVER[$key]) as $ip) {
            $ip = trim($ip);
            if ((bool) filter_var($ip, 
                FILTER_VALIDATE_IP,
                FILTER_FLAG_IPV4 |
                FILTER_FLAG_NO_PRIV_RANGE |
                FILTER_FLAG_NO_RES_RANGE
            )){ return $ip; }
        }
    }
    return null;
}
2011-12-14 15:26

[Ubuntu] 掛載 Windows 分享目錄

  • 安裝 smbfs 套件
    sudo apt-get install smbfs
  • 建立掛載目錄
    sudo mkdir /mnt/windows_share
  • 開放最大權限
    sudo chmod 777
  • 測試掛載
    sudo mount -t cifs //192.168.0.10/my_share /mnt/windows_share -o username=jax,password=1234,noacl,noperm,codepage=cp950,iocharset=big5,file_mode=0666,dir_mode=0777
    
  • 察看是否成功
    df -h
    Filesystem Size Used Avail Use% Mounted on
    //192.168.0.10/my_share 7.9G 208K 7.9G 1% /mnt/windows_share
  • 卸載
    sudo umount /mnt/windows_share
  • 修改開機掛載設定檔
    sudo vim /etc/fstab
    /mnt/windows_share was on //192.168.0.10/my_share
    //192.168.0.10/my_share /mnt/windows_share cifs username=jax,password=1234,noacl,noperm,codepage=cp950,iocharset=big5,file_mode=0666,dir_mode=0777 0 0
    
  • 套用開機設定檔
    mount -a
  • 再次察看是否成功
    df -h
    Filesystem Size Used Avail Use% Mounted on
    //192.168.0.10/my_share 7.9G 208K 7.9G 1% /mnt/windows_share

參考資料:
在 ubuntu 中 mount windows 分享的目錄
載掛(Mount)遠端資料夾的應用
ubuntu的几个技巧: 自动连接Windows共享文件夹, 定时文件同步备份
2011-11-23 00:38

[MySQL] EXPLAIN 分析報告的意義

轉載自:PHP + MySQL 程式設計研習

  • table
    表示所引用的表格名稱。
  • type
    表示查詢時的「聯結類型」(join type),以下依序是「最佳」至「最差」的各種類型:
    • system
      表格中僅有一列。這是 const 類型的一個特例。
    • const
      表格中符合條件的只有一列。因為僅有一列,其值在後續的查詢中可被視為常數。
    • eq_ref
      表示在與其它表格的資料列結合時,此表格只有一列會被讀取。當 join 使用到資料表中的所有索引,並索引是 UNIQUE 或 PRIMARY KEY 時才會被用到。
    • ref
      表示在與其它表格的資料列結合時,此表格中所有符合的資料列都會被讀出來。這是當 join 只使用到部份鍵值(註),或此鍵非 UNIQUE 或 PRIMARY KEY 時才會用到(依照 join 的條件仍然無法選定單一目標列)。若因此符合的資料列數不多的話,它也算是一種不錯的「聯結類型」。
      註:我們指定「A+B」欄位為 index key,但查詢時只用到「A」欄位。
    • range
      表示將在一定範圍內執行搜尋的動作。
    • index
      與 ALL 相同,但只有 index table 會被瀏覽。這通常比 ALL 快,因為 index table 通常比原始資料表來得小。
    • All
      表示這項查詢將對整個原始資料表瀏覽一遍,是最不好的類型。
  • possible_keys
    表示 MySQL 能夠藉由哪些 index 來搜尋目標。
  • key
    表示 MySQL 實際藉由哪個 index 來搜尋目標。
  • key_len
    表示 MySQL 實際使用的 key 長度。若 index key 是由兩個欄位以上複合而成的話,您可以在此看見 MySQL 使用了 index 的多少部份。
  • ref
    表示哪個欄位(或常數)將被用來與 key 一起比對。
  • rows
    表示 MySQL 粗略估計在查詢的過程中,必須瀏覽的資料列數。
  • Extra
    顯示 MySQL 在解決這項查詢工作時的一些附加訊息。例如:「where used」表示 where 子句將會限制某些資料列的輸出。
2011-11-23 00:14

[MySQL] TEMPORARY 臨時表

最近為了解決一個效率太差的問題而找上這個東西,由於有一個資料表的筆數實在太多了,再加上好幾百個 query 都同時在同一個區段做查詢,剛好可以使用臨時表來處理這個問題,原本查詢需要的時間大概超過一分鐘,現在最多只要 10 秒,刷新後約 2 秒。

MySQL 的臨時表只會存在在 Session 期間,當 Session 結束後就會自動刪除,不同的 Session 的表名稱並不會衝突,所以就算用一樣的名稱也不會出現錯誤,臨時表只能用在 MEMORY,MyISAM,MERGE,或者InnoDB 引擎上。

-- 透過 SELECT 建立臨時表
CREATE TEMPORARY TABLE my_temp_table ENGINE=MEMORY
SELECT * FROM my_table WHERE col_1 > 1000

-- 為臨時表建立索引
ALTER TABLE my_temp_table
    ADD INDEX (col_1),
    ADD INDEX (col_1,col_2)

參考資料:
MySQL CREATE TABLE Syntax
mysql temporary table簡介
避免 MySQL 使用 temporary table on disk
2011-11-22 23:29

[PHP] 把多個圖片壓縮封裝並下載

<?php
$fileList = array(
    '/var/www/pics/001.jpg',
    '/var/www/pics/002.jpg',
    '/var/www/pics/003.jpg',
    '/var/www/pics/004.jpg',
    '/var/www/pics/005.jpg',
    '/var/www/pics/006.jpg',
);


/*建立臨時壓縮檔*/
$file = tempnam("tmp", "zip");
$zip = new ZipArchive;
$res = $zip->open($file, ZipArchive::CREATE|ZipArchive::OVERWRITE);
if ($res!==true) { exit('壓縮錯誤');}

foreach ($filePathList as $filePath){
    $zip->addFile($filePath, $fileName);
}
$zip->close();

ob_end_clean();
header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-disposition: attachment; filename=pics_list.zip');

readfile($file);
unlink($file); 
exit;

參考連結:PHP: ZipArchive - Manual
2011-10-20 15:43

[PHP] 以活躍指標顯示日期時間

function ShowTimeLive($date) {
    $diff = time() - strtotime($date);
    
    if($diff < 60){
        return $diff.' 秒前';
    }elseif($diff < 3600){
        return round($diff/60).' 分鐘前';
    }elseif($diff < 86400){
        return round($diff/3600).' 小時前';
    }elseif($diff < 432000){
        return round($diff/86400).' 天前';
    }else{/*超過5天*/
        return date('n月j日',strtotime($date));
    }
}

/*demo*/
echo ShowTimeLive('2011-10-13 21:14:42');
2011-10-20 15:31

[PHP] 使用簡易單位顯示檔案大小

function ShowBytes($size) {
    $size=doubleval($size);
    $sizes = array(
        " Bytes", 
        " KB", 
        " MB", 
        " GB", 
        " TB"
    );
    if ($size == 0) { 
        return('n/a'); 
    } else {
        $i = floor( log($size, 1024) );
        return (round( $size/pow(1024, $i), 2) . $sizes[$i]); 
    }
}

/*demo*/
for($size=0; $size<3000000; $size+=512) {
    echo $size,' => ', ShowBytes($size),'<br />';
}
/*
0 => n/a
512 => 512 Bytes
1024 => 1 KB
1536 => 1.5 KB
2048 => 2 KB
2560 => 2.5 KB
3072 => 3 KB
3584 => 3.5 KB
*/
2011-10-20 15:26

[PHP] 格式化單位秒數

只要將秒數減去 28800 之後,丟進 date() 就OK了,不過只能顯示到小時,至於要有天數的部分就不能這樣做了,只能用在一些短時間的顯示。

for($sec=0; $sec<30000; $sec+=30) {
    echo $sec,' => ', date('H:i:s',$sec-28800),'<br />';
}
/*
0 => 00:00:00
30 => 00:00:30
60 => 00:01:00
90 => 00:01:30
120 => 00:02:00
150 => 00:02:30
180 => 00:03:00
*/
2011-09-13 18:01

[轉載] Linux shell script 的彩色控制

轉載自:Linux shell script 的彩色控制

Linux 下的終端機畫面不是只能換換背景而已,顯示出來的顏色也是能控制的。使用的顏色就像以前的DOS 時代,或者現在的BBS 顏色控制方式一樣。

以shell 的顯示為例,顯示的格式如下:

\33[ 文字樣式 ; 文字顏色 ; 背景顏色 m
文字內容………………
\33[0m

文字樣式有列下幾種色碼可以使用:
  • 0 一般亮度
  • 1 高度度
  • 4 加底線
  • 5 灰底

文字顏色則都是3開頭,有下列色碼:
  • 30 黑色
  • 31 紅色
  • 32 綠色
  • 33 黃色
  • 34 藍色
  • 35 紫色
  • 36 青綠
  • 37 白色

再來是背景顏色色碼,都是4開頭:
  • 40 黑色
  • 41 紅色
  • 42 綠色
  • 43 黃色
  • 44 藍色
  • 45 紫色
  • 46 青綠
  • 47 白色

如果我要在畫面上顯示高亮度的綠色(32)及黑色背景,可以如下:
sprintf "\33[1;32;40m 我的文字 \33[0m"

也可以分開來寫比較清楚
sprintf "\33[1;32;40m "
sprintf "我的文字"
sprintf "\33[0m"

記得shell 輸出碼要用 printf 而不是用一般的 echo。echo 的話要寫成 echo -e 。
但並不是所有的終端機畫面都是用黑色背景的。如果我們不要指定它的黑色背景,讓它使用系統原始背景色,可以省略背景描述變成如下:
sprintf "\033[1;32m"
sprintf "我的文字"
sprintf "\033[0m"

是不是就比較完美了呢。

其實這些控制碼和BBS 的還真像。
2011-09-09 11:11

RamDisk 設定 & 瀏覽器 cache 設定

上次已經有建立過 RamDisk 一次了,最近重灌又在玩了一次,說真的,不紀錄下來,久久又會忘記了。

首先先設定 C:\boot.ini,在 [operating systems] 的最後加入 /PAE,這是為了讓 XP能夠定址到3G以上的空間,然後重新開機才會生效。
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /noexecute=alwaysoff /PAE







然後將多出來的記憶體建立成 RamDisk,先是要讓 SuperSpeed RamDisk 抓到多出來的記憶空間。




這裡選擇要自動搜尋,它會將沒用到的空間標記起來。


接著選擇建立一個新的 RamDisk,就會出現以下的畫面,先是設定空間的大小。








設定 Chrome 的快取目錄指向到 RamDisk 中,只要在開啟的連結中加入 --disk-cache-dir="P:\temp\chrome" 參數就可以改變快取目錄。




設定 Firefox 的快取目錄指向到 RamDisk 中,在 Firefox 的網址列中鍵入 about:config,進入進階設定的頁面中,然後新增一個名稱為 browser.cache.disk.parent_directory 的字串,其值為 P:\temp\firefox





2011-09-09 10:15

[jQuery] 等待多個 Ajax 請求完成

最近在找等待多個 Ajax 完成的方法,找到 jQuery.when函数分析這篇文章中有處理多個 Ajax 的方法,但對於數量不固定的狀況,jQuery.when 輸入參數的方式實在有點討厭,必須要指定 Ajax 的數量,還好想起有 apply 這個方法可以用,可以將 array 轉換成呼叫 function 的參數,這樣不管有多少數量,都可以很輕鬆的帶入到 jQuery.when 中。

/*將多個 Ajax 加到 array 中*/
var ajaxRequest=[];
for (var i=0; i<10; i++){
    ajaxRequest.push(
        $.ajax({
            data: {'a':i},
            success: function(data) {
                console.log(data);
            }
        })
    );
};

/*利用 apply 將 ajaxRequest 帶入 jQuery.when*/
var der=$.when.apply( $, ajaxRequest )

der.always(function() {
    console.log(arguments);
    alert('全部結束');
});        
der.done(function() {
    console.log(arguments);
    alert('全部成功');
});        
2011-09-05 14:10

[jQuery] textarea 自動高度很簡單

上網找了一些文章來看後,自己又再改了一改,發現很簡單就可以達到自動高度的功能,真是給他快樂的說。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>文字區塊自動高度</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>
    <script type="text/javascript"> 
    jQuery(function($) {
        $("textarea.AutoHeight").css("overflow","hidden").bind("keydown keyup", function(){
            $(this).height('0px').height($(this).prop("scrollHeight")+"px");
        }).keydown();
    });
    </script> 
</head>
<body>
    <textarea class="AutoHeight"></textarea>
    <textarea class="AutoHeight"></textarea>
    <textarea class="AutoHeight"></textarea>
</body>
</html>
2011-08-18 16:42

[轉載] apache2ctl 指令

轉載自:Ubuntu系統網絡應用服務器Apache配置基礎

apache2ctl 是 Apache2 服務器的前端程序。他可以幫助管理員控制 Apache2 後台 daemon 的功能。

apache2ctl -v
顯示 apache 的版本。
apache2ctl -V
顯示 apache 的版本和編譯參數。
apache2ctl -h
輸出命令列選項的簡要說明。
apache2ctl -l
輸出一個靜態編譯在服務器中的模塊的列表。 它不會列出使用 LoadModule 指令動態加載的模塊。
apache2ctl -L
輸出一個指令的列表,并包含了各指令的有效參數和使用區域。
apache2ctl -t
僅對配置文件執行語法檢查。
apache2ctl -t -D DUMP_VHOSTS
apache2ctl -S
顯示虛擬主機配置的詳細信息。
apache2ctl -t -D DUMP_MODULES
apache2ctl -M
顯示動態模組加載的詳細信息。
apache2ctl start
啟動 apache2 daemon。
apache2ctl stop
停止 apache2 daemon。
apache2ctl restart
重新啟動 apache2 daemon。
apache2ctl status
顯示一個簡要的狀態報告。
apache2ctl graceful
優雅地重新啟動 apache2 daemon。 如果 daemon 尚未啟動,則啟動它。它和標準重新啟動的不同之處在於:不會中斷當前已經打開的連接,也不會立即關閉日誌。這意味著,如果在日誌滾動腳本使用它,則在處理日誌之前必須加入一個實實在在的延遲,以確保老的日誌文件在被處理前已經關閉。在重新啟動 daemon 之前,此命令會使用 configtest 自動檢查配置文件,以確保 apache 不會死掉。
apache2ctl graceful-stop
優雅地停止 apache2 daemon。 它和標準停止的不同之處在於:不會中斷當前已經打開的連接,也不會立即關閉日誌。
apache2ctl configtest
執行一次配置文件語法檢查。 它解析配置文件,並報告 Syntax Ok 或者是特定的語法錯誤詳細信息。
2011-08-18 15:10

[Ubuntu] Apache 未設定 ServerName 造成的警告

Ubuntu 下的 Apache 有時候在啟動時會出現以下的警告訊息:
Could not reliably determine the server's fully qualified domain name, using 127.0.1.1 for ServerName

由於沒有任何 ServerName 的設定造成的警告,只要在 /etc/apache2/apache2.conf 中加入 ServerName localhost 的預設值就不會出現這個錯誤了。

這個問題我之前也遇到過,但不常發生,久了就忘記該把設定寫在哪裡了,因為可以設定的地方有三四個,為了遵守統一的規則才不會亂。

當要建立多個虛擬主機時,只要在 <VirtualHost *:80> 中才去覆寫 ServerName my_host_name 就不會衝突了。

2011-07-21 15:49

[C語言] strtok 切開字串

#include <string.h>

char *strtok(char *str, const char *delim);

strtok 提供的功能是將字串依照所設定的切分符號字串分解。

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv){
    if (argc != 2) {
        fprintf(stderr, "Usage:  %s <list>\n", argv[0]);
        return 1;
    }

    /*將字串複製到新的空間*/
    char *temp = strdup((const char*)argv[1]);
    char *token;

    /*取出字段*/
    token = strtok(temp, ",");
    while (token != NULL){
        puts(token);

        /*取得下一個字段*/
        token = strtok(NULL, ",");
    }

    puts(argv[1]);
    puts(temp);

    /*釋放剛剛複製的空間*/
    free(temp);

    return 0;
}
2011-07-21 14:20

[轉載][C語言] memcpy 複製指定長度的字串

轉載自:C Language -memcpy

#include <string.h>

void *memcpy (void *destination, const void *source, size_t num);

memcpy 提供的功能是烤貝記憶體中指定的資料長度製另外一個記憶位置中。

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv){
    char str[256];

    memcpy(str, "memcpy test", 7);

    printf("str = (%s)\n", str);
    // str = (memcpy )

    return 0;
}
2011-07-21 14:04

[轉載][C語言] memset 設定記憶體空間的值

轉載自:C Language -memset

#include <string.h>

void *memset(void *s, int c, size_t n);

memset 設定位元組中的位元值,設定的方式從s 開始將n 個位元組設定成為c 的位元值並回傳s,經常運用的範圍是在將位元組的位元值清為0。

#include <string.h>

int main(){
    /*將str陣列中所有的值設定為0*/
    char str[10+1]; 
    memset(str, 0x00, sizeof(str));
    return 0;
}
2011-07-21 13:23

[C語言] realpath 取得真實路徑

realpath 真是一個方便又好用函數,簡簡單單就可以取得一個路徑的絕對路徑,還可以檢查檔案是否存在。


#include <stdlib.h>

char *realpath(const char *path, char *resolved_pa​​th)

函數說明:realpath()用來將參數 path 所指的相對路徑轉換成絕對路徑後存於參數 resolved_pa​​th 所指的字符串數組或指針中。
返回值: 成功則返回指向 resolved_pa​​th 的指針,失敗返回 NULL,錯誤代碼存於 errno。

PS:當路徑檔案不存在時也會丟出 NULL,但 resolved_pa​​th 中仍會有化簡後的路徑。


#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv){
    if (argc != 2) {
        printf("Usage: %s <file>\n", argv[0]);
        return 1;
    }

    char path[1024];
    char *exist;

    exist=realpath(argv[1], path);

    /*經過化簡後的路徑*/
    puts(path);

    /*如果檔案不存在將會是 NULL*/
    if(exist==NULL){
        puts("NULL");
    }else{
        puts(exist);
    }

    return 0;
}
2011-07-20 18:51

HTML 標籤一覽

之前在做員工教育時整理的 HTML 標籤一覽,順便分享出來。

檔案連結:HTML 標籤一覽
2011-07-20 18:50

HTML meta 彙整

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!--網頁文件的編碼格式-->

<meta http-equiv="Content-Language" content="zh-TW" />
<!--網頁內容的語言-->

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<meta http-equiv="X-UA-Compatible" content="IE=9, IE=8, chrome=1" />
<!--指定 IE 頁面呈現所使用的渲染引擎-->

<meta http-equiv="X-Frame-Options" content="deny" />
<!--限制頁面中Frame的使用方式-->
<!--   sameorigin – 只允許來自同一個網域的頁面嵌入-->
<!--   deny – 防止任何頁面的嵌入-->

<meta http-equiv="Date" content="Wed, 16 Feb 2011 22:34:13 GMT" />
<!--網頁內容的建立日期-->

<meta http-equiv="Last-Modified" content="Mon, 03 Jan 2011 17:45:57 GMT" />
<!--網頁內容的修改日期-->

<meta http-equiv="Location" content="URL=http://www.w3schools.com" />
<!--宣告此網頁的絕對制式資源位址-->

<meta http-equiv="Set-Cookie" content="w3scookie=myContent;expires=Fri, 30 Dec 2011 12:00:00 GMT; path=http://www.w3schools.com" />
<!--設定cookie,如果網頁過期,存盤的cookie將被刪除,需要注意的也是必須使用GMT時間格式-->

<meta http-equiv="Windows-Target" content="_top" />
<!--強制頁面在目前的視窗中以獨立頁面顯示,可以防止網頁被別人當作一個frame頁嵌入-->

<meta http-equiv="Refresh" content="300" />
<meta http-equiv="Refresh" content="10;URL=http://www.w3schools.com" />
<!--定時讓網頁在指定的時間內重新整理,或是跳轉到指定頁面-->

<meta http-equiv="Expires" content="Mon,12 May 2001 00:20:00 GMT" />
<!--設定網頁內容暫存的到期時間-->

<meta http-equiv="Pragma" content="no-cache" />
<!--禁止瀏覽器從近端機的緩存中調閱頁面內容(僅 IE 適用)-->

<meta http-equiv="cache-control" content="no-cache" />
<!--瀏覽器的緩存控制-->
<!--   public - 可放在公用的緩存區-->
<!--   private - 只能放在私人的緩存區-->
<!--   no-cache - 不許存放在緩存區-->
<!--   no-store - 可以暫時存放緩存區,但是不許長存--> 




<meta name="KeyWords" lang="EN" content="key1,key2,key3" />
<meta name="KeyWords" lang="zh-TW" content="關鍵字1,關鍵字2,關鍵字3" />
<!--網頁內容的關鍵字-->

<meta name="Abstract" content="內容摘要" />
<!--網頁內容的摘要-->

<meta name="Description" content="內容描述" />
<!--網頁內容的描述-->

<meta name="Generator" content="Aptana 2" />
<!--製作網頁的工具名稱-->

<meta name="Author" content="作者名稱" />
<!--網頁製作者的名稱-->

<meta name="Reply-To" content="abc@mail.com" />
<!--聯繫人的 Email-->

<meta name="Website" content="http://www.website.com/" />
<!--網頁製作者的網站-->

<meta name="owner" content="http://www.website.com/" />
<!--定義所有者的網頁或網站-->

<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<!--viewport的作用是告訴瀏覽器,目前裝置有多寬(或多高),以便在縮放時有個基準-->
<!--   width - viewport的寬度(Number或 device-width)-->
<!--   height - viewport的高度(Number或 device-height)-->
<!--   initial-scale - 初始的縮放比例(0.25~5)-->
<!--   minimum-scale - 允許用戶縮放到的最小比例(0.25~5)-->
<!--   maximum-scale - 允許用戶縮放到的最大比例(0.25~5)-->
<!--   user-scalable - 用戶是否可以手動縮放(1/0或yes/no)-->

<meta name="Robots" content="noodp,noydir" />
<!--搜尋引擎檢索設定-->
<!--   all - 內容將被檢索,且頁面上的連結可以被查詢-->
<!--   none - 內容將不被檢索,且頁面上的連結不可以被查詢-->
<!--   index - 內容將被檢索-->
<!--   follow - 頁面上的連結可以被查詢-->
<!--   noindex - 內容將不被檢索,但頁面上的連結可以被查詢-->
<!--   nofollow - 內容將不被檢索,頁面上的連結可以被查詢-->

<meta name="Googlebot" content="nofollow" />
<!--針對 Google bot 的robots-->

<meta name="baiduspider" content="nofollow" />
<!--針對百度 bot 的robots-->

<meta name="classification" content="Computer" />
<!--告知搜索引擎網站(頁)應被列到哪個目錄下-->

<meta name="copyright" content="2011© W3Schools.com" />
<meta name="doc-rights" content="2011© W3Schools.com" />
<!--網頁的版權聲明-->

<meta name="Distribution" content="Taiwan" />
<!--描述網站(頁)的發佈地-->
<!--   web - 為全面互聯網-->
<!--   intranet - 只為內部網路-->
<!--   global - 全球性網頁-->
<!--   local - 本地端網頁-->
<!--   Intern use - 測試網頁-->

<meta name="doc-class" content="Completed" />
<!--指定文件的完成狀態-->
<!--   Completed - 已完成-->
<!--   Draft - 草稿-->
<!--   Living Document - 動態文件-->
<!--   Published - 發佈-->

<meta name="DownloadOptions" content="noopen" />
<!--控制下載對話匡上的按鈕顯示-->
<!--   noopen - 隱藏[開啟]的按鈕-->
<!--   nosave - 隱藏[儲存]的按鈕-->

<meta name="name" content="My document" />
<!--指定文件名稱-->

<meta name="rating" content="" />
<!--網頁內容分級-->
<!--   14 years - 14歲以上-->
<!--   general - 普通-->
<!--   mature - 成年人-->
<!--   restricted - 限制-->
<!--   safe for kids - 孩童-->

<meta name="resource-type" content="document" />
<!--告知這個網頁的形式是文件-->

<meta name="revisit-after" content="7 days">
<!--搜尋引擎檢索器多久之後來造訪一次-->

<meta name="其他" content="" />
<!--你可以定義自己 meta 名稱與描述-->




<!--[針對 IE 的設定]-->

<meta name="MSSmartTagsPreventParsing" content="yes"/>
<!--防止微軟頁面編輯軟體在頁面上自動添加標籤-->

<meta http-equiv="imagetoolbar"  content="no"/>
<!--關閉IE的圖片管理工具列-->

<meta http-equiv="MSThemeCompatible" content="no" />
<!--關閉XP的藍色立體按鈕系統顯示樣式-->

<meta http-equiv="Pics-label" content="">
<!--網頁等級升等職稱,在IE的internet選項中有一項內容設定,可以防止瀏覽一些受限制的網站,而網站的限制層級就是通過meta內容來設定的-->

<meta http-equiv="Page-Enter" content="revealTrans(duration=10,transtion=50)">
<meta http-equiv="Page-Exit" content="revealTrans(duration=20,transtion=6)">
<!--設定IE進入和離開頁面時的特殊效果-->
2011-07-11 17:43

為 Blogger 的地點標記加上 Google Maps 呈現

Blogger 增加了一個標記地點的功能,但只有標記也不知道能拿來做什麼,後來想想用JS寫了一個呈現的小程式,讓文章中設定的資訊可以直接呈現。

以下程式不支援 IE,因為我不想在我的 Blog 上用 Framework,所以 IE 就沒辦法呈現,哈!只要將以下其中一個的程式碼加在 </body> 之前就可以了。

在[文章]的最[前面]插入地圖
<script type="text/javascript">
function showGoogleMap(pos){
    var w=300,h=300,z=14;
try {
    var postOuter=document.getElementsByClassName(&#039;post-outer&#039;);
    for(var i=0; i&lt;postOuter.length; i++){
        var postLocation=postOuter[i].getElementsByClassName(&#039;post-location&#039;)[0];
        var point=postLocation.getElementsByTagName(&#039;a&#039;)[0];
        if(!point){continue;}
        var mapIframe=&#039;&lt;iframe width=&quot;&#039;+w+&#039;&quot; height=&quot;&#039;+h+&#039;&quot; src=&quot;&#039;+point.href+&#039;&amp;output=embed&amp;iwloc=z&amp;z=&#039;+z+&#039;&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&#039;;
        var postBody=postOuter[i].getElementsByClassName(&#039;post-body&#039;)[0];

        switch(pos){
            case &#039;loc-a&#039;:
                postLocation.innerHTML+=mapIframe;
                break;
            case &#039;loc-b&#039;:
                postLocation.innerHTML=mapIframe+postLocation.innerHTML;
                break;
            case &#039;post-a&#039;:
                postBody.innerHTML+=mapIframe;
                break;
            case &#039;post-b&#039;:
            default:
                postBody.innerHTML=mapIframe+postBody.innerHTML;
                break;
        }
    }
}catch(e){}
}
showGoogleMap(&#039;post-b&#039;);
</script>

在[文章]的最[後面]插入地圖
<script type="text/javascript">
function showGoogleMap(pos){
    var w=300,h=300,z=14;
try {
    var postOuter=document.getElementsByClassName(&#039;post-outer&#039;);
    for(var i=0; i&lt;postOuter.length; i++){
        var postLocation=postOuter[i].getElementsByClassName(&#039;post-location&#039;)[0];
        var point=postLocation.getElementsByTagName(&#039;a&#039;)[0];
        if(!point){continue;}
        var mapIframe=&#039;&lt;iframe width=&quot;&#039;+w+&#039;&quot; height=&quot;&#039;+h+&#039;&quot; src=&quot;&#039;+point.href+&#039;&amp;output=embed&amp;iwloc=z&amp;z=&#039;+z+&#039;&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&#039;;
        var postBody=postOuter[i].getElementsByClassName(&#039;post-body&#039;)[0];

        switch(pos){
            case &#039;loc-a&#039;:
                postLocation.innerHTML+=mapIframe;
                break;
            case &#039;loc-b&#039;:
                postLocation.innerHTML=mapIframe+postLocation.innerHTML;
                break;
            case &#039;post-a&#039;:
                postBody.innerHTML+=mapIframe;
                break;
            case &#039;post-b&#039;:
            default:
                postBody.innerHTML=mapIframe+postBody.innerHTML;
                break;
        }
    }
}catch(e){}
}
showGoogleMap(&#039;post-a&#039;);
</script>

在[地點]的[前面]插入地圖
<script type="text/javascript">
function showGoogleMap(pos){
    var w=300,h=300,z=14;
try {
    var postOuter=document.getElementsByClassName(&#039;post-outer&#039;);
    for(var i=0; i&lt;postOuter.length; i++){
        var postLocation=postOuter[i].getElementsByClassName(&#039;post-location&#039;)[0];
        var point=postLocation.getElementsByTagName(&#039;a&#039;)[0];
        if(!point){continue;}
        var mapIframe=&#039;&lt;iframe width=&quot;&#039;+w+&#039;&quot; height=&quot;&#039;+h+&#039;&quot; src=&quot;&#039;+point.href+&#039;&amp;output=embed&amp;iwloc=z&amp;z=&#039;+z+&#039;&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&#039;;
        var postBody=postOuter[i].getElementsByClassName(&#039;post-body&#039;)[0];

        switch(pos){
            case &#039;loc-a&#039;:
                postLocation.innerHTML+=mapIframe;
                break;
            case &#039;loc-b&#039;:
                postLocation.innerHTML=mapIframe+postLocation.innerHTML;
                break;
            case &#039;post-a&#039;:
                postBody.innerHTML+=mapIframe;
                break;
            case &#039;post-b&#039;:
            default:
                postBody.innerHTML=mapIframe+postBody.innerHTML;
                break;
        }
    }
}catch(e){}
}
showGoogleMap(&#039;loc-b&#039;);
</script>


實際呈現樣式:


2011-07-11 14:50

[轉載] Google Maps嵌入參數

為了製作 Blogger 上的地圖呈現,找到一篇詳細參數說明的翻譯,雖然可用的選項不多,但留著以後方便查。


轉載自:Google Maps嵌入参数
原文:http://mapki.com/wiki/Google_Map_Parameters


一般性的內容

q=
這是最常用的參數。

查詢- 所有被傳入這個參數的內容會被象maps.google.com中的查詢輸入框中所輸入的內容一樣被處理,特別是:

  • 要查找的精確地址,標記點或者在某個特殊點上顯示的信息框。
    • 提示:在附近不能有類似或者著名的地點的查詢值才是可靠的。例如,給出一個會議通知,告訴人們去128號門牌號碼的地點,但是只能在街區信息中發現一個12-8的位置(比如6/2010,誰會知道它以後會被匹配到什麼信息? )
  • 城鎮名字,或者前面的部分郵政編碼,會顯示到標記或者信息框裡。
  • 由緯度和經度信息指定的位置,用十進制形式,比如(52.123N,2.456W或52.123,-2.456),或者採用度/分/秒來表示(52 7 22.8N,2 27 21.6W或52 7 22.8,-2 27 21.6),或者度和分(52 7.38N,2 27.36W或52 7.38,-2 27.36)。
  • 在信息窗口和側邊欄中以粗體顯示的文本內容,增加括號()。你可以在不希望斷行的的時候使用%A0防止斷行發生。你還可以在行尾增加足夠多的%A0,並在後面跟一個空格(在URL中使用+號)來強制產生斷行。例子如原文指出:URL: http://maps.google.com?q=New+ York,+NY+(Mapki%A0is%A0a%A0very%A0good%A0Wiki%A0for%A0Google%A0Maps!%A0%A0%A0%A0%A0%A0%A0%A0+The%A0previous%A0line%A0is%A0now% A0sufficiently%A0long!)
  • to和from需要激活駕駛線路規劃功能。
  • 關鍵字near和loc:會激活本地搜索功能。
  • 兩個街之前可以用空格&空格形式,但是在URL裡需要使用+%26%或%20%26%20,而不是+&+或+&amp;+。
  • 需要指出的是+號,其實它與,號的作用相同。
  • 位置信息也可以由在@符號後的十進制形式來表達,如(@52.123,-2.456)。這個方式應該會自動給出一個較低的縮放比例。使用這種格式會影響到查詢的其它參數。 @符號,而不是near或者loc:可以形成單一的查詢結果。而其它的方式可能返回數以千計的結果。
  • q=10+Downing+Str+is+not+here@51.50335,-0.227721
    可以在指定的地址放置一個自定義的提示標記,比如q=唐寧街10號不在這裡@51.50335,-0.227721。  

    • 這個標籤不能是國家的名字,或者沒有顯示出標記的時候。但是當給出座標的情況下,它可以是空白的。
  • 座標之外增加()標籤可以為Google地圖提供一些提示。
    1. http://maps.google.com/maps?q=24.197611,120.780512
      我們的位置正好在某被錯誤標識的知名地點附近。讀者應該可以注意到正確的綠色箭頭。
    2. http://maps.google.com/maps?q=Dan@24.197611,120.780512
      Dan標籤可以擴展成為某機場的名字(Danville Regional Airport)
    3. http://maps.google.com/maps?q=24.197611,120.780512+ (Dan)
      這種情況會安全一些。但是顯示的是一個黃色的標記。
    4. http://maps.google.com/maps?q=loc:24.197611,120.780512這是一個精確的地點表示。
  • 要注意用%表述非ASCII字符,比如(和)還有+是安全的,但是空格必須以%20表示。注意它們可能被用戶的瀏覽器解釋錯誤。
  • sky:前綴用來查詢由Sky產生的KML內容。這個參數是被Google Sky使用,並產生KML輸出。
  • 包含GeoRSS數據的Google Earth .KML/.KMZ文件或者RSS輸出的完整URL,可以被Google Earth使用,裡麵包含的信息可以被顯示在地圖上。

near=
可以使用位置信息的一部分,而不是像q=參數那樣輸入全部信息。

g=
這是一個給q參數提供額外上下文信息的地址或位置。 Google Maps在這裡自己用來保存上一次運行的搜索。注:如果這是第一次運行,它將包含你所開始的位置信息。所以它有潛在的信息洩露的風險,你需要檢查你是否真的明白並且要分享這個參數所對應的信息。


Search Mode/查詢模式

  • mrt=指出查詢的類型(空白表示所有內容-缺省)
    • mrt=all值為all指出查詢所有內容。
    • mrt=loc值為loc指出是進行位置信息查詢,它需要q=參數。
    • mrt=yp值為yp指出是商業查詢(即:黃頁),它也需要q=信息,一般情況下是位置信息。
    • mrt=websearch值為websearh指出映射的web頁面。這些網頁通過GoogleBot能夠指出地理位置信息。
    • mrt=realestate值為realstate為固定資產查詢。
    • mrt=ds值為ds時為相關的地圖。 Google的GeoRSS源索引(可能是KML?)
  • start=start=參數會跳過前(start-1)個匹配結果。
  • num=num=參數顯示,最多這個數量的匹配結果。合法的範圍是0到20(但是0有點沒有用處)。

Location/位置信息

  • ll= 顯示地圖時中心點的緯度、經度信息。要注意次序。而只接受十進制數值格式才可以。
    如果使用了這個參數但是沒有使用查詢,那麼地圖就以這個點為中心點顯示,但是沒有標記或信息窗口顯示。
  • sll=
    商業查詢執行時指定的點的緯度和經度。你可以使用它來執行一個偏離中心的商業搜索。 Google使用它,所以在執行完一個商業查詢後,中心移動後可以使用“鏈接到此頁”來記錄地圖位置。使用<math>map.getBounds().getSouthWest().toUrlValue()</math>將返回與maps.google.com相同的結果。
  • spn=spn=大致的經緯區域。如果沒有指縮放參數z=,那麼將調整縮放水平到一個合理的數值。
  • sspn=
    屏幕區域,計算方法:
    <math>new GLatL​​ng(map.getBounds().getNorthEast().lat() – map.getBounds().getSouthWest().lat(), map.getBounds().getNorthEast().lng() – map .getBounds().getSouthWest().lng()).toUrlValue()</math>
  • latlng=這是一個奇怪的參數。它有3個由,號分隔的數字。前兩個數字(大概相當於緯度和經度的100000倍)被忽略。第三個數字似乎是Google內部用來處理特殊業務的企業ID。比如latlng=0,0,14944637421527611642代表Blackpool社區教堂。指定此參數會執行一個針對該業務面頁的Google搜索,並顯示一個小地圖。其它參數,特別是q=參數,必須是有效的內容(但不一定涉到目標業務)。
  • cid= Similar to latitude and longitude, but generating a different map size.
    這個值似應該是地點的編號。原文的表述與latlang重複。
  • geocode=
    geocode值似乎是在線路規劃時各關鍵點的編碼。每個geocode之間使用%3B來分隔。
  • radius=在指定半徑內採用本地化信息。需要sll參數指定信息或者類似中心點位置才能使用。單位會採用英里,但是在公制國家可能會採用公里。這個參數有助預防Google結果遠離了結果城市,並讓它被限制在指定區域。

Map Display/地圖顯示

  • t=地圖類型。 m=>常規地圖,k=>衛星地圖,h=>混合地圖,p=>地域地圖,e=>GoogleEarth
  • z=縮放級別,取值範圍1~20。1比例尺最大,20比例尺最小。
  • layer=激活圖層。目前t表示交通情況。
  • lci=激活可以層疊的圖層。用,號分隔。
    • com.panoramio.all 來自Panoromio的圖片
    • com.youtube.all來自YouTube的視頻
    • org.wikipedia.en維基百科(英文)
    • com.google.ugc.c752d13e87c4fbd7來自Webcams.travel的網絡攝像頭。
    • transit公共交通
    • bike自行車線路
  • view=這個參數在測試的時候沒有看出分別。

Directions/路徑規劃

  • saddr= 出發點地址。
  • daddr=目標地址。
    “+to:” 可以使用+to:子句增加多地點線路規劃時的目標地址信息,比如daddr=大石洞村+to:馬欄廣場+to:棠梨溝
  • mra ?? 此參數涵義未知,可能的取值:dm/dpe/cc/ls…
  • mrcr ??此參數涵義未知,可能的取值:0
  • mrsp解析座標到街名。
    • mrsp=0打開從座標解析街名
    • mrsp=1關閉從座標解析街名
  • mrad= 附加目標地址。如果你的行程有三個地點,你可以用saddr=,daddr=和mrad=表示,而不採用+to:子句。
  • dirflg 路線類型。
    • dirflg=h避免高速公路。
    • dirflg=t避免收費路段。
    • dirflg=r採用公共交通。僅在一些區域可用。還可以提出附加的時間信息。
    • dirflg=w步行方式。仍在測試狀態。
    • dirflg=b騎行方式。僅在某些區域可用,仍在測試狀態。
  • via=用,號分隔的經由地址。
  • doflg=距離單位。缺省的是國家的法定標準。
    • doflg=ks ??這個真不知道。
    • doflg=ptk輸出距離單位顯示為公里。
    • doflg=ptm輸出距離單位顯示為英里。
  • ttype= 時間類型。在dirflg=r的狀況下採用公共交通工具的時候date和time參數的解析類型。  
    • ttype=now現在就出發,這個會忽略date和time參數。
    • ttype=dep 出發時間。
    • ttype=arr 到達時間。
  • date= 出發/到達日期,格式mm/dd/[yy]yy。由ttype決定是哪個日期。
  • time= 出發/到達時間,格式hh:mm am|pm。由ttype決定是哪個時間。
  • sort= 公共交通線路的排序 
    • sort=def缺省的排序方式。最快的行程優先。
    • sort=num最少的換乘優先。
    • sort=walk最少的步行優先。
  • start=與搜索模式很像,選擇第n個結果。

Street View/街景

  • cbll= Latitude,longitude for Street View.街景的經緯度信息。
  • cbp= Street View window that accepts 5 parameters街景窗口可以接受5個參數:
    1. 街景/地圖安排,11=上半部街景,下半部地圖,12=大部分是街景顯示,角部為可以調整角度的地圖
    2. 移軸角度,範圍是-90到90度。
    3. 縮放範圍,0~2
    4. 斜度(採用度數表示),-90~90,缺省值是5
  • panoid=這裡的ID是附近的全景對象的ID。全景對象採用可以點擊的小箭頭,你可以移動到下一個對象。

Output Control/輸出控制

  • hl=主機語言。僅支持一部分語言,如hl=fr表示法語
  • om=這個參數指定下方縮略圖是否顯示。如果指定一個1以外的值,縮略圖會關閉。 (經過測試1,2會顯示)。如果參數會被省略或者指定了值1,則顯示。
  • ie=指定輸入的字符編碼,比如ie=UTF8。
  • oe=指定輸出的字符編碼,比如oe=UTF8。
  • output=指定輸出格式,空白(缺省值)是標準的網頁格式。  
    • output=html在整合到Google地圖前使用舊風格的Google本地頁面格式,顯示小地圖和大的邊欄風格。
    • output=js輸出Google地圖使用的JavaScript對象和函數調用,包括駕駛線路的多邊形編碼和HTML格式的場景信息。
    • output=kml輸出包含當前地圖信息的KML文件。
    • output=mobile針對移動設備的格式輸出。在地圖中央位置顯示一個簡單的紅色圖釘。所有的移動基於鏈接而不是鼠標的移動。
    • output=nl輸出Google Earth和Google Maps可以獲取NetworkLink信息的KML文件內容。
    • output=embed輸出可以嵌入到第三方網站的HTML內容。這個參數僅與加密的s=參數一塊工作,據推測可能是阻止顯示不可預知的內容。
    • output=dragdir返回JSON對象。此對象包括反向的地理位置編碼和針對給定saddr(線路開始點)和daddr(線路結束點)線路的多邊形編碼。
    • output=georss 針對當前地圖(可能僅適用於MyMaps)的GeoRSS輸出。
  • f=控制查詢表單的顯示風格。  
    • f=d顯示成路徑規劃表單(有兩個輸入框,始點、終點)
    • f=l此參數似乎沒有作用了。
    • f=q缺省的顯示方式,單一輸入框。
  • pw=激活打印模式,初始化打印。與原文不同,pw=1/2兩個值均可以。測試環境是Ubuntu 11.04+Google Chrome。
  • v= 如果指定了output=kml,則此參數指定kml的版本。缺省是2.0,如果想指定是2.2,則v=2.2。

提示信息窗口

信息顯示窗口就是漫畫書中的對話氣球框。


我的地圖

  • msa=參數目前應該沒有意義了。

雜項

  • vp= 這個參數會使Google地圖切換到版權服務模式。它以JavaScript格式返回所有者的版權信息而不是返回可以畫出地圖的html內容。 vp參數指出視圖位置(即地圖的中心位置)。版權服務僅在提供了spn=z=參數的情況下才可以工作。它們分別代表區域和縮放比例。一還有一些可選的參數,比如t=,它用來指出地圖的類型,key=用來指出站點用來執行查詢時所用到的API key。例如:http://maps.google.com/maps?spn=0.030372,0.068665&z=6&t=h& vp=53.859462,-3.038235
  • ftr=0 這個參數是用來關掉所有Google地圖實驗室特性的。當你遇到這些特性出現問題或者無法載入地圖,這個特性可能提供有用的途徑。使用這個參數之後,你需重新激活那些實驗室特性。比如訪問:http://maps.google.com/maps?ftr=0。這個鏈接會提示你關掉了哪些特性,並且會提示是否保存這種改變。
  • source= 未知。一個值是s_d,另一個是s_q。
  • noexp= 未知。其中一個值是0。
  • noal= 未知。其中一個可取值是0。
  • oi=nojs 在它合併到Google地圖之前使用舊風格的Google本地頁面格式,使用小地圖和大的邊條,就像前面指定output=html選項那樣。這個選項需要停止JavaScript的工作。
2011-07-11 14:49

[轉載] 屬性(Attribute)與特性(Property)

之前看到jQuery 1.6.1上場救援,不用改寫attr()囉這篇文章時,讓我很疑惑 Attribute 與 Property 到底是有什麼不同,在字典上查出來的結果都是屬性,爬了一些文章後找到一篇不錯的解釋文。


轉載自:屬性與特性

在進入瀏覽器作為客戶端之後,屬性(Attribute)與特性(Property)這兩個名詞就不斷交相出現,到目前還沒正式解釋它們的意義。

其實在正式進入瀏覽器作為客戶端前,對於JavaScript物件本身帶有的名稱,這邊的文件都用特性這個名詞,代表以某個JavaScript物件作為名稱空間的名稱。例如:
var obj = {
    x : 10,
    y : 20
};

以上文件都稱,物件obj擁有特性x與y,特性x的值為10,特性y的值為20。

HTML本身可以擁有屬性。例如:
<input name="user" value="guest">

文件中會稱,<input>標籤擁有屬性name與value,屬性值各為user與guest。

瀏覽器會剖析HTML,為每個標籤建立對應的DOM物件,完成剖析後,對於HTML的所有屬性(無論標籤上是否有撰寫),DOM物件上會建立對應的特性,通常屬性名稱是什麼,特性名稱也會是什麼,如果標籤上有設定某個屬性,則屬性值為何,特性值也就為何,如果標籤上沒有設置屬性,則DOM物件上的特性會有預設值

例如上例中,<input>對應的DOM元素上,name特性與value特性值分別是user與guest。你可以如下分別取得(假設是頁面中第一個<input>標籤):
var input = document.getElementsByName('user')[0];
var name = input.name;
var value = input.value;

像這時,DOM元素上的name、value特性,也可以稱之為name與value屬性。也就是說,屬性這個詞,可用來表示HTML中的屬性,也可用來表示DOM中相對應的特性。對於HTML中沒有設定的標籤屬性,DOM上也會有對應的特性(屬性),不過都是預設值,例如,上面的<input>標籤並沒有設置type屬性,但DOM物件上對應的特性(屬性),其值為"text"。

不過,HTML的屬性名稱未必與DOM物件的特性(屬性)名稱相對應。例如class就是一個例子,因為class在JavaScript中是關鍵字,在DOM上要取得HTML的class屬性對應名稱必須使用className,<label>的for屬性,因為for是關鍵字,而必須使用htmlFor特性來取得。例如:
<img id="logo" src="images/caterpillar.jpg" class="logo" title="Caterpillar's Logo"/>


若要以JavaScript取得HTML的class屬性值,則必須:
var className = document.getElementById('logo').className;

透過JavaScript特性存取方式取得HTML屬性的對應值,也未必是HTML屬性中真正設定的值。例如,透過JavaScript取得<img>的src,結果是絕對URL,即使屬性中設定的是相對URL。

瀏覽器在剖析完HTML後,對於HTML中有設置的屬性,其實會在DOM物件上建立attributes特性。你可以如下顯示attributes的元素值,每個元素的型態是Attr
var attributes = document.getElementById('logo').attributes;
for(var i = 0; i < attributes.length; i++) {
    var attrName = attributes[i].nodeName;
    var attrValue = attributes[i].nodeValue;
    ...
}

以物件結構來表示的話:
{
    attributes : {
        '0' : {nodeName : 'id', nodeValue : 'logo', ...},
        '1' : {nodeName : 'src', nodeValue : 'images/src', ...},
        '2' : {nodeName : 'class', nodeValue : 'logo', ...},
        '3' : {nodeName : 'title', nodeValue : 'Caterpillar\’s logo', ...},
        length : 4
        ...
    },
    id : 'logo',
    src : 'http://caterpillar.onlyfun.net/images/caterpillar.jpg',
    className : 'logo',
    title : 'Caterpillar\'s logo',
    …
}

attributes上的特性值,是HTML上真正設定的屬性與值。在文件剖析完畢後,DOM物件上的屬性(特性)與attributes上的特性是對應的。

注意,上面是以物件結構來示意,並不是指真正的型態就是上面所表示的。attributes的型態會是 NamedNodeMap ,而每個索引元素的型態會是 Attr(如果你手邊有個JavaScript Debugger的話,可以很方便地觀察這些東西)。

你可以使用DOM物件的getAttribute()來取得attributes中的屬性,使用setAttribute()設定attributes中的屬性(同時亦會改變DOM對應的特性),使用removeAttribute()來移除attributes屬性。

移除屬性是指移除attributes上對應的特性值,而非移除DOM物件上對應的特性(屬性)值,DOM物件上對應的特性(屬性)值在使用removeAttribute()後,只是回到預設值,而不是直接將特性移除,沒有任何操作可以將DOM上對應屬性的特性移除。如果HTML上沒有設置該屬性,則使用getAttribute()指定該屬性會取得null,但並不表示DOM上沒有對應屬性的特性,而是該特性值會是預設值。使用setAttribute()可以在attributes中設定屬性,相對應的DOM特性值也會改變。

例如,以下的程式,只會將attributes的中src對應的特性移除,不會移除DOM上src特性(屬性),DOM上src只是回到''的預設值。
var img = document.getElementById('logo');
img.removeAttribute('src');
// img.src 的值是 '',不是undefined
// img.attributes['src'] 是 undefined

如果你直接改變DOM上的特性(屬性),attributes中對應的屬性並不會有變化。例如:
<input id="user" value="guest">

使用以上的程式:
document.getElementById('user').value = 'Justin';
var user1 = document.getElementById('user').value; // 值是'Justin'
var user2 = document.getElementById('user').getAttribute('value'); // 值是'guest'

如果你要同時改變attribues上的屬性與DOM上的特性(屬性),則要使用setAttribute()。例如:
document.getElementById('user').setAttribute('value', 'Justin');
var user1 = document.getElementById('user').value; // 值'Justin'
var user2 = document.getElementById('user').getAttribute('value'); // 值'Justin'


其他參考資訊:
property和attribute的区别
JavaScript property 、 DOM property 、 HTML attribute
翻譯名詞:attribute、property
2011-07-05 15:02

關閉 Firefox 外掛套件的版本檢查

最近 Firefox 升級的速度實在太頻繁了,導致很多外掛套件不能用了,再加上外掛套件不可能一致的推出新版,所以最快的方式就是暫時關閉外掛套件的版本檢查。
  1. 在網址列輸入 about:config 進入進階設定中
  2. 新增 Boolean 值 extensions.checkCompatibility.5.0false
    PS: 5.0 為你當前 Firefox 的版本,請以你目前的版本更換參數名稱。
  3. 重啟 Firefox

參考來源:[每週技巧]使firefox可安裝與使用不相容add-on的方法
2011-07-04 16:54

創:光速戰記 (Tron Legacy) console 上的指令

$ whoami
flynn

$ uname -a
SolarOS 4.0.1 Generic_50203-02 sun4m i386
Unknown.Unknown

$ login -n root
Login incorrect
login:backdoor
No home directory specifed in password file!
Logging in with home=/

#bin/history
  488  cd /opt/LLL/controller/laser/
  489  vi LLLSDLaserControl.c
  490  make
  491  make install
  492  ./sanity_check
  493  ./configure -o test.cfg
  494  vi test.cfg
  495  vi ~/last_will_and_testament.txt
  496  cat /proc/meminfo
  497  ps -a -x -u
  498  kill -9 2207
  499  kill 2208
  500  ps -a -x -u
  501  touch /opt/LLL/run/ok
  502  LLLSDLaserControl -ok 1

#
2011-05-23 17:07

CSS Selector 優先權計算表

資料來源:小繁的blog