Popular Posts
Enable SSL connection for Jsoup import org.jsoup.Connection; import org.jsoup.Jsoup; import javax.net.ssl.*; import java.io.IOException; import java.security.KeyManagement... Word break tag : <wbr/> (HTML5) The  HTML  <wbr>  tag  is  used  defines  a  potential  line  break  point  if  needed.  This  stands  for  Word  BReak. This  is  u... Build an OpenVPN server on android device Preparation An android device, in this case, Sony xperia Z is used Root permission required Linux Deploy for deploy i...
Blog Archive
Stats
Generate subversion diff report using python

bash:

svn --diff-cmd "python" --extensions "diff_to_html.py" diff -r 596:671

diff_to_html.py

import sys
import difflib
import os
import argparse

FOLDER_MODIFY = 'modify'
FOLDER_ADD = 'add'
FOLDER_DELETE = 'delete'

# 解析參數
parser = argparse.ArgumentParser()
parser.add_argument('-u', action='store_true')
parser.add_argument('-L', action='store_true')
parser.add_argument('-r', '--report', default='report')
parser.add_argument('-w', '--white-list',
                    nargs='+',
                    default=['.cs', '.csproj', '.config', '.xml', '.sln'])
parser.add_argument('revfrom')
parser.add_argument('revto')
parser.add_argument('filefrom')
parser.add_argument('fileto')
args = parser.parse_args()

from_file = args.revfrom
to_file = args.revto
from_file_path = args.filefrom
to_file_path = args.fileto

output_folder = args.report
white_list = args.white_list

# inject
inject_script = """
    <script>
        document.body.onload = function () {
            readableChange();
        }

        function readableChange() {
            var className = 'diff_chg';
            var lines = getChangedRows(className);

            // 頭尾應為文字內容
            lines.forEach(function (item) {
                var headerText = item.firstChild.data;
                var tailText = item.lastChild.data;
                var fullText = Array.prototype.map.call(item.childNodes, function (child) {
                    return child.nodeType == '3' ? child.data : child.innerText;
                });

                if (headerText !== undefined) {
                    fullText.shift();
                }
                if (tailText !== undefined) {
                    fullText.pop();
                }

                var i = 10;
                while (item.lastChild) {
                    item.removeChild(item.lastChild);
                }

                item.appendChild(document.createTextNode(headerText || ''));
                item.appendChild(createMark(className, fullText))
                item.appendChild(document.createTextNode(tailText || ''));
            })
        }

        function createMark(className, text) {
            var mark = document.createElement('span');
            mark.classList.add(className);
            mark.appendChild(document.createTextNode(text.join('')));
            return mark;
        }

        function getChangedRows(className) {
            var changedLines = Array.prototype.map.call(document.querySelectorAll('.' + className), function (element) {
                return element.parentElement;
            });
            changedLines = changedLines.filter(function (element) {
                return element.tagName == 'TD';
            });
            var lines = [];
            for (var i = 0; i < changedLines.length; i++) {
                var line = changedLines[i];
                if (!lines.find(function (item) {
                    return item == line;
                })) {
                    lines.push(line);
                }
            }
            return lines;
        }
    </script>
"""

inject_styles = """
    <style>
        * {
            font-size: 0.9rem !important;
        }
    </style>
"""


def readlines(path):
    """
    讀取檔案內容
    """
    content = None
    try:
        with open(file=path, mode='rt', encoding='utf-8') as f:
            content = [l for l in f.readlines()]
    except:
        try:
            with open(file=path, mode='rt', encoding='ms950') as f:
                content = [l for l in f.readlines()]
        except:
            print('讀取 {} 失敗'.format(path))
    return content


def execute():
    """
    比對檔案產出 HTML
    """
    print('讀取檔案 {}'.format(to_file_path))
    to_file_content = readlines(to_file_path)
    print('讀取檔案 {}'.format(from_file_path))
    from_file_content = readlines(from_file_path)

    if to_file_content is None or from_file_path is None:
        return

    html = difflib.HtmlDiff().make_file(
        from_file_content, to_file_content, from_file, to_file,  context=True)

    html = html.replace('</head>', inject_styles + '</head>')
    html = html.replace('</body>', inject_script + '</body>')

    output_file = '{}.html'.format(to_file[0: to_file.find('\t')])
    output_file = output_file.replace('/', '_')
    output_file = output_file.replace('\\', '_')

    if len(to_file_content) == 0:
        output_file = os.path.join(output_folder, FOLDER_DELETE, output_file)
        if not os.path.exists(os.path.join(output_folder, FOLDER_DELETE)):
            os.makedirs(os.path.join(output_folder, FOLDER_DELETE))
    elif len(from_file_content) == 0:
        output_file = os.path.join(output_folder, FOLDER_ADD, output_file)
        if not os.path.exists(os.path.join(output_folder, FOLDER_ADD)):
            os.makedirs(os.path.join(output_folder, FOLDER_ADD))
    else:
        output_file = os.path.join(output_folder, FOLDER_MODIFY, output_file)
        if not os.path.exists(os.path.join(output_folder, FOLDER_MODIFY)):
            os.makedirs(os.path.join(output_folder, FOLDER_MODIFY))

    print('寫入檔案 {}'.format(output_file))
    with open(file=output_file, mode='wt', encoding='utf-8') as f:
        f.write(html)


if len([ext for ext in white_list if to_file[0: to_file.find('\t')].lower().endswith(ext.lower())]) > 0:
    execute()
else:
    print('不處理 {} 的檔案比對。'.format(to_file[0: to_file.find('\t')]))

output file:

Expression in polymer
Since Polymer doesn't support expression directly, I create an express function as expression alternative.

Demo

Demo source

<html>
<head>
    <title>Express function for Polymer</title>
    <base href="https://cdn.rawgit.com/download/polymer-cdn/2.0.2/lib/">
    <link rel="import" href="polymer/polymer.html" />
</head>
<body>
    <h1>Expression</h1>
    <expressed-content count="15"></expressed-content>

    <dom-module id="expressed-content">
        <template>
            <template is="dom-repeat" items="[[sequences]]" as="item">
                <!-- This means: -->
                <!-- 1. sqrt(item) as $result -->
                <!-- 2. printText($result, item) as output -->
                <div>[[express(item, sqrt, printText, item)]]</div>
            </template>
        </template>
        <script>
            'use strict';
            class ExpressedContent extends Polymer.Element {

                static get is() { return 'expressed-content'; }

                static get properties() {
                    return {
                        count: {
                            type: Number,
                            value: 10,
                            observer: '_countChanged'
                        },

                        sequences: {
                            type: Array
                        }
                    }
                }

                _countChanged(n, o) {
                    n = Math.max(0, n * 1);
                    let sequences = [];
                    for (let i = 0; i < n; i++) {
                        sequences.push(i + 1);
                    }
                    this.sequences = sequences;
                }

                /**
                 * An express function instead of expression
                 */
                express() {
                    let args = [...arguments];

                    // first argument should be first parameter
                    let params = [args.shift()];
                    // second argument should be a function
                    let fn = args.shift();

                    // arguments before next function will be additional parameters
                    while (args[0] && typeof (args[0]) !== 'function') {
                        params.push(args.shift());
                    }

                    // execute and receive result
                    let nextMainParam = fn.call(this, ...params);

                    // continue express when args is not empty
                    return args.length === 0 ? nextMainParam : this.express(nextMainParam, ...args);
                }

                sqrt(n) {
                    return n * n;
                }

                printText(n1, n2) {
                    return `${n2} x ${n2} = ${n1}`;
                }

            }
            customElements.define(ExpressedContent.is, ExpressedContent);
        </script>
    </dom-module>
</body>
</html>
Javascript lambda: No binding of this
<form>
    <p>
        <button id="f1">Invoke with function</button>
    </p>
    <p>
        <button id="f2">Invoke with lambda</button
    </p>
    <div id="output"></div>
</form>
<script>
    'use strict';
    (function () {
        let f1 = document.querySelector('#f1'),
            f2 = document.querySelector('#f2'),
            output = document.querySelector('#output');

        function appendResult(message) {
            let log = document.createElement('pre');
            log.appendChild(document.createTextNode(message));
            output.appendChild(log);
        }

        // define with function, reference 'this' to button element
        f1.onclick = function () {
            appendResult('Button [Invoke with function] clicked!');
            appendResult('This is: ' + JSON.stringify(this) + ' [' + this.constructor.name + ']');
            console.log(this);
            return false;
        };

        // define with lambda, reference 'this' to {name: 'Bruce'} object
        f2.onclick = () => {
            appendResult('Button [Invoke with lambda] clicked!');
            appendResult('This is: ' + JSON.stringify(this) + ' [' + this.constructor.name + ']');
            console.log(this);
            return false;
        };

    }).call({name: 'Bruce'})
</script>
Result:

Reference: No binding of this
Memo: Debounce Task

To prevent multi-execution from caller in short time, use debounce for single execution.

var debounce = function (func, threshold, execAsap) {
    var timeout;
    return function debounced () {
        var obj = this, args = arguments;
        function delayed () {
            if (!execAsap)
            func.apply(obj, args);
            timeout = null;
        };
        if (timeout)
            clearTimeout(timeout);
        else if (execAsap)
            func.apply(obj, args);
        timeout = setTimeout(delayed, threshold || 100);
    };
}
Compacting VirtualBox Disk Images - Linux Guests
  1. Start the Linux virtual machine;
  2. Clean the free space on the disk of the Linux virtual machine;
    dd if=/dev/zero of=zerofillfile bs=1M
    • if= specifies the input file;
    • /dev/zero indicates a bit-stream of zeros
    • of= specifies the output file
    • zerofillfile name of the file containing the bit-stream of zeros
    • bs= indicates the block size
    • 1M indicates that the block size will be 1 megabyte
    rm zerofillfile
  3. Shutdown the Linux virtual machine;
  4. Use the VirtualBox VBoxManage utility to compact the Linux guest image.

Ref: Compacting VirtualBox Disk Images - Linux Guests

Grant permission for virtualbox shared folder

The regular way of getting access to the files now, is to allow VirtualBox to automount the shared folder (which will make it show up under /media/sf_directory_name) and then to add your regular user to the vboxsf group (as root #).

usermod -aG vboxsf <youruser>
Build an OpenVPN server on android device

Preparation


  1. An android device, in this case, Sony xperia Z is used
  2. Root permission required
  3. Linux Deploy for deploy image via chroot/proot
  4. OpenVPN


Step

1. Root android device for superuser permission
2. Install Linux Deploy from play store or custom apk.
3. Install linux
  • Click download icon to select which image to deploy

  • Select which distribution and suite to use
  • Set user name & password
  • Allow init system
  • Enable SSH server

  • Deploy distribution

  • After installation completed, start linux

4. Connect to android via SSH
5. Install OpenVPN
  • Install required packages
  • Create certification folder and edit vars configuration
  • Edit vars as blow
  • Build ca, server and client certification

  • Copy required certification to the path of openvpn
  • Clone configuration file from sample config
  • Edit server.conf
  • Edit server.conf as blow, modify what your need
  • Modify networking config sysctl.conf
  • Modify content to allow transfer traffic from vpn
  • Make changes work
  • Edit firewall rules
  • Add following content to allow route from vpn subnet to wireless
  • Edit firewall configuration
  • Allow forward policy
  • Add firewall rule for vpn and ssh
  • Make changes work. (In this case, there was some error but I ignore that)
  • Start openvpn
  • Validate result

6. Use vpn client to connect android device
My Conky config

About Conky: Conky is a free, light-weight system monitor for X, that displays any kind of information on your desktop.


Preview: