家里爆水管的救命神器

家里爆水管的救命神器

家里爆水管怎么办?

在美国当home owner,就总会碰到这样或那样的问题。爆水管就是其中一项。这不,今天就碰到了。我家前院的一个水龙头因为老化,直接就给冲喷了。前院直接就水漫金山了。而且祸不单行的是,那个总闸好像还坏了。我还算镇静,想到水表那应该有开关。结果发现那个开关是个长条形的,根本拧不动。只好打电话给当地自来水公司。幸好我们的墨西哥邻居出手相助,用了一个超大的扳手给关上了。因为自来水公司他们只来帮关闸,不管维修,所以就再打电话给他们说不用来了。他们反应很慢,不知道还要等几个小时呢。

救命神器

后来我买来新的水龙头换上,但是邻居不在,总不能老麻烦人家。如果Google了一下这个阀门应该有什么工具。结果还真给我找到了。这个工具叫water meter key

如果家里curb side的水表的阀门是这种长条类型的,强烈建议花10几刀给家里备上这么个救命神器。真到爆水管的关键时候能把总闸关了。叫一次plumber起码得几百刀了,而且要多少你都得给。我不知道叫自来水公司要不要钱,这次我是取消了,不然说不定事后给张账单也说不准。

在Java里怎样把exception的stacktrace压缩到一行?

在Java里怎样把exception的stacktrace压缩到一行?

一般在Java里,我们可以用printStackTrace把stacktrace打印出来。

try {
    // do something
} catch (Exception e) {
    e.printStackTrace();    
}

在server里,如果我们需要用graylog来search log,就需要把stacktrace压缩到一行。我们可以用apache的ExceptionUtils

import org.apache.commons.lang.exception.ExceptionUtils;
//...

try {
    // do something
} catch (Exception e) {
    logger.error("Exception: {}", 
        ExceptionUtils.getStackTrace(e)
    );
}

Macbook 中文输入法使用全角/半角标点符号

Macbook 中文输入法使用全角/半角标点符号

在我的Macbook上写中文,标点符号都是半角的(也就是英文的)。一直都很疑惑,本来还以为是wordpress的问题。今天好奇在网上做了一下研究,终于找到原因了。

解决方法

点击屏幕上方的菜单栏的输入法

注意下拉菜单里面有个“Use Halfwidth Punctuation“的选项,如果这个是打勾的,就会用半角标点符号。再点击一下去掉勾就可以变会正常的全角中文标点符号了。

怎样在Excel里正确显示韩语

怎樣在Excel裡正確顯示韓語

最近遇到一个问题,用Excel打开含有韩语CSV文件, 里面的韩语字符都是乱码。后来发现问题是那些CSV的encoding格式是UTF-8。如果直接用Excel打开,解码格式就不对。

解决方法

在File目录选import

选CSV

选择文件,然后重要的一步, 选择File origin,然后选UTF-8

剩下的正常操作, 选择delimiter,这样韩语(其实是任何 UTF-8的字符)就可以在Excel正常显示了。

ECharts快速上手

ECharts快速上手

前段一直是我的短板, 没有太多机会系统学习. 最近想做一个股票分析系统的webapp, 于是就在网上找合适的javascript library做data visualization. D3.js以前用过, 觉得太过底层, 写起来太麻烦. 于是发现了ECharts, 好像是国内大神写得, 已经是Apache project, 非常厉害. 于是follow了这个tutorial. 里面有些小细节我觉得初学者可能会卡住, 这里我写得详细一点.

安装npm

npm是node package manager的意思, 是用了管理安装javascript libraries的. 相当于Python里的pip. 安装可以看我前面的文章.

安装ECharts

首先给项目建立一个新的directory

% mkdir test_echart
% cd test_echart

在项目directory里安装echarts library

npm install echarts --save

完成后directory里会有那么几个东西

% ls
package-lock.json
node_modules/		package.json

开始Coding

在项目directory里面添加一个html file叫main.html, 内容如下调用echart

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <!-- including ECharts file -->
    <script src="node_modules/echarts/dist/echarts.min.js"></script>
</head>

<body>
    <!-- preparing a DOM with width and height for ECharts -->
    <div id="main" style="width:600px; height:400px;"></div>
</body>

<script type="text/javascript">
        // based on prepared DOM, initialize echarts instance
        var myChart = echarts.init(document.getElementById('main'));

        // specify chart configuration item and data
        var option = {
            title: {
                text: 'ECharts entry example'
            },
            tooltip: {},
            legend: {
                data:['Sales']
            },
            xAxis: {
                data: ["shirt","cardign","chiffon shirt","pants","heels","socks"]
            },
            yAxis: {},
            series: [{
                name: 'Sales',
                type: 'bar',
                data: [5, 20, 36, 10, 10, 20]
            }]
        };

        // use configuration item and data specified to show chart
        myChart.setOption(option);
    </script>
</html>

header里面的这行相当于Python的import

    <script src="node_modules/echarts/dist/echarts.min.js"></script>

现在directory内容如下

% ls
main.html		package-lock.json
node_modules/		package.json

用浏览器打开main.html. 在Mac里可以在terminal里用

% open main.html

网页显示如下, 还是挺酷的.

简单看看js code, option就是一个json object, 里面包含了图的一些信息和data. 一开始init了一个echarts object, 然后给它set一下option这个json object. 和d3比起来还是简单多了.

        var myChart = echarts.init(document.getElementById('main'));
        
        var option = {
            // json object
        };

        myChart.setOption(option);

我把数据改一改, 就可以显示一些投资标的的市值了

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <!-- including ECharts file -->
    <script src="node_modules/echarts/dist/echarts.min.js"></script>
</head>

<body>
    <!-- preparing a DOM with width and height for ECharts -->
    <div id="main" style="width:1000px; height:400px;"></div>
</body>

<script type="text/javascript">
        // based on prepared DOM, initialize echarts instance
        var myChart = echarts.init(document.getElementById('main'));

        // specify chart configuration item and data
        var option = {
            title: {
                text: 'Market Caps'
            },
            tooltip: {},
            legend: {
                data:['Sales']
            },
            xAxis: {
                data: []
            },
            yAxis: {},
            series: [{
                name: 'Sales',
                type: 'bar',
                data: []
            }]
        };

        const MARKET_CAP = 'market cap';
        var legends = [MARKET_CAP];
        var symbols = ['AAPL', 'GOOGL', 'FB', 'AMZN', 'NVDA', 'NFLX', 'TSLA', 'BTC', 'ETH', 'V', 'MA']
        var marketCaps = [2256, 1185, 778, 1634, 323, 238, 669, 622, 109, 482, 356];

        option.legend.data = legends;
        option.xAxis.data = symbols;
        option.series[0].data = marketCaps;	
        option.series[0].name = MARKET_CAP;	

        // use configuration item and data specified to show chart
        myChart.setOption(option);
    </script>
</html>

网页更新如下. 接上个数据的后端就可以显示不同的数据了.

Python/Pandas实战: 处理IBKR Statement

Python/Pandas实战: 处理盈透Statement

Pandas是一个非常强大的数据分析方面的Python package. 如果是做Machine Learning或者数据分析, 掌握Pandas很省去很多麻烦. 许多Machine Learning前期的数据处理也是用Pandas做得.

IBKR(Interactive Brokers, 有时简称IB, 中文叫盈透证券)是美国老牌券商, 也是我的主要使用的券商. 又到了辞旧迎新的时候, 需要看看2020投资收益, 于是趁新年长周末写点小程序做点数据分析. 而这正好覆盖了Pandas的各种常用functions.

下载IB Statement

IB Statement提供多种方式下载, 比如html, pdf, csv. 用作数据处理选csv. 内容大概长这样

IB statement例子

Statement这个column是内容, 里面有很多项, 而这里我只看“Realized & Unrealized Performance Summary”, 然后相同的第一列后面的列数都是一样的. 上图是Jupyter Lab的显示有问题. 因为文件其实可以看成很多CSV files连在一起, 而第一列可以看成是小csv的文件名. 然后第二列是Header或者Data. Header那行就是告诉你后面的Data行里每一列都是什么. 于是我们可以把数据读到内存里.

建立Pandas DataFrame

import pandas as pd

field = 'Realized & Unrealized Performance Summary'

f = open('statement.csv', 'r')

rows = []
for line in f:
    cols = line.strip().split(',')
    if cols[0] == field:
        if cols[1] == 'Header':
            header_row = cols[2:]
        else:
            rows.append(cols[2:])

header_ros是个list of string

['Asset Category',
 'Symbol',
 'Cost Adj.',
 'Realized S/T Profit',
 'Realized S/T Loss',
 'Realized L/T Profit',
 'Realized L/T Loss',
 'Realized Total',
 'Unrealized S/T Profit',
 'Unrealized S/T Loss',
 'Unrealized L/T Profit',
 'Unrealized L/T Loss',
 'Unrealized Total',
 'Total',
 'Code']

而rows是list of list. 就是list of rows

[['Stocks',
  'AAPL',
  '0',
  '0',
  '0',
  '0',
  '0',
  '0',
  '29564.510608',
  '-14.176325',
  '0',
  '0',
  '29550.334283',
  '29550.334283',
  '\n'],
 ['Stocks',
  'AMD',
  '0',
  '0',
  '0',
  '0',
  '0',
  '0',
  '220.208447',
  '0',
  '0',
  '0',
  '220.208447',
  '220.208447',
  '\n'],
...
]

接下来就可以用Panda create dataframe了

df = pd.DataFrame(rows, columns = header_row)
df.head(5)

这里有个问题. Created出来的dataframe的数据类型有数字有string, 全部都是object. 如果sort by数字column得到的结果是sort by string, 并不是我们想要的. 可以用dtypes来确定

df.dtypes
Asset Category           object
Symbol                   object
Cost Adj.                object
Realized S/T Profit      object
Realized S/T Loss        object
Realized L/T Profit      object
Realized L/T Loss        object
Realized Total           object
Unrealized S/T Profit    object
Unrealized S/T Loss      object
Unrealized L/T Profit    object
Unrealized L/T Loss      object
Unrealized Total         object
Total                    object
Code                     object
dtype: object

这里我把需要转换成数字的columns转换了

header_text_col = set(['Asset Category', 'Symbol', 'Code'])
num_col = list(set(header_row) - header_text_col)
df[num_col] = df[num_col].apply(pd.to_numeric)
df.dtypes
Asset Category            object
Symbol                    object
Cost Adj.                  int64
Realized S/T Profit      float64
Realized S/T Loss        float64
Realized L/T Profit        int64
Realized L/T Loss        float64
Realized Total           float64
Unrealized S/T Profit    float64
Unrealized S/T Loss      float64
Unrealized L/T Profit      int64
Unrealized L/T Loss      float64
Unrealized Total         float64
Total                    float64
Code                      object
dtype: object

这样就可以对数字类型的column进行排序了, 比如下面指令做2步操作
1. 选出Asset Category是”Stocks”的rows, 相当于SQL里的where, 语法为df[df['Asset Category'] == 'Stock'], return是另一个filtered好的dataframe
2. 按Realized Total从小到大排序, return也是另一排序好的dataframe

df[df['Asset Category'] == 'Stock'].sort_values(by=['Realized Total'], ascending=True)

还可以画图

stock_gain = df[
    (df['Asset Category'] == 'Stocks') & (
        df['Realized Total'] != 0.0)][['Symbol', 'Realized Total']].sort_values(
    by=['Realized Total'], ascending=True)
stock_gain

还可以画图

stock_gain.plot.bar(x='Symbol')

技术小结

建立dataframe

rows是list of rows(lists), header_row是list of string

df = pd.DataFrame(rows, columns = header_row)

显示前n行

df.head(10)

显示后面n行

df.tail(10)

把特定columns转换成数字(numerical type)

num_col是list of strings, 下面命令会把num_col里的columns都转化成数字类. 类似SQL里的select cast(col1 as double), cast(col2 as double), ... from df

df[num_col] = df[num_col].apply(pd.to_numeric)

Filter和sort

类似SQL里, select * from df where asset_category = 'Stocks' order by realized_total asc;

df[df['Asset Category'] == 'Stocks'].sort_values(by=['Realized Total'], ascending=True)

在Apache2里怎样redirect URL? | How to redirect URL using Apache2?

在Apache2里怎样redirect URL?

原来以为这个问题很简单, Google了一下发现网上的答案五花八门, 而且版本很混乱 有httpd的, ASP.net, url redirect的, url rewrite的. 经过多次尝试各种组合, 终于试出了一个可行的解决方案, 值得在此记录一下, 相信一定能帮到有类似需求的人. 本文例子为Ubuntu + apache2, 2020年, 2021年左右.

普通URL redirect到另一个网站

编辑/etc/apache2/sites-available里面的一个site, 比如mysite, 需要redirect到anothersite.com, 那么可以加上一行Redirect

<VirtualHost *:80>
ServerAdmin webmaster@localhost
...
         ServerName mysite.com
         ServerAlias www.mysite.com
         DocumentRoot /var/www/html/mysite
         Redirect / http://anothersite.com
...         

修改完成后保存, 重启apache2

sudo service apache2 restart

Redirect到一个子目录

上面的方法可以redirect到不同的URL, 但是如果想redirect mysite.com到mysite.com/blog就不行. 我试了一下, 如果像上面那样改动, 在浏览器输入mysite.com就会被不停的改成mysite.com/blog/blog/blog… 无限循环. 很明显, 改写是recursive的. 那么就不要用Redirect而是用RedirectMatch

<VirtualHost *:80>
ServerAdmin webmaster@localhost
...
         ServerName mysite.com
         ServerAlias www.mysite.com
         DocumentRoot /var/www/html/mysite
         RedirectMatch ^/$ /blog/
...       

我也不太清楚apache2配置的语法细节, 但是以上是试过可行的方法. 最后一样是重启apache2让配置生效

sudo service apache2 restart

2020-12-26 比特币定投实验更新 | 2020-12-26 Update on Dollar average plan for buying bitcoin

2020-12-26 比特币定投实验更新

牛年还没到, 最近比特币就已经气冲天, 今天单价已经过了$26,000. 因为Concoinbase Pro有一次交易最少要买0.001个比特币的限制, 入场门槛越来越高了, 现在最少一次也要买入$26.xx以上了. 今天以前总投入$60, holding总价值$86.xx, 不到一个月总回报43%! 如果把全部资产买入真的是有机会改变阶级. 不过能赚到不正是因为赌注下少, 不在乎它的短期波动, 所以才能拿的住吗?我觉得还是继续执行定投计划, 也许会适量增加一点投入, 但注码量要控制在即使输光也不会让自己难受的范围内, 毕竟这还是有可能归零的高风险投资, 而自己对比特币还并不是很熟悉, 有时间的时候还是要多学习, 或者能做为程序员参与到相关项目开发中, 这样才有信心下比较重的注码投入. 不然就还是以娱乐为主吧.

今天新投入$30, 买入0.00111758, 均价$26,710.00. 总投入$90, holding现价值116.10.

照顾新生儿的经验总结

照顾新生儿的经验总结

现代社会, 尤其生活在湾区这种竞争激烈并且高物价的地方. 当父母不容易. 本文为宝妈总结的照顾小宝宝经验, 希望对其他新手父母有帮助.

照顾新生儿的关键就是要照顾小宝宝的吃睡玩.

我这里主要谈谈胸喂常遇到的问题. 胸喂最大的问题是宝宝是否能以正确的姿势吸奶. 大宝出生的时候没有经验,而且大宝天生舌筋可能有点紧,所以刚开始几天母乳没吃好,黄疸有点严重.二宝还好没有遇到这个问题,而且在医院遇到的护士教了我很有用的经验,所以二宝吸奶很好. 如果你担心你的宝宝吸奶是否正确,可以在医院的时候请教护士, 医院还有免费的母乳喂养指导lactation consultant. 我学到的经验是如果宝宝吸奶发出很大的咂咂声,那就说明宝宝吸奶舌头姿势不对, 有很多空气进去. 如果姿势正确,还是发出这样的声音,那你要怀疑宝宝舌筋有问题, 你可以找儿医做个简单的检查.检查很简单, 宝宝张开嘴, 儿医就可以通过观察宝宝舌头下的舌筋,和宝宝舌头的一些简单动作就可以大概看出来.

如果宝宝吸奶正常, 那下来还可能会遇到宝宝吐奶和呛奶的问题. 我家宝宝一般会在吃完奶过一会后吐奶, 我的解决办法是, 喂完后竖起来抱宝宝来拍嗝. 顺利的话, 稍微一拍,宝宝的嗝就出来, 但有时候拍很久都没嗝, 这时候我误以为没嗝, 把宝宝放下一会后, 她却吐奶了. 后来我发现, 如果喂奶的时候尽量让宝宝竖起来的姿势吸奶, 吃完奶后嗝很快就可以拍出来. 但是有时候拍完嗝后还是会有少量奶吐出来, 那么我怀疑有两个原因,一个是喂完奶后竖抱的时间不够长(一般的话要半个小时), 还有一个可能是宝宝吃的太多溢出来了, 那这种情况的话, 我的解决办法是少量多次, 我参考了网上的EASY程序3小时循环图.

但是这个schedule对我来说要做个小调整,因为我发现到宝宝睡觉的时候,我抱着她哄睡,她却哭闹, 我不知道她是因为没吃饱呢,还是不是真饿只是为了奶睡. 为了判断,我一般是这样, 首先每次喂宝宝的话保证宝宝吸的时间在10-15分钟, 中间可能要休息拍嗝(休息拍嗝时间不算),那么可能分2-3次喂. 但是时间够了,不代表宝宝一定吃饱了, 因为胸喂的话不知道奶的速度,所以仅靠时间判断奶量并不准确. 喂完后, 等一会看看,如果宝宝哭闹很久, 放倒胸前抱的话, 作出找奶的动作,那么可能是没吃饱, 如果只是稍微哭闹不持久的话, 那就可能不是真饿. 下来我们说下呛奶的问题. 我的宝宝一般只有在胸喂的时候奶速太急的时候会呛奶, 吐奶的时候她一般不会呛, 只是突然哭一下,然后奶从嘴角涌出来, 所以我看到她吐奶的第一反应是擦拭掉奶,防止流进耳朵. 呛奶的时候,宝宝一般会咳嗽, 然后休息几秒就好了, 我会保持她倾斜吃奶的姿势面朝上,不会去立刻竖抱起来拍, 网上也是不建议立即竖抱, 这样的话会容易把奶吸入呼吸道, 建议让宝宝侧着脸,然后轻拍宝宝背部. 但最好的话还是要避免呛奶的出现, 我的方法是, 如果知道奶速很急, 那就靠在椅子或者墙上,身体后倾, 让宝宝趴着吃, 这样宝宝就不会呛了.

大部分宝宝不能像大人那样自主入睡, 所以大人会比较辛苦. 我现在的偷懒办法是, 睡前让宝宝多消耗体力, 比如tummy time. 然后关灯放固定的催眠音乐, 抱累的话, 大人可以坐在椅子上靠后, 让宝宝趴在胸上, 身体有个角度, 这样大人也不累, 宝宝也舒服不用担心吐奶, 这样等宝宝睡着后, 就可以放下了. 我最近发现了个问题就是, 用普通的毯子给宝宝打包的话, 在抱的过程中, 尤其是竖抱的时候, 毯子会上移,遮住宝宝的口鼻, 所以我建议还是用睡袋. 为了防止宝宝睡觉过程中吐奶, 然后醒来, 我把宝宝的小床的床垫一头抬高一点,这样宝宝的床有个坡度. 等过些时间后, 再把床放平.

一个月左右的小宝宝活动能力还很有限, 能玩的东西不多, 我们家用的是下图这个可以让宝宝躺着踢上面琴键的小玩具, 踢到了就会响音乐. 上面还有些小动物造型的小挂件. 她高兴的时候还挺喜欢玩的.

最后推荐两个好用的apple watch功能, 一个是track 喂奶的时间, 一个是照明功能, 晚上胸喂的话不用起来开灯.