Initial Configuration for Eclipse

Eclipse虽老,但仍然好用,特别是对于老Java码农来说。

1. 版本选择

一般Java的Web开发,选择Eclipse IDE for Enterprise Java and Web Developers。官方下载链接如下:

2. 实用的初始化设置

1)修改默认字符集为UTF-8

windows -> Preferences -> General -> Workspace -> Text file encoding -> 选UTF-8

2)修改默认字体,改善中文显示太小

windows -> Preferences -> General -> Appearance -> Colors and Fonts -> Basic -> Text Font -> Edit -> 选Courier New

3)代码自动提示功能失效的解决方法

Window -> Preferences -> Java -> Editor -> Content Assist -> Advanced -> Select the proposal kinds contained in the 'default' content assist list -> 勾选"Java Non-Type Proposals"、"Java Proposals"、"Java Type Proposals"三个选项

4)在输错方法后仍然出现代码自动提示

Window -> Preferences -> Java -> Editor -> Content Assist -> Auto Activation triggers for java -> 改为.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

5)禁用Language Servers,提高Eclipse性能

Window -> Preferences -> Language Servers -> 取消所有勾选

6)安装插件Quick Bookmarks plugin,快速的标记和访问书签

  • 安装:Help -> Eclipse Marketplace -> 搜“Quick Bookmarks plugin”并安装
  • 使用:Alt+[数字],标记书签。Alt+Shift+[数字],跳转到书签。

Simple Example of PDF.js

工作上遇到需要在浏览器展示PDF文件,于是找到了Mozilla开发的PDF.js。玩了一下,结论是,直接使用其自带的示例是简单的方法。

主要是没找到有用的开发文档,而自己也不会Node.js的开发。所以尝试自己写的页面,只能利用HTML 5的canvas展示PDF内容。官方自带的示例,会把PDF转换成HTML,并且有显示目录、缩略图、打印、等各种实用的功能,媲美很多完整的PDF阅读软件。

这里记下写过的页面,可以翻页、放大缩小:

<h4>显示PDF</h4>
<p>
    <button id="prePage">上一页</button> <input type="text" id="curPage" value="" readonly /> <button id="nextPage">下一页</button>
    <br />
    <button id="zoomIn">+</button> <input type="text" id="zoomScale" value="1" readonly /> <button id="zoomOut">-</button>
</p>
<p>
    <canvas id="the-canvas" style="border: 1px solid black; direction: ltr;"></canvas>
</p>

<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="/js/pdfjs/pdf.js"></script>
<script>
//加载PDF按钮
pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdfjs/pdf.worker.js';//自己的路径

var loadingTask = pdfjsLib.getDocument('/pdfjs/docker.pdf'); 
var pdfDoc = null;
var totalpage = 0;
var curPage = $("#curPage");
var zoomScale = $("#zoomScale");

loadingTask.promise.then(function (pdf) {
    //加载指定界面(第一页)
    pdfDoc = pdf;
    totalpage = pdfDoc.numPages;
    getPage(1);
});

function getPage(pageNum) {
    if(pageNum < 1) {
    	pageNum = 1;
    } else if(pageNum > totalpage) {
    	pageNum = totalpage;
    }
    setCurPageNum(pageNum);
    pdfDoc.getPage(pageNum).then(function (page) {
    	//var scale = 1;
    	var viewport = page.getViewport({ scale: getZoomScale() });
    	var canvas = document.getElementById('the-canvas');
    	var context = canvas.getContext('2d');
    	canvas.height = viewport.height;
    	canvas.width = viewport.width;
    	var renderContext = {
    		canvasContext: context,
    		viewport: viewport,
    	};
    	page.render(renderContext);
    });
}

function makeThumb(page) {
    // draw page to fit into 96x96 canvas
    var vp = page.getViewport(1);
    var canvas = document.createElement("canvas");
    canvas.width = canvas.height = 96;
    var scale = Math.min(canvas.width / vp.width, canvas.height / vp.height);
    return page.render({canvasContext: canvas.getContext("2d"), viewport: page.getViewport(scale)}).promise.then(function () {
    	return canvas;
    });
}

function loadThumb() {
    var pages = []; while (pages.length < pdfDoc.numPages) pages.push(pages.length + 1);
    return Promise.all(pages.map(function (num) {
    	// create a div for each page and build a small canvas for it
    	var div = document.createElement("div");
    	document.body.appendChild(div);
    	return pdfDoc.getPage(num).then(makeThumb).then(function (canvas) {
    		div.appendChild(canvas);
    	});
    }));
}

function getCurPageNum() {
    return parseInt(curPage.val());
}
function setCurPageNum(pageNum) {
    return curPage.val(pageNum);
}
function getZoomScale() {
    return parseFloat(zoomScale.val());
}
function setZoomScale(scale) {
    return zoomScale.val(scale);
}
$("#prePage").click(function(){
    var pageNum = getCurPageNum() - 1;
    getPage(pageNum);
})
$("#nextPage").click(function(){
    var pageNum = getCurPageNum() + 1;
    getPage(pageNum);
})
$("#zoomIn").click(function(){
    var scale = getZoomScale();
    scale = Math.round((scale + 0.2) * 100) / 100;
    scale > 2 && (scale = 2);
    setZoomScale(scale);
    getPage(getCurPageNum());
})
$("#zoomOut").click(function(){
    var scale = getZoomScale();
    scale = Math.round((scale - 0.2) * 100) / 100;
    scale < 0.6 && (scale = 0.6);
    setZoomScale(scale);
    getPage(getCurPageNum());
})
</script>

Free Multi-Platform Database Tool

最近接触了两款开源、跨平台、支持多种SQL数据库的数据库管理工具,值得记录一下。

DBeaver

官网:https://dbeaver.io/

2020年疫情期间,在家办公,想找个数据库管理工具,可以在Linux上访问SQL Server数据库,于是遇到DBeaver。界面像Eclipse,容易上手;基于Java,可以跨平台使用;使用JDBC,几乎支持所有数据库。在Linux上,几乎是万能的数据库管理工具了。

HeidiSQL

官网:https://www.heidisql.com/

在Windows上安装MariaDB 10.4.12时,发现自带了HeidiSQL数据库管理工具。界面及操作都跟MySQL Workbench相似,清晰明了,而且支持各种SQL数据。比较意外的是,其基于Delphi开发,所以Linux上需要利用Wine运行。

Shunde Double-layer Milk Custard

顺德双皮奶,作为代表家乡的特色甜品小吃,一直深受本人喜爱,只是会吃不会做。近来几乎每天都买水牛奶给孩子补充营养,于是尝试做一下,原来也很简单。主要是以前错误以为第一层奶皮需要技巧弄上去,实际是物理原理,脂肪会浮在水面上。所以,只要弄到水牛奶,再简单弄一下就能吃到双皮奶了。

材料(两碗份量)

  • 水牛奶:250g
  • 蛋清:50g(大概一只鸡蛋的蛋清)
  • 糖:12g(可根据口味增减)

做法

  1. 水牛奶煮开,平均倒入两个碗内。放凉,让第一层奶皮形成。
  2. 轻轻拨开奶皮,倒出牛奶,并让奶皮留在碗里。
  3. 鸡蛋分离出蛋清和蛋黄。倒出的牛奶,加入蛋清和糖,搅拌均匀至混合。
  4. 牛奶和蛋清混合物,用筛网过滤一下(去除杂质,让口感更滑),再平均倒回两个碗里。
  5. 碗上盖上小碟子(或者保鲜膜、锡纸之类,还是小碟子比较环保)。待蒸锅水沸后,放上去蒸7到10分钟(我是8分钟)。
  6. 蒸好后,放凉到接近体温再食用。夏天可以放冰箱冷藏后食用。

Unpleasant Experience with Motion Photo

Google Camera(简称gcam)自推出以来,一直是最喜爱的摄影应用(可惜后来变成Pixel机型专属应用)。幸好有开发者移植到其它机型,特别是像红米Note 4X那种渣拍照的手机,极大提升了拍照能力。近来在红米K30 5G上也装上了gcam,并默认开启了“动态照片(Motion Photo)”功能。本来没啥影响,只是拍出来一堆文件名以MVIMG开头或者扩展名前带有“.MP”的照片,昨天好奇研究了一下,才发现就是动态照片。

动态照片,简单来说,就是把拍照前几秒录下视频,并把视频与拍出来的照片整合在一起,生成一个jpg文件。目前发现两种格式:文件名后面带有“.MP”的,在EXIF信息里会说明mp4文件在整个jpg文件中位置;文件名以“MVIMG_”开头的,jpg文件里有个“ftypmp4”标识,该标识后面的数据就是mp4文件。

其实动态照片也没什么坏处,但是找了一圈也找不到可以直接浏览动态图片的Android应用。如果是看不到的视频,那保存在照片中,有什么意义?还浪费了存储空间,也不利于分享、传输。最后找了个工具,叫GoMoPho,把所有拍摄的动态照片都转为普通jpg文件。其实就是把动态文件切割为jpg和mp4两个文件,我保留了jpg并删除了mp4。GoMoPho的相关网址如下:

GoMoPho虽然只有命令界面,但是支持上面提到的两种动态照片,而且已移植到多种操作系统,还能支持批量处理文件夹的文件。

Simple Recipe for Portuguese Tart

这是个简易葡挞食谱。网上的视频看到的,简易的地方是,利用比葡挞皮更容易买到的手抓饼来做。试着做了一下,并修改了材料份量,效果还不错。

材料(做6个的份量)

  • 原味手抓饼 1块
  • 鸡蛋 1个
  • 牛奶 80克
  • 白糖 15克

做法

  1. 制作挞皮。手抓饼解冻,卷起来,平均切成6份。搓圆,摊在蛋挞模具上,做成碗状。
  2. 制作挞液。鸡蛋打散,加入牛奶和白糖,搅拌至白糖融化。然后过筛,去除杂质,带来更细滑的口感。
  3. 挞皮倒入挞液,8分满即可。挞液会在烤的时候涨起,太满会溢出,导致挞皮容易糊。
  4. 烤箱预热10分钟,200摄氏度中层烤20分钟。挞皮金黄,挞液有焦糖色,即可出炉。

总结

  1. 鸡蛋尽量选小的,如果是比较大的鸡蛋,要减少牛奶的份量。
  2. 手抓饼一定要选原味的。毕竟没人想吃带葱的葡挞吧。
  3. 出炉后,要放凉一下才能吃。主要是怕烫嘴(笑)。

Roasted Chestnuts

今天烧烤时,顺便烤了板栗,非常成功!记录一下经验吧。

材料

  • 小板栗 120g左右(一人一次的份量)

做法1

  1. 小板栗洗干净,用刀切个开口,大概二分之一周长。一般用刀砍下去,板栗没有分成两半,而是粘在刀上,就可以了。砍板栗的教程,具体可以参考李子柒于2020-10-10发布关于中秋节的视频,在12:46处(笑)。
  2. 开水里煮10分钟。
  3. 从水中捞出放烤盘里,烤箱预热后,以190摄氏度烤10分钟。注意不要烤糊,烤到板栗外壳干脆即可,这样更容易剥开。
  4. 这个做法,可以用微波炉代替烤箱。但是板栗处理不好的话,容易爆炸(喷得微波炉内壁到处都是板栗碎),不推荐。

做法2

  1. 小板栗洗干净,用锡纸包好。用竹签戳一个小洞,用于排气。
  2. 放在碳炉(烧烤炉)上,大概烤半个小时到1个小时。
  3. 由于锡纸把板栗里的水分都锁住,所以做出来不会变得太硬,非常好吃。

注意

  1. 选用个头小的小板栗,是因为更容易熟,做起来少费点时间。
  2. 板栗一次不能多吃。其淀粉含量比较高,多吃容易导致消化不良(例如放屁量增多)。

Resurrection Remix OS for Redmi K30 5G

作为MIUI恐惧者,无奈LineageOS官方没有支持这台红米K30 5G,只能诚惶诚恐地使用欧版MIUI。直到某天发现了Resurrection Remix OS官方支持这款手机,才终于脱离MIUI。

查了资料,才知道Resurrection Remix OS是基于LineageOS的一款开源ROM,基本体验与LineageOS一致,并增加了很多设置(基本上是界面的,个人感觉用途不大),适合喜欢原生Android的用户。

LineageOS的优点基本继承了,总结一下缺点吧:

  1. 国内支付应用,基本不能使用指纹支付。历史原因,一直遗留下来的问题。跟LineageOS一样。
  2. 关屏后不能双击屏幕打开锁屏界面
  3. 不能双击桌面锁屏。可以设置双击任务栏或者三大金刚键进行锁屏。
  4. 不能拍摄6400万像素的照片。ROM自带相机和Google Camera移植版,最高都只支持1610万像素。不过即使是MIUI的自带相机,拍出来的6400万像素照片基本直出(纯粹自我安慰)。
  5. 刚开始使用,比较耗电。做了一些优化后,后面变得相对省电一点。不过,这手机本身也不怎么省电。
  6. 长时间使用的应用,容易自动退出。比如Chrome开个视频后,很大几率会自动关掉并回到桌面。可能是电源管理自动优化吧。

总的来讲,曾经的LineageOS用户可以放心刷,也没有遇到影响日常使用的bug 。

刷机过程,跟LineageOS一样。重点还是那句:刷机前先备份好数据。Recovery备份分区(刷机失败时可以还原系统) + Ti Backup备份应用(用于迁移应用及数据)。

1. 下载相关数据

2. 刷机

  • 备份数据。最好连sdcard的数据也备份一下
  • wipe手机,即Recovery格式化data分区
  • 解锁、刷recovery
  • 刷ROM
  • Recovery里Root系统
  • 刷Opengapps
  • 清cache
  • 重启进入系统

要注意,进入系统后,需要连Google验证。

3. 耗电优化的处理

当前的节电设置如下:

  • a)屏幕刷新率设为 60Hz,在“设置”->“系统”->Device-specific settings->Minimum Refresh Rate。120Hz屏幕其实很丝滑,但60Hz确实够用。
  • b)关闭 5G 网络,只用 4G 。设置移动网络的首选网络类型为“LTE/WCDMA”。当前来说,5G除了耗电比较快,没感受到什么优势。
  • c)限制应用使用电量。在电池管理器设置受限应用。目前设了 Google Play 商店。
  • d)关闭 Google 账户的自动同步功能,只开启了 Chrome 和 Gmail 。
  • e)冻结了一些不常用但不可缺的应用。冰箱、Shelter 、island 等。其中 island 的名称太中二,个人接受不了而放弃。用 Shelter 的话,如果工作空间的应用没用到 GMS,最好冻结它,并尽量安装非无依赖 GMS 的应用。

Overnight-Dried Fish (Ichiya-boshi)

动画《放学后海堤日记》第10集,提到吃不完的竹荚鱼做成“一夜干”(いちやぼし),不仅很好吃,还能提高存储时间。对这个做法很好奇,于是周末试了下,果然很惊艳!

虽然一夜干可以用新鲜鱼和冰鲜鱼,但是为了避免失败而造成的浪费,选用了太阳鱼(无细骨的淡水鱼)。最后烤制时,用了烤箱代替炭炉。

材料

  • 太阳鱼 1条
  • 清水 300ml
  • 盐 30g
  • 料酒或米酒 适量

做法

  1. 太阳鱼削鳞,从背部开刀,去鳃、清理内脏、清理黑膜,清洗干净。
  2. 清水和盐配成10%浓度的盐水,放入鱼,浸泡30分钟到1小时。盐水放入适当的料酒或米酒,可以去腥。
  3. 从盐水取出鱼,用厨房纸吸干表面水份,放入冰箱冷藏过夜。目的是风干鱼肉。冬天可以放室外风干,夏天只能放冰箱。放冰箱的话,鱼的腥味可能会充满整个冰箱,而盐水放入酒来去腥,可缓解这一问题。
  4. 从冰箱取出鱼,再次吸干表面水份。烤箱最高温度(我的是230°C)预热10分钟后,把鱼放最上层,烤大约20分钟,烤至表面金黄即可。烤的过程要适时翻面。鱼皮那面先朝上来烤,再翻面,可以烤出完整的鱼皮。

由于浸泡盐水、风干和烤炙,鱼肉的水份大部分流失,使得鱼的鲜味浓缩,所以吃起来味道很棒!

后记

  1. 试过太阳鱼、泥鯭、立鱼(䲞鱼)。立鱼本身油脂丰富、鲜味足,应该是目前出品味道最好的,其次是太阳鱼。泥鯭肉质太柴,且油脂不足,不推荐。
  2. 做法试过烤箱、电烤盘、炭烤,其中炭烤应该是最棒的。理论上,平底锅香煎也是可以做。
  3. 用烤箱的话,鱼身最好插入长竹签,方便烤制过程中翻面。炭烤的话,不推荐插入竹签,因为竹签容易烤糊甚至着火。

Redmi K30 5G

由于贪便宜,上一部手机红米Note4x(代号:mido)买了3G内存+32G存储的版本,导致用了两年半就内部空间不足。即使插上128GB的TF卡,并转为内部存储,也要面对偶尔出现的SD卡错误,导致装在卡上的应用不能运行。抓狂……然后CFO的批准下,一起换了红米K30 5G(代号:picasso)。

这个时间点,要换手机,就肯定选5G网络的了。然后,考虑高性价比,能解BL锁,能刷第三方ROM,就剩下红米了。最后在K30i 5G与K30 5G之间,选择了拥有主摄6400万像素的K30 5G。低配版6GB + 128GB,目测用3年应该没问题。

关于此手机的一切说明,可以参考这个文章:

按照文章的刷机操作,就是手机绑定小账号、解BL锁、刷recovery、刷欧版MIUI、折腾流氓应用。但是解锁后直接刷最新版Recovery,进去时会黑屏。参考了网上的经验分享,需要先刷旧版Recovery,然后刷ROM,再刷新版Recovery。由于该Recovery自带Magisk,所以不用单独下载。相关软件如下:

1)小米官方解锁工具

2)非官方TWRP Recovery

旧版:TWRP-3.4.0B-0209-REDMI_K30_5G-CN-wzsx150-fastboot 目前最新版:TWRP-3.4.2B-0623-REDMI_K30_5G-CN-wzsx150-fastboot

3)欧版MIUIv12

简单的刷机流程是:刷旧版Recovery,格式化Data分区,刷入欧版MIUI,双清,在Recovery刷入最新版Recovery后,再进入Recovery进行root,重启进入系统。

刷完欧版ROM,我选择了冰箱(主要冻结无用的系统App,曾经买了付费版) + Island(主要是使用工作空间隔离流氓App,并且能进行冻结)结合使用。由于Shelter不能在MIUI上运行,只能暂时使用Island(缺点是没有自动冻结,用起来没有Shelter顺手)。

用了一段时间,一开始感觉是比较耗电,渐渐感觉跟红米Note4x差不多。已调低屏幕刷新率60mHz,没什么感觉。玩过Minecraft,手机发烫比较严重,耗电也比较快。

希望后面能刷上LineageOS。但是XDA-Developers上的网友说,小米官方一直没更新这手机的kernel源码,导致第三方系统不能完善。目前也就先这样了。


后记 2023-06-22

不经不觉三年了。这手机的缺点总结如下:

  1. 重。贴上“钢化玻璃膜”和插上两个SIM卡,K30 5G整体重量超过220g。对比红米 Note4X是170g。
  2. 玻璃后盖容易碎。
  3. 5G网络“鸡肋”。开了5G网络,除了流量飞快,还容易发热。而且室内一般没信号,自动切换到4G。直接后果是耗电。
  4. 后置主摄6400万像素,可以说是欺骗。由于传感器是SONY IMX686,采用4合1像素,一般相机应用只能识别成1600万像素。只有MIUI自带的相机应用才能拍摄出6400万像素的照片。
  5. 可刷的开源ROM较少。没办法,毕竟不是销外国际的机型。