升级Mac OS X的php到8.0,并设置apache2去使用它

问题描述

最近想在本地安装mediaWiki,目前版本是1.36。Macbook自带的php版本是7.3.11,然后出现以下error:

MediaWiki 1.36 requires PHP 7.3.19 or higher; you are using PHP 7.3.11.

于是就干脆升级PHP到8.0。本文记录一下怎样在Mac OS X (Catalina)上安装PHP 8.0。

安装PHP 8.0

使用Homebrew

brew install php

目前brew里面默认版本就是8.0。homebrew的安装目录在/usr/local/Cellar/ 下面。安装完后系统默认的仍然是7.3。

% which php
/usr/bin/php

% php --version
PHP 7.3.11 (cli) (built: Feb 29 2020 02:50:36) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.11, Copyright (c) 1998-2018 Zend Technologies

需要

$ brew services start php

这样brew会设置好新版本路径

% which php
/usr/local/bin/php

% php -version
PHP 8.0.10 (cli) (built: Aug 26 2021 15:34:04) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.10, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.10, Copyright (c), by Zend Technologies

设置Apache2

编辑httpd.conf,用mvim或其他编辑器,需要sudo权限

% sudo mvim /etc/apache2/httpd.conf

添加

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

<IfModule dir_module>
#old:
#   DirectoryIndex index.html
#new:
    DirectoryIndex index.php index.html
</IfModule>

#old: LoadModule php7_module libexec/apache2/libphp7.so
#new:
LoadModule php_module local/opt/php/lib/httpd/modules/libphp.so

重启apache2

sudo apachectl restart

算法练习 力扣 150. Evaluate Reverse Polish Notation

问题总结

这题比较简单,如果学过computer architecture,这个Reverse Polish Notation (RPN)基本就是个stack machine。很像汇编语言。用stack就可以解决。

除法要求

that division between two integers should truncate toward zero.

测试数据里面有负数, python里面整数除法结果如果是小数,约成整数后是往小的方向约的。比如-0.4会变成-1,题目要求往0约,也就是-0.4变成0。用int(a/b)可解决。一个冷门知识。

Python解法

class Solution:
    def evalRPN(self, tokens: List[str]) -> int:
        stack = []
        ops = {'+', '-', '*', '/'}
        for token in tokens:
            if token not in ops:
                stack.append(int(token))
            else:
                op = token
                num2 = stack.pop()
                num1 = stack.pop()
                res = self.evalSimple(num1, num2, op)
                stack.append(res)
        
        return stack.pop()
                
    def evalSimple(self, num1, num2, op):
        if op == '+':
            return num1 + num2
        elif op == '-':
            return num1 - num2
        elif op == '*':
            return num1 * num2
        elif op == '/':
            return int(num1 / num2)    

用with关键词来简化presto queries

最近学到的,使用with来简化query,用起来想先create一些临时的table,这样可以避免写嵌套的subqueries。效果应该是一样的

例子如下:

with temp1 as (
  select a, b from table1
),
temp2 as (
  select c, d from table2
)
select 
  temp1.a,
  temp2.c
from 
  temp1
join
  temp2
on 
  temp1.b = temp2.d

安装IBKR python API

IB官网下载最新API,选Software: TWS API,然后”I Agree” License aggreement。然后选平台,比如TWS API Latest for Mac / Unix。

https://www.interactivebrokers.com/en/index.php?f=5041

cd 到下载地址。

unzip twsapi_macunix.985.02.zip

根据README.md里说的

python3 setup.py sdist
python3 setup.py bdist_wheel
python3 -m pip install  --upgrade dist/ibapi-9.85.2-py3-none-any.whl

具体版本可能有点不一样。我安装的时候README.md里的版本有点过时,不是下载的现有版本。

安装完成后就可以读User’s Guide了。

算法练习:有版本号的key-value store

要求

写一个kv store,需要实现按版本查找的method,简单的每次take新snapshot,就把map复制一次,放到list里面,这样按版本找可以实现O(1)。如果想省空间可以次snapshot只存diff。查的时候要把每个snapshot都查一次,就变成O(num_snapshots)。

Python 实现

class kvstore:
    def __init__(self):
        self.store = {}
        self.snapshots = []
        self.changed_keys = set()

    def set(self, k, v):
        self.store[k] = v
        self.changed_keys.add(k)

    def get(self, k):
        return self.store.get(k, None) 

    def snapshot(self):
        d = {}
        for k in self.changed_keys:
            d[k] = self.store[k]
        self.snapshots.append(d)
        self.changed_keys = set()
        return len(self.snapshots) - 1

    def get_from_snap(self, snap_version, key):
        for version in range(snap_version, -1, -1):
            if key in self.snapshots[version]:
                return self.snapshots[version][key]
        return None

store = kvstore()
store.set("k1",  "v1")
store.set("k2", "v2")

assert store.get("k1") == "v1"

last_snapshot = store.snapshot()
assert last_snapshot == 0
assert store.get("k1") == "v1"
assert store.get_from_snap(last_snapshot, "k1") == "v1"
assert store.get_from_snap(last_snapshot, "k2") == "v2"
assert store.get_from_snap(last_snapshot, "k3") == None

last_snapshot = store.snapshot()
assert last_snapshot == 1
assert store.get("k1") == "v1"
assert store.get_from_snap(last_snapshot, "k1") == "v1"
assert store.get_from_snap(last_snapshot, "k2") == "v2"
assert store.get_from_snap(last_snapshot, "k3") == None

store.set("k3", "v3")
store.set("k2", "k2-1")
last_snapshot = store.snapshot()
assert last_snapshot == 2
assert store.get("k1") == "v1"
assert store.get_from_snap(last_snapshot, "k1") == "v1"
assert store.get_from_snap(last_snapshot, "k2") == "k2-1"
assert store.get_from_snap(last_snapshot, "k3") == "v3"

在Mac OS上安装Apache2, PHP, MySQL

最近想在Mac上装个wordpress,自然得先安装Apache2, PHP, MySQL。

简单科普一下这些软件

Apache:Web server, 处理http请求
PHP: 用来写网站逻辑的语言
MySQL: 数据库

WordPress就是一个用PHP写得程序,用PHP写的逻辑决定怎样处理http request,而数据就写在MySQL里面。

本来还想着用MAMP,这个是我很多年前用过的一个Mac软件,做个个界面打包管理以上软件。最近发现改成收费的了。于是Google一下直接在Mac OS上手动安装,毕竟Mac OS就是UNIX,不会太难。结果发现Mac OS基本都自带了。MAMP彻底没什么用了。

本文用的是Mac OS Catalina。

Apache2

启动Apahce2

% sudo apachectl start

浏览器打开http://localhost/,确认工作。

让Apache2可以使用PHP

cd /etc/apache2
cp httpd.conf httpd.conf.backup

编辑文件,

% sudo mvim httpd.conf

把下面这行的注释取消(删除开头的“#“)

LoadModule php7_module libexec/apache2/libphp7.so

重启Apache2

% sudo apachectl restart

找到Document Root。Document Root就是硬盘上存放html或者PHP文件的地方。

% grep DocumentRoot httpd.conf
# DocumentRoot: The directory out of which you will serve your
DocumentRoot "/Library/WebServer/Documents"
    # access content that does not live under the DocumentRoot.

可见Mac OS里document root在/Library/WebServer/Documents。

测试PHP正常工作

% cd /Library/WebServer/Documents
% sudo mvim phpinfo.php

phpinfo.php内容如下

<?php phpinfo();

然后打开网页http://localhost/phpinfo.php测试,能看到显示PHP信息就表示成功了。

Mac OS下安装MySQL

MySQL官网下载。我下的是这个

打开dmg文件以后运行里面的pkg文件安装。中间需要给root设置密码。

安装目录在

/usr/local/mysql

确定mysql server正在运行

ps aux | grep -i mysqld

方便起见,需要把mysql命令加到PATH里面。编辑.zprofile

% mvim ~/.zprofile

添加下面一行

PATH=/usr/local/mysql/bin:$PATH

新开一个terminal,测试用mysql client登陆

mysql -u root -p

输入安装时设置的root密码,登陆进去后尝试

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

能看到返回说明安装成功。

参考资料

本文参考了这篇英文博文。写得非常清楚,我添加了一些细节。作者Jason McCreary,他的网页里有很多很好的技术文章,值得收藏。

在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)
    );
}

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>

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

照顾新生儿的经验总结

照顾新生儿的经验总结

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

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

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

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

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

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

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

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