2019年9月25日 星期三

php get_headers 判斷URL是否有效


在php中判斷一個文件或目錄是否存在,大家通常都會想到is_file和file_exists兩個函數。但這兩個函數再判斷一個遠程url文件是否存在的問題上還是會存在這樣那樣的問題。這裡作者將和大家分享一種利用php get_headers函數來判斷遠程url文件是有效否存在的辦法。

關於php get_headers函數的作用及用法,可以參考本站文章:

php get_headers函數的作用及用法

下面來具體說如何利用php get_headers卻判斷url的真實有效性。

通過該函數的介紹,我們可以知道對於這個函數簡單的說就是它返回的是一個HTTP請求的頭文件信息,信息格式基本如下:

(1)

Array
(
    [0] => HTTP/1.1 200 OK
    [1] => Date: Sat, 29 May 2004 12:28:13 GMT
    [2] => Server: Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [3] => Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
    [4] => ETag: "3f80f-1b6-3e1cb03b"
    [5] => Accept-Ranges: bytes
    [6] => Content-Length: 438
    [7] => Connection: close
    [8] => Content-Type: text/html
)

(2)

Array
(
    [0] => HTTP/1.0 404 Not Found
    [1] => Date: Sat, 29 May 2004 12:28:13 GMT
    [2] => Server: Apache/1.3.27 (Unix)  (Red-Hat/Linux)
    [3] => Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
    [4] => ETag: "3f80f-1b6-3e1cb03b"
    [5] => Accept-Ranges: bytes
    [6] => Content-Length: 438
    [7] => Connection: close
    [8] => Content-Type: text/html
)

從以上兩種情況可以很容易看出,如果判斷該url是否有效存在肯定是通過數組中的第一個元素值來判斷的。服務器返回 200 即文件正確返回的意思,服務器返回 404 即文件不存在,因此從這個地方就可以很容易的判斷一個url的是否存在了

2019年5月21日 星期二

合乎規格的標籤

/<!([\s\S]{0,}?)>|<([a-z][\s\S]{0,}?)(?:\s[\s\S]{0,}?|)([\/]?)>|<\/([a-z][\s\S]{0,}?)>/g

2019年3月14日 星期四

堆疊樹

// 堆疊樹(由下往上)

// (1~n) m 的子節點為 2m, 2m+1
// 階層從 1階 開始
// 每階最多 (2(level-1)次方) 個節點
let data = [26, 5, 19, 1, 61, 11, 59, 15, 48, 77];

// 最後一個有子節點的節點
let lastParentIndex = Math.floor(data.length / 2) - 1;

console.log(JSON.stringify(data));
// 往前拜訪每個有孩子的節點
for (let i = lastParentIndex; i >= 0; i--) {
    debugger;
    check(i, data);
}
console.log(JSON.stringify(data));

//----------------------------
// 檢查父節點與子節點的大小
function check(parent_index, _data) {
    debugger;

    // 會不斷往下有子節點的節點探索
    while (parent_index <= lastParentIndex) {

        let leftIndex = (parent_index + 1) * 2 - 1;
        let rightIndex = leftIndex + 1;

        // 可能沒有 right 子節點
        rightIndex = (rightIndex >= _data.length) ? null : rightIndex;

        // console.log('%d = %d',  _data[leftIndex], _data[rightIndex]);

        let maxIndex = (rightIndex == null || (_data[leftIndex] > _data[rightIndex])) ? leftIndex : rightIndex;

        if (_data[parent_index] < _data[maxIndex]) {
            // 交換
            let temp = _data[maxIndex];
            _data[maxIndex] = _data[parent_index];
            _data[parent_index] = temp;
        }

        // 往下層比較
        // 確定變動的節點要比他的子節點大
        parent_index = maxIndex;
    }
}
------------------------------------------------------------------------
// 堆疊樹(由上往下)

// (1~n) m 的子節點為 2m, 2m+1
// 階層從 1階 開始
// 每階最多 (2(level-1)次方) 個節點
let data = [26, 5, 19, 1, 61, 11, 59, 15, 48, 77];

console.log(JSON.stringify(data));
// 往前拜訪每個有孩子的節點
for (let i = 0; i < data.length; i++) {
    debugger;
    check(i, data);
}
console.log(JSON.stringify(data));

//----------------------------
// 檢查父節點與子節點的大小
function check(parent_index, _data) {
    debugger;

    let prev_index;

    // 會不斷往下有子節點的節點探索
    while (parent_index >= 0) {


        if (prev_index != null) {
            // 回朔 只需比對上一個子節點
            if (_data[parent_index] < _data[prev_index]) {
                // 交換
                let temp = _data[prev_index];
                _data[prev_index] = _data[parent_index];
                _data[parent_index] = temp;
            }

        } else {
            // 第一次進入

            let leftIndex = (parent_index + 1) * 2 - 1;
            let rightIndex = leftIndex + 1;

            leftIndex = (leftIndex >= _data.length) ? null : leftIndex;
            rightIndex = (rightIndex >= _data.length) ? null : rightIndex;


            if (leftIndex == null && rightIndex == null) {
                // 都沒有子節點
                return;
            }

            console.log('%d(%d,%d)', _data[parent_index], _data[leftIndex], _data[rightIndex]);

            let maxIndex = (rightIndex == null || (_data[leftIndex] > _data[rightIndex])) ? leftIndex : rightIndex;

            if (_data[parent_index] < _data[maxIndex]) {
                // 交換
                let temp = _data[maxIndex];
                _data[maxIndex] = _data[parent_index];
                _data[parent_index] = temp;
            }
        }
        //-----------------------
        prev_index = parent_index;
        // 往下層比較
        // 確定變動的節點要比他的子節點大
        let nextCheckIndex = Math.floor((parent_index + 1) / 2) - 1;

        if (nextCheckIndex == parent_index && parent_index == 0) {
            // 只為了解決無限迴圈
            return;
        }

        // 往上
        parent_index = nextCheckIndex;
    }
}

2019年3月13日 星期三

DoublyLinkedList

module.exports = DoublyLinkedList;


// 雙向連結
function DoublyLinkedList() {

    let head;
    let tail;
    let length;

    this._head = function (node) {
        if (node == null) {
            return head;
        } else {
            head = node;
        }
    };

    this._tail = function (node) {
        if (node == null) {
            return tail;
        } else {
            tail = node;
        }
    };

    this._length = function (_length) {
        if (_length == null) {
            return length;
        } else {
            length = _length;
        }
    };

}

(function () {
    this.append = function (el) {
        debugger;

        let node = new Node(el);

        if (this._head() == null) {
            this._head(node);

            this._length(1);
            this._tail(node);

        } else {
            let prev_node = this._head();
            let count = 0;

            while (prev_node.next != null) {
                prev_node = prev_node.next;
                count++;
            }

            prev_node.next = node;
            node.prev = prev_node;

            this._length(++count);
            this._tail(prev_node);
        }

    };

    this.insert = function (position, el) {

    };

    this.remove = function (el) {

    };

    this.removeAt = function (position) {

    };

    this.indexOf = function (position) {

    };

    this.size = function () {
        return this._length();
    };

    this.toJSON = function () {
        debugger;
        let res = [];
        let node = this._head();

        do {
            if (node == null) {
                break;
            } else {
                res.push(JSON.stringify(node.element));
            }
        } while ((node = node.next) != null);

        return res.join(',');
    };

}).call(DoublyLinkedList.prototype);


//==============================================================================

function Node(el) {
    this.element = el;
    this.prev = null;
    this.next = null;
}

2019年3月12日 星期二

javascript array.sort()

如果 compareFunction 沒有被應用,元素將被轉換為字串並以 Unicode 編碼位置進行比較來排序。舉例來說,"Banana" 會被排在 "cherry" 之前。在數值排序中,9 排在 80 前面,但因為數字被轉換成字串,在 Unicode 順序中 "80" 會在 "9" 的前面。
如果 compareFunction 被應用,陣列元素們將根據比較函式之回傳值來排序。如果 ab 為被比較之兩元素,則:
  • compareFunction(a, b) 的回傳值小於 0,則會把 a 排在小於 b 之索引的位置,即 a 排在 b 前面。
  • compareFunction(a, b) 回傳 0,則 ab 皆不會改變彼此的順序,但會與其他全部的元素比較來排序。備註:ECMAscript 標準並不保證這個行為,因此不是所有瀏覽器(如 Mozilla 版本在 2003 以前)都遵守此行為。
  • compareFunction(a, b) 的回傳值大於 0,則會把 b 排在小於 a 之索引的位置,即 b 排在 a 前面。
  • compareFunction(a, b) 在給予一組特定元素 a 及 b 為此函數之兩引數時必須總是回傳相同的值。若回傳值不一致,排序順序則為 undefined。



sort(a, b) 預設是從小排到大

 compareFunction(a, b) > 0 認為 (a - b > 0) 所以 a 與 b 交換

2019年3月8日 星期五

一個 promise 再包裝的例子



'use strict';

/**
 * Promise
 *
 * Inspired by https://gist.github.com/RubaXa/8501359 from RubaXa <trash@rubaxa.org>
 *
 * @param {Function} handler   Called as handler(resolve: Function, reject: Function)
 * @param {Promise} [parent]   Parent promise for propagation of cancel and timeout
 */
function Promise(handler, parent) {
    var me = this;

    if (!(this instanceof Promise)) {
        throw new SyntaxError('Constructor must be called with the new operator');
    }

    if (typeof handler !== 'function') {
        throw new SyntaxError('Function parameter handler(resolve, reject) missing');
    }

    var _onSuccess = [];
    var _onFail = [];

    // status
    this.resolved = false;
    this.rejected = false;
    this.pending = true;

    /**
     * Process onSuccess and onFail callbacks: add them to the queue.
     * Once the promise is resolve, the function _promise is replace.
     * @param {Function} onSuccess
     * @param {Function} onFail
     * @private
     */
    var _process = function (onSuccess, onFail) {
        _onSuccess.push(onSuccess);
        _onFail.push(onFail);
    };

    /**
     * Add an onSuccess callback and optionally an onFail callback to the Promise
     * @param {Function} onSuccess
     * @param {Function} [onFail]
     * @returns {Promise} promise
     */
    this.then = function (onSuccess, onFail) {
        return new Promise(function (resolve, reject) {
            var s = onSuccess ? _then(onSuccess, resolve, reject) : resolve;
            var f = onFail ? _then(onFail, resolve, reject) : reject;

            _process(s, f);
        }, me);
    };

    /**
     * Resolve the promise
     * @param {*} result
     * @type {Function}
     */
    var _resolve = function (result) {
        // update status
        me.resolved = true;
        me.rejected = false;
        me.pending = false;

        _onSuccess.forEach(function (fn) {
            fn(result);
        });

        _process = function (onSuccess, onFail) {
            onSuccess(result);
        };

        _resolve = _reject = function () { };

        return me;
    };

    /**
     * Reject the promise
     * @param {Error} error
     * @type {Function}
     */
    var _reject = function (error) {
        // update status
        me.resolved = false;
        me.rejected = true;
        me.pending = false;

        _onFail.forEach(function (fn) {
            fn(error);
        });

        _process = function (onSuccess, onFail) {
            onFail(error);
        };

        _resolve = _reject = function () { }

        return me;
    };

    /**
     * Cancel te promise. This will reject the promise with a CancellationError
     * @returns {Promise} self
     */
    this.cancel = function () {
        if (parent) {
            parent.cancel();
        } else {
            _reject(new CancellationError());
        }
        return me;
    };

    /**
     * Set a timeout for the promise. If the promise is not resolved within
     * the time, the promise will be cancelled and a TimeoutError is thrown.
     * If the promise is resolved in time, the timeout is removed.
     * @param {number} delay     Delay in milliseconds
     * @returns {Promise} self
     */
    this.timeout = function (delay) {
        if (parent) {
            parent.timeout(delay);
        } else {
            var timer = setTimeout(function () {
                _reject(new TimeoutError('Promise timed out after ' + delay + ' ms'));
            }, delay);

            me.always(function () {
                clearTimeout(timer);
            });
        }
        return me;
    };

    // attach handler passing the resolve and reject functions
    handler(function (result) {
        _resolve(result);
    }, function (error) {
        _reject(error);
    });
}

/**
 * Execute given callback, then call resolve/reject based on the returned result
 * @param {Function} callback
 * @param {Function} resolve
 * @param {Function} reject
 * @returns {Function}
 * @private
 */
function _then(callback, resolve, reject) {
    return function (result) {
        try {
            var res = callback(result);
            if (res && typeof res.then === 'function' && typeof res['catch'] === 'function') {
                // method returned a promise
                res.then(resolve, reject);
            } else {
                resolve(res);
            }
        } catch (error) {
            reject(error);
        }
    }
}

/**
 * Add an onFail callback to the Promise
 * @param {Function} onFail
 * @returns {Promise} promise
 */
Promise.prototype['catch'] = function (onFail) {
    return this.then(null, onFail);
};

// TODO: add support for Promise.catch(Error, callback)
// TODO: add support for Promise.catch(Error, Error, callback)

/**
 * Execute given callback when the promise either resolves or rejects.
 * @param {Function} fn
 * @returns {Promise} promise
 */
Promise.prototype.always = function (fn) {
    return this.then(fn, fn);
};

/**
 * Create a promise which resolves when all provided promises are resolved,
 * and fails when any of the promises resolves.
 * @param {Promise[]} promises
 * @returns {Promise} promise
 */
Promise.all = function (promises) {
    return new Promise(function (resolve, reject) {
        var remaining = promises.length,
                results = [];

        if (remaining) {
            promises.forEach(function (p, i) {
                p.then(function (result) {
                    results[i] = result;
                    remaining--;
                    if (remaining == 0) {
                        resolve(results);
                    }
                }, function (error) {
                    remaining = 0;
                    reject(error);
                });
            });
        } else {
            resolve(results);
        }
    });
};

/**
 * Create a promise resolver
 * @returns {{promise: Promise, resolve: Function, reject: Function}} resolver
 */
Promise.defer = function () {
    var resolver = {};

    resolver.promise = new Promise(function (resolve, reject) {
        resolver.resolve = resolve;
        resolver.reject = reject;
    });

    return resolver;
};

/**
 * Create a cancellation error
 * @param {String} [message]
 * @extends Error
 */
function CancellationError(message) {
    this.message = message || 'promise cancelled';
    this.stack = (new Error()).stack;
}

CancellationError.prototype = new Error();
CancellationError.prototype.constructor = Error;
CancellationError.prototype.name = 'CancellationError';

Promise.CancellationError = CancellationError;


/**
 * Create a timeout error
 * @param {String} [message]
 * @extends Error
 */
function TimeoutError(message) {
    this.message = message || 'timeout exceeded';
    this.stack = (new Error()).stack;
}

TimeoutError.prototype = new Error();
TimeoutError.prototype.constructor = Error;
TimeoutError.prototype.name = 'TimeoutError';

Promise.TimeoutError = TimeoutError;


module.exports = Promise;

2019年3月7日 星期四

worker 環境判定

if(typeof Window !== 'undefined'){
    // browser
}else if(typeof WorkerGlobalScope !== 'undefined'){
    // browser worker
   
}else if(typeof module !== 'undefined'){
    // node.js
    const {isMainThread} = require('worker_threads');
       
    if(isMainThread){
        // MainThread
    }else{
        // worker
    }
}

2019年3月5日 星期二

所有的html標籤

所有的html標籤

不同系統的換行符號

str.replace(/(\r\n|\n)/, '')


|一、概念:

換行符‘\n’和回車符‘\r’

(1)換行符就是另起一行  — ‘\n‘ 10 換行(newline)

(2)回車符就是回到一行的開頭 — ‘\r‘ 13 回車(return)

所以我們平時編寫檔案的回車符應該確切來說叫做回車換行符 

CR: 回車(Carriage Return) \r
LF: 換行(Line Feed) \n

二、應用:
(1)在微軟的MS-DOS和Windows中,使用“回車CR(‘\r’)”和“換行LF(‘\n’)”兩個字元作為換行符;
(2)Windows系統裡面,每行結尾是 回車 換行(CR LF),即“\r\n”;
(3)Unix系統裡,每行結尾只有 換行LF,即“\n”;
(4)Mac系統裡,每行結尾是 回車CR 即’\r’。
Mac OS 9 以及之前的系統的換行符是 CR,從 Mac OS X (後來改名為“OS X”)開始的換行符是 LF即‘\n’,和Unix/Linux統一了。
三、影響:
(1)一個直接後果是,Unix/Mac系統下的檔案在Windows裡開啟的話,所有文字會變成一行;
(2)而Windows裡的檔案在Unix/Mac下開啟的話,在每行的結尾可能會多出一個^M符號。
(3)Linux儲存的檔案在windows上用記事本看的話會出現黑點。
四、可以相互轉換:
在linux下,命令unix2dos 是把linux檔案格式轉換成windows檔案格式,命令dos2unix 是把windows格式轉換成linux檔案格式。
在不同平臺間使用FTP軟體傳送檔案時, 在ascii文字模式傳輸模式下, 一些FTP客戶端程式會自動對換行格式進行轉換. 經過這種傳輸的檔案位元組數可能會發生變化.
 如果你不想ftp修改原檔案, 可以使用bin模式(二進位制模式)傳輸文字。
一個程式在windows上執行就生成CR/LF換行格式的文字檔案,而在Linux上執行就生成LF格式換行的文字檔案。

2019年2月26日 星期二

拖曳一個小方塊.......不錯用

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="./js_lib/jquery-3.3.1.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }

        body {
            position: relative;
        }

        div.container_1 {
            height: 1000px;
            background-color: #ffc;
            position: relative;
        }

        #moveEvent {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            border: 1px dashed;
            z-index: 99999;
            display: none;
            user-select: none;
            opacity: 0;
        }

        #box_1 {
            width: 100px;
            height: 100px;
            position: absolute;
            top: 50px;
            left: 100px;
            z-index: 100;
            background-color: #00F;
            user-select: none;
        }
    </style>
</head>

<body>
    <div id="moveEvent">
        <!-- 全螢幕的畫布 -->
    </div>
    <div class="container_1">
        <p id="box_1">
            box
        </p>
    </div>
    <script>

        // screen 與 #box_1 的座標差
        let topOffset;
        let leftOffset;
        let callback;


        $('#box_1').on('mousedown', function (e) {
            console.dir(e);


            let { left, top } = $(this).position();

            topOffset = top - e.screenY;
            leftOffset = left - e.screenX;
            //-----------------------
            callback = (function (leftOffset, topOffset, x, y) {
                let left = x + leftOffset;
                let top = y + topOffset;

                $('#box_1').css({
                    top: top,
                    left: left
                });
            }).bind(this, leftOffset, topOffset);
            //-----------------------
            $('#moveEvent').css('display', 'block');
        });

        $('#moveEvent').on('mousemove', function (e) {
            console.log('offset:(%s, %s)', e.offsetX, e.offsetY);
            console.log('screen(%s, %s)', e.screenX, e.screenY);

            if(callback){
                callback(e.screenX, e.screenY);
            }
        });

        $('#moveEvent').on('mouseup', function () {
            callback = undefined;
            $('#moveEvent').css('display', '');
        });
    </script>
</body>

</html>

2019年2月25日 星期一

yahoo serialize

/*
Copyright (c) 2014, Yahoo! Inc. All rights reserved.
Copyrights licensed under the New BSD License.
See the accompanying LICENSE file for terms.
*/

'use strict';

// Generate an internal UID to make the regexp pattern harder to guess.
var UID                 = Math.floor(Math.random() * 0x10000000000).toString(16);
var PLACE_HOLDER_REGEXP = new RegExp('"@__(F|R|D)-' + UID + '-(\\d+)__@"', 'g');

var IS_NATIVE_CODE_REGEXP = /\{\s*\[native code\]\s*\}/g;
var UNSAFE_CHARS_REGEXP   = /[<>\/\u2028\u2029]/g;

// Mapping of unsafe HTML and invalid JavaScript line terminator chars to their
// Unicode char counterparts which are safe to use in JavaScript strings.
var ESCAPED_CHARS = {
    '<'     : '\\u003C',
    '>'     : '\\u003E',
    '/'     : '\\u002F',
    '\u2028': '\\u2028',
    '\u2029': '\\u2029'
};

function escapeUnsafeChars(unsafeChar) {
    return ESCAPED_CHARS[unsafeChar];
}

module.exports = function serialize(obj, options) {
    options || (options = {});

    // Backwards-compatability for `space` as the second argument.
    if (typeof options === 'number' || typeof options === 'string') {
        options = {space: options};
    }

    var functions = [];
    var regexps   = [];
    var dates     = [];

    // Returns placeholders for functions and regexps (identified by index)
    // which are later replaced by their string representation.
    function replacer(key, value) {
        if (!value) {
            return value;
        }

        // If the value is an object w/ a toJSON method, toJSON is called before
        // the replacer runs, so we use this[key] to get the non-toJSONed value.
        var origValue = this[key];
        var type = typeof origValue;

        if (type === 'object') {
            if(origValue instanceof RegExp) {
                return '@__R-' + UID + '-' + (regexps.push(origValue) - 1) + '__@';
            }

            if(origValue instanceof Date) {
                return '@__D-' + UID + '-' + (dates.push(origValue) - 1) + '__@';
            }
        }

        if (type === 'function') {
            return '@__F-' + UID + '-' + (functions.push(origValue) - 1) + '__@';
        }

        return value;
    }

    var str;

    // Creates a JSON string representation of the value.
    // NOTE: Node 0.12 goes into slow mode with extra JSON.stringify() args.
    if (options.isJSON && !options.space) {
        str = JSON.stringify(obj);
    } else {
        str = JSON.stringify(obj, options.isJSON ? null : replacer, options.space);
    }

    // Protects against `JSON.stringify()` returning `undefined`, by serializing
    // to the literal string: "undefined".
    if (typeof str !== 'string') {
        return String(str);
    }

    // Replace unsafe HTML and invalid JavaScript line terminator chars with
    // their safe Unicode char counterpart. This _must_ happen before the
    // regexps and functions are serialized and added back to the string.
    str = str.replace(UNSAFE_CHARS_REGEXP, escapeUnsafeChars);

    if (functions.length === 0 && regexps.length === 0 && dates.length === 0) {
        return str;
    }

    // Replaces all occurrences of function, regexp and date placeholders in the
    // JSON string with their string representations. If the original value can
    // not be found, then `undefined` is used.
    return str.replace(PLACE_HOLDER_REGEXP, function (match, type, valueIndex) {
        if (type === 'D') {
            return "new Date(\"" + dates[valueIndex].toISOString() + "\")";
        }

        if (type === 'R') {
            return regexps[valueIndex].toString();
        }

        var fn           = functions[valueIndex];
        var serializedFn = fn.toString();

        if (IS_NATIVE_CODE_REGEXP.test(serializedFn)) {
            throw new TypeError('Serializing native function: ' + fn.name);
        }

        return serializedFn;
    });
}

2019年2月13日 星期三

java swing 刊誤

p525>> 
import java.awt.event.*;
import java.awt.Window;

public class BasicWindowMonitor extends WindowAdapter {

  public void windowClosing(WindowEvent e) {
    Window w = e.getWindow();
    w.setVisible(false);
    w.dispose();
    System.exit(0);
  }
}

2019年2月9日 星期六

node.js 路徑

// 專案目錄位置
const root = fs.realpathSync('./');

require(`${root}/node_modules/..........`);

批配套嵌的 script 標籤

 // 否定式前向搜索
target = '<script><script>555</script></script>'
reg = <script>(?!.*<script>).*?</script>

2019年2月3日 星期日

java 取得物件資訊

static void getClassInfo(Object o) {
        Class c = o.getClass();

        // 取得套件代表物件
        Package p = c.getPackage();

        out.printf("package %s;%n", p.getName());

        // 取得型態修飾,像是public、final
        int m = c.getModifiers();

        out.print(Modifier.toString(m) + " ");
        // 如果是介面
        if (Modifier.isInterface(m)) {
            out.print("interface ");
        } else {
            out.print("class ");
        }

        out.println(c.getName() + " {");
        //-----------------------
        // 取得宣告的資料成員代表物件
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            // 顯示權限修飾,像是public、protected、private
            out.print("\t"
                    + Modifier.toString(field.getModifiers()));
            // 顯示型態名稱
            out.print(" "
                    + field.getType().getName() + " ");
            // 顯示資料成員名稱
            out.println(field.getName() + ";");
        }
       
        out.println("----------------------");
        //-----------------------
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            // 顯示權限修飾,像是public、protected、private
            out.print("\t"
                    + Modifier.toString(
                            method.getModifiers()));
            // 顯示返回值型態名稱
            out.print(" "
                    + method.getReturnType().getName() + " ");
            // 顯示方法名稱
            out.println(method.getName() + "();");
        }
        out.println("}");
    }

java 教學

https://github.com/JustinSDK/JavaSE6Tutorial

2019年2月2日 星期六

tkinter 教學

https://www.programcreek.com/python/example/4300/Tkinter.Scrollbar

http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html

http://effbot.org/tkinterbook/

https://www.tutorialspoint.com/python/python_gui_programming.htm

操控點位移(不錯的版本)

<pre>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style media="screen">
        *{
            padding: 0;
            margin: 0;
            box-sizing: border-box;
        }

        .main_container{
            width: 400px;
            height:300px;
            background-color: #FCC;
            position: relative;
        }

        .symbol {
            width: 100%;
            height: 100%;
        }

        .operator{
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
        }

        p.box{
            position: absolute;
            left: 0;
            top: 0;
            width: 20px;
            height: 20px;
            background-color: #666;
        }
    </style>
    <script src="./js_lib/jquery-3.3.1.min.js" charset="utf-8"></script>

</head>

<body>
    <div>
        <button type="button" onclick=t_1()>go</button>
    </div>
    <div class="main_container">
        <div id="symbol" class="symbol">

        </div>
        <div id="operator" class="operator">
            <p class="box" id="box_1"></p>

        </div>

    </div>
    <script>
        function V(){
            this.symbol;
            this.operator;
            this.box;

            this.box_click_left;
            this.box_click_top;

            this.__construct();
        };

        (function(){
            this.__construct = function(){
                debugger;
                this.symbol = document.querySelector('#symbol');
                this.operator = document.querySelector('#operator');
                this.box = document.querySelector('#box_1');



                $(this.box).on('mousedown', (function(e){
                    this.event_1(e);
                }).bind(this));


                $(this.operator).on('mouseup', (function(e){
                    this.event_2(e);
                }).bind(this));

            };
            //----------------------------
            this.event_1 = function(e){
                // debugger;

                this.box_click_left = e.offsetX;
                this.box_click_top = e.offsetY;

                $(this.box).appendTo(this.symbol);

                $(this.operator).on('mousemove', (function(e){
                    this.event_3(e);
                }).bind(this));
            };
            //----------------------------
            this.event_2 = function(e){
                $(this.operator).off('mousemove');
                $(this.box).appendTo(this.operator);
            };
            //----------------------------

            this.event_3 = function(e){

                console.log('(%s, %s)', e.offsetX, e.offsetY);

                let x= e.offsetX - this.box_click_left;
                let y = e.offsetY - this.box_click_top;

                $(this.box).css({
                    left: x,
                    top: y
                });

            };
        }).call(V.prototype);

        new V();
    </script>
</body>

</html>
</pre>

2019年1月24日 星期四

pipe

https://www.npmjs.com/package/multipipe
https://github.com/zoubin/streamify-your-node-program

http://www.xiedacon.com/2017/08/11/Node.js%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90-pipe%E5%AE%9E%E7%8E%B0/#Node-js%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90-pipe%E5%AE%9E%E7%8E%B0

-----------------------------------------------------------------------

const _ = require("underscore");
require("underscore_extension")(_);

const $path = require("path");
const $fs = require('fs');
const $zlib = require('zlib');

http();

function http() {

    let server = require("http").createServer(async function (req, resp) {

        resp.writeHead(200, {
            'Content-Type': 'image/jpg',
            'content-encoding': 'gzip'
        });


        let _path = $path.resolve(__dirname, './images/plane_1.jpg');

        let reader = $fs.createReadStream(_path);
        reader = reader.pipe($zlib.createGzip());
        await pipe(reader, resp);

        resp.end();
    });
    server.listen(8081);
}

function _error(res) {
    res.writeHead(200, {
        'Content-Type': 'text/html'
    });
    console.log('error...')
    res.end('<h1>error</h1>');
}


function pipe(reader, writer, size) {

    let def = _.deferred();

    reader.on('readable', function () {
        // 採用靜態模式
        console.log('----------readable----------------');
        write();
    });

    reader.on('data', function (chunk) {
        // reader.read() 會進來此
        console.log('on data(%s)', chunk.length);
    });

    writer.on('drain', function () {
        console.log('drain..........');

        let data;

        // 讀取之未讀完的記憶體
        if (!write(true)) {
            return;
        }

        console.log('舊的讀取完');
        reader.resume();
    });

    reader.on('end', function () {
        console.log('end');
        def.resolve();
    });
    //----------------------------

    function write(noPause) {
        console.log('....write')
        while (true) {
            console.log('read(%s)', (noPause ? 'flush' : 'ok'));
            let data = reader.read(size);

            if (data === null) {
                console.log('read end');
                break;
            } else {
                if (writer.write(data) === false) {
                    console.log('too much pause');

                    if (!noPause) {
                        console.log('pause...');
                        reader.pause();
                    }

                    return false;
                }
            }
        }
        return true;
    }

    //----------------------------
    return def.promise();
}










2019年1月22日 星期二

tkinter

import json
from tkinter import *


class GUI:
    data = {0: 'aaa', 1: 'bbb', 2: 'ccc'}

    def __init__(self):
        self.root = Tk()
        self.checks = {}
        self.msg = Label(self.root)

        self._build_1()
        self._event_1()
        self._render()

    def _build_1(self):
        Label(self.root, text="choose").pack()

        for i in range(len(GUI.data)):
            check = self.checks[i] = BooleanVar()

            // 監聽述職的變化
            check.trace('w', self._event_1)

            checkbtn = Checkbutton(self.root, text=GUI.data[i], variable=check)
            checkbtn.pack()

        self.msg.pack()

    def _render(self):
        self.root.mainloop()

    def _event_1(self, *args):

        res = []

        for i, check in (self.checks).items():
            
            if check.get() == True:
                res.append(GUI.data[i])

        res = json.dumps(res)
        self.msg.config(text=res)


GUI()

2019年1月19日 星期六

node.js stream.pipe

Stream.prototype.pipe = function(dest, options) {
  var source = this;
  source.on('data', function (chunk) {
    if (dest.writable) {
      if (false === dest.write(chunk) && source.pause) {
        source.pause();
      }
    }
  });

  dest.on('drain',   function () {
    if (source.readable && source.resume) {
      source.resume();
    }
  });

  dest.emit('pipe', source);

  // Allow for unix-like usage: A.pipe(B).pipe(C)
  return dest;
};

2019年1月18日 星期五

node.js 進程池

const cp = require('child_process')

function doWork(job, callback) {
    // TODO worker 是 工作进程,下一步进行实现
    let child = cp.fork('./worker')
    // 用来跟踪回调的执行状态,防止出现多次回调调用
    let cbTriggered = false;

    child.once('error', function (err) {
        if (!cbTriggered) {
            callback(err)
            cbTriggered = true;
        }
        // 异常错误时,杀死子进程
        child.kill();
    })
        .once('exit', function (code, signal) {
            if (!cbTriggered) {
                callback(new Error('Child exited with code: ' + code));
            }
        })
        .once('message', function (result) {
            callback(null, result)
            cbTriggered = true;
        })
        .send(job);
}

//--------------------------------------
// pooler.js

const cp = require('child_process');
// 取到cpu 数量
const cpus = require('os').cpus().length;

module.exports = function (workModule) {

    // 当没有空闲的cpu时,用来存放任务队列
    let awaiting = [];
    // 存放准备就绪的工作进程
    let readyPool = [];
    // 存放现有的工作者进程的数量
    let poolSize = 0;

    return function doWork(job, callback) {

        // 如果没有空闲的工作进程并且工作进程达到了限制,就把后续任务放入队列等待执行
        if (!readyPool.length && poolSize > cpus) {
            return awaiting.push([doWork, job, callback])
        }

        // 获取下一个可用的子进程或者fork一个新的进程并增加池子大小
        let child = readyPool.length
            ? readyPool.shift()
            : (poolSize++ , cp.fork(workModule));

        let cbTriggered = false;

        // 移除子进程上的所有监听,保证每一个子进程每次只有一个监听
        child
            .removeAllListeners()
            .once('error', function (err) {
                if (!cbTriggered) {
                    callback(err)
                    cbTriggered = true;
                }
                child.kill();
            })
            .once('exit', function (code, signal) {

                if (!cbTriggered) {
                    callback(new Error('Child exited with code: ' + code));
                }

                poolSize--;
                // 如果子进程由于某种原因退出,保证在readyPool中也被移除了
                let childIdx = readyPool.indexOf(child);
                if (childIdx > -1) {
                    readyPool.splice(childIdx, 1);
                }

            })
            .once('message', function (result) {
                callback(null, result)

                cbTriggered = true;

                // 把空闲的子进程再次放入readyPool,等待接下来的任务
                readyPool.push(child);
                if (awaiting.length) {
                    setImmediate.apply(null, awaiting.shift());
                }
            })
            .send(job);
    }
}

2019年1月16日 星期三

node.js http 讀取 stream

function pstreamPipe(path, callback, code){
    return (streamPipe(path, callback, code)[0]);
}


function streamPipe(path, callback, code) {
    let def = _.deferred();


    let stream = require("fs").createReadStream(path);
    if (code) {
        stream.setEncoding(code);
    }

    stream.on('data', function (data) {
        callback(data);
    });

    stream.on('error', function (err) {
        def.reject(err);
    });

    stream.on('end', function () {
        def.resolve();
    });

    return [def.promise(), stream];
}

一個 java 泛型的例子

public interface X<T> {
   
    public void setData(T data);
   
    public T getData();
}

public class Y<T> implements X<T> {

    public T data;

    @Override
    public void setData(T data) {
        this.data = data;
    }

    public T getData() {
        return this.data;
    }
}

public class Done {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        X<String> x = new Y();
        x.setData("hi");
       
        out.println(x.getData());
    }
   
}

swing 的組織想法

// 中間協調者
public class Observeable<T> {
    // 要通知的組件
    public ArrayList<Observe> elements;
   
    public void emit(String eventName, T data){
       
    }
}

public interface Observe<T> {
   
    public void on(String eventName);
   
    public void off(String eventName);
   
    public void notify(String eventName, T data);
}

public class Element<T, E> implements Observe<E> {
    // swing 元件
    public T x;

    @Override
    public void on(String eventName) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void off(String eventName) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void notify(String eventName, E data) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }  
}

2019年1月8日 星期二

javascript eval() 常會錯誤難解的地方

let l = "aaa\"bbb\"aaa";
let command = "let x = \"" + l + "\";";

console.log(command); // >>> let x = "aaa"bbb"aaa";

eval(command);
//-------------------------------------------
// 解法

let l = "aaa\"bbb\"aaa"; (看作  aaa"bbb"aaa)

l = l.replace(/\"|\'/g, function(m){
    return ('\\' + m);
});

(把 i  看作 aaa\"bbb\"aaa)


特殊字符\u2028導致的Javascript腳本異常

網上查詢得知,這個編碼為2028的字符為行分隔符,會被瀏覽器理解為換行,而在Javascript的字符串表達式中是不允許換行的,從而導致錯誤。
解決方法

把特殊字符轉義替換即可,代碼如下所示:
1
   
str = str.Replace("\u2028", "\\u2028");

替換後,用之前有問題的文章測試,加載正常,問題解決。

另外,Javascript中的特殊字符一共有13個,建議都進行轉義處理,如下:
Unicode 字符值    轉義序列    含義    類別
\u0008     \b     Backspace    
\u0009     \t     Tab     空白
\u000A     \n     換行符(換行)     行結束符
\u000B     \v     垂直製表符     空白
\u000C     \f     換頁     空白
\u000D     \r     回車     行結束符
\u0022     \"     雙引號 (")    
\u0027     \'     單引號 (')    
\u005C     \\     反斜槓 (\)    
\u00A0           不間斷空格     空白
\u2028           行分隔符     行結束符
\u2029           段落分隔符     行結束符
\uFEFF           字節順序標記     空白

2019年1月5日 星期六

python list.sort

x = [{"age": 15}, {"age": 5}, {"age": 10}]


def sortFn(arg):
    '''用 age 作為排序依據'''
    return arg['age']

x.sort(key=sortFn)
print(x)