win11 家庭版开启远程登录
1. 开启 rdp
参考:https://www.cnblogs.com/ministep/p/15829494.html#41__55
2. vnc
服务端安装 tightvnc, 试了tigervnc 和 utralvnc 都不太稳定
客户端用 realvnc 或者 utralvnc, tightvnc
参考:https://www.cnblogs.com/ministep/p/15829494.html#41__55
服务端安装 tightvnc, 试了tigervnc 和 utralvnc 都不太稳定
客户端用 realvnc 或者 utralvnc, tightvnc
unarto/share-ssr-v2ray-ss-akun - https://github.com/unarto/share-ssr-v2ray-ss-akun
hwanz/SSR-V2ray-Trojan-vpn: 免费白嫖公益机场合集SSR-V2ray/免费vpn-定时更新 - https://github.com/hwanz/SSR-V2ray-Trojan-vpn
最新SSR/V2ray专线机场推荐与评测(2022.03更新) - ssrv2ray - https://hwzhwz.github.io/posts/8c826425.html
jichangjiedian/README.md at c4bef7829bf424b012ee5debc3e04966aed43bd0 · sqlemma/jichangjiedian - https://github.com/sqlemma/jichangjiedian/blob/c4bef7829bf424b012ee5debc3e04966aed43bd0/README.md
free-ssr-v2ray/README.md at 2fd01d5967fd7d22131f55155cf6d8d3b86d16d9 · honven/free-ssr-v2ray - https://github.com/honven/free-ssr-v2ray/blob/2fd01d5967fd7d22131f55155cf6d8d3b86d16d9/README.md
jichangjiedian/README.md at main · sqlemma/jichangjiedian - https://github.com/sqlemma/jichangjiedian/blob/main/README.md
最近写了一些 markdown, 在 vscode 上感觉一般的纯文本文档写起来还是比较舒服的,但是如果有表格编辑起来就比较麻烦了,排版很困难,于是想起了最近很多基于 electron/nwjs 的所见即所得的 markdown 编辑器,比如 typora, marktext 等等, 如果在 vscode 中实现类似功能编辑起来就很方便了。
于是便写了这个插件:
插件地址: https://marketplace.visualstudio.com/items?itemName=zaaack.markdown-editor
源码地址: https://github.com/zaaack/vscode-markdown-editor
基于强大 vditor 项目,vscode 端并不需要多少代码即可拥有众多 feature:
项目 | 简介 |
---|---|
utools | 启动器,Alfred 替代品 |
PxCook | sketch 预览工具,除此还有Sketch Measure, zeplin,蓝湖… |
httppie | http client 命令行工具 |
softmaker-office | mac上启动最快的 office 套件 |
LICEcap | mac 上压缩率最高的gif录屏软件 |
稻壳阅读器 | 高性能 pdf/epub 阅读器 |
magicanrest | 定时锁屏休息 |
坚果云网盘 | 文件同步 |
sqltab | 免费聚合数据库客户端 |
deskscreen | 把手机/pad 等设备变成扩展屏幕(跨平台) |
espanso | 跨平台的系统全局snippets,文本快捷输入,支持 emoji |
tinycal 小历日历 |
项目 | 简介 |
---|---|
lunacy | win10打开编辑sketch文件 |
WSLHostPatcher | wsl2 服务在局域网可访问 |
openhardware/coretemp | cpu温度监控 |
mouseinc | 鼠标手势+触发角 |
stretchly | 20分钟锁屏休息20s |
Monitorian | 外接显示器亮度修改 |
macast | dlina流媒体投屏接收软件 |
RevokeMsgPatcher.v1.7 | qq/微信防撤回 |
TrafficMonitor | 流量监控 |
猫影绿色免安装1.0.7_fix2 | |
ProjectEye | 护眼提醒 |
wsa工具箱 | wsa安卓工具箱 |
Clash (设置里的LoopbackManager) | 代理(uwp应用设置) |
ScreenToGif | 高压缩最小的 gif录屏软件 |
xdown | 下载器 |
zyplayer | 影视 |
geek uninstaller | |
项目 | 简介 |
---|---|
local-cors-proxy/npm | 本地反向代理服务添加 cors header |
caddy | go版 反向代理服务器 |
NeatDownloadManager | 多线程下载工具 |
xdown | bt下载工具 |
spacedesk | 屏幕扩展 |
项目 | 简介 |
---|---|
Postern | 代理切换 |
项目 | 简介 |
---|---|
excalidraw | 手写样式的流程图 |
perfect-freehand | 毛笔画图 |
draw.io | 在线流程图 |
figma | 在线原型图, 可以导出svg |
alternativeto.com | 替代品查找网站 |
asciiflow | 基于文本的流程图 |
tool.lu | 程序员工具箱 |
在线接码 | 临时手机号用于注册小号 |
photopea | 在线ps, 支持导入 sketch 预览,不过只能看图 |
tailscale.com | 免费vpn组网,支持远程访问内网机器 |
ss | 机场推荐 |
项目 | 简介 |
---|---|
bookzz | 电子书下载 |
bookrix | 电子书下载 |
z-library | zlibrary电子书 |
项目 | 简介 |
---|---|
gitpod.io | 在线开发环境, db/IDE/shell 等 (开源免费) |
poshover | 推送服务 |
微信绑定qq邮箱发邮件 | 同上 |
Server 酱/喵提醒/Telegram 订阅/钉钉机器人 /PushPlus/gotify/ddpush | 同上 |
vercel/netlify | 云服务serverless |
小米球 钉钉内网穿透 nat123 | 内网穿透 |
ghproxy/toolwa | github下载加速 |
zellij | tmux 替代品,界面更友好,对鼠标支持更好 |
项目 | 简介 |
---|---|
vip视频解析 | |
网盘聚合搜索 | |
v视频下载 | |
downsub | 下载YouTube字幕 |
https://www.youtubemy.com (网友自荐,还不错),可用 | youtube 视频下载 |
https://pickvideo.net/(被河蟹,需要爬梯子) -》 | 同上 |
https://bitdownloader.com/en2 | 同上 |
http://www.clipconverter.cc/ ( | 同上 |
http://fetchvideo.com/ (正常) | 同上 |
mkvtoolnix | 最快的字幕封装工具,将字幕导入到视频 |
ZY-Player | 全网视频客户端 |
SVG 的 text 标签是不支持自动换行的,但是如果想用 svg 作为一个画图模版还是需要文本换行。这个组件可以自动对 svg 节点进行截断,支持 tspan 单独设置样式,比如改变颜色啥的,但是暂时不支持 tspan 改变文本宽度,因为用的是别人写的测量宽度的包。本来这个作者也有个换行组件的,但是看源码发现不支持中文,所以写了这个组件。
用法:
<AutoText
width={50 / 375 * window.innerWidth} // width should be 'px'
x={47} // x, y can be svg coordinate
y={337}
fill="#494949"
fontFamily="SourceHanSerif-Regular, Source Han Serif"
fontSize={13}
fontWeight="normal"
lineSpacing={30} // or line-height
spans={[
'Helllo,',
{ tag: 'tspan', text: 'Amy', props: { fill: '#B09148' } },
', ',
'what can I do for you?',
]}
/>
import 'core-js/fn/set'
import 'core-js/fn/map'
import React from 'react'
import svgTextSize from 'svg-text-size';
const rightSymbols = new Set(
'“‘[「【﹝〔<‹«{『((<《'.split('')
)
const leftSymbols = new Set(
',,,!!??”\]」】》>’»﹞〕〗〉}))』'.split('')
)
const toggleSymbols = new Map([
['\'', 'right'],
['"', 'right'],
])
// Takes a string, and a width (and svg attrs, if they apply), and returns
// an array of lines, representing the break points in the string.
const textWrap = (text, width, attrs, doc = document, {
_leftSymbols = leftSymbols,
_rightSymbols = rightSymbols,
_toggleSymbols = toggleSymbols,
}) => {
let words = []
let toggleMap = new Map()
for (let i = 0; i < text.length; i++) {
const char = text[i];
if (_rightSymbols.has(char)) {
words.push(char + text[i + 1])
i += 1
} else if (_leftSymbols.has(char)) {
words[words.length - 1] += char
} else if (_toggleSymbols.has(char)) {
let isRightStart = _toggleSymbols.get(char) === 'right'
if (!toggleMap.has(char)) {
toggleMap.set(char, isRightStart ? 'right' : 'left')
}
let stickyDirection = toggleMap.get(char)
if (stickyDirection === 'right') {
words.push(char + text[i + 1])
i += 1
} else {
words[words.length - 1] += char
}
toggleMap.set(char, stickyDirection === 'left' ? 'right' : 'left')
} else if (/^\w+$/.test(char)) {
let last = words[words.length - 1]
if (/^\w+$/.test(last)) {
words[words.length - 1] += char
} else {
words.push(char)
}
} else {
words.push(char)
}
}
let lines = [];
let currentLine = [];
words.forEach(word => {
const newLine = [...currentLine, word];
const size = svgTextSize(newLine.join(''), attrs, doc);
if (size.width > width) {
lines.push(currentLine.join(''));
currentLine = [word];
} else {
currentLine.push(word);
}
});
lines.push(currentLine.join(''));
if (lines[0] === '') { lines.shift(); }
return lines;
};
function getReactAttr(attrs) {
let newAttrs = {}
for (let key in attrs) {
let val = attrs[key]
key = key.replace(/([A-Z])/g, s => '-' + s.toLowerCase())
switch (key) {
case 'font-size':
case 'line-spacing':
case 'letter-spacing':
if (typeof val === 'number') {
val += 'px'
}
break;
default:
break;
}
newAttrs[key] = val
}
return newAttrs
}
/**
\```
props: {
spans: [
"some text",
{ tag: 'tspan', text: 'some text', props: { } }
],
width: 100,
x: 0,
y: 0,
}
\```
*/
export default class SVGAutoText extends React.PureComponent {
getAttrProps() {
const {
spans, width, x, y,
leftSymbols, rightSymbols, toggleSymbols,
...props } = this.props
return props
}
getWrappedSpans() {
let spanSlices = []
let startIdx = 0
let fullText = ''
let spans = this.props.spans.map(
span => {
if (!span.tag) {
return {
tag: 'tspan',
text: span ? span + '' : '',
props: null,
}
}
span.text += ''
return span
}
)
for (const span of spans) {
let end = startIdx + span.text.length
spanSlices.push({
...span,
start: startIdx,
end,
})
startIdx = end
fullText += span.text
}
let globalProps = this.getAttrProps()
let lines = textWrap(fullText, this.props.width, getReactAttr(globalProps), this.props)
let tspans = []
let lineIdx = 0
let lineLen = 0
let sliceIdx = 0
let sliceLen = 0
let lastLine = -1
let { x: offsetX = 0, y: offsetY = 0 } = this.props
let lineHeight = parseInt(globalProps['lineSpacing'] || globalProps['lineHeight'], 10)
let fontSize = parseInt(globalProps['fontSize'], 10) || 16
function makeTspan(text, props, lineIdx) {
let x = lastLine === lineIdx ? void 0 : offsetX
lastLine = lineIdx
return (
<tspan
key={tspans.length + text}
{...props}
x={x}
y={lineIdx * (lineHeight ? lineHeight : fontSize * 1.4) + offsetY}
>
{text}
</tspan>
)
}
for (const line of lines) {
lineLen += line.length
while (sliceLen < lineLen && sliceIdx < spanSlices.length) {
let slice = spanSlices[sliceIdx]
tspans.push(makeTspan(slice.text, slice.props, lineIdx))
sliceIdx++
sliceLen += slice.text.length
}
if (sliceLen > lineLen) { // break slice
let lastSlice = spanSlices[sliceIdx - 1]
let text1 = lastSlice.text.slice(0, lastSlice.text.length - (sliceLen - lineLen))
let text2 = lastSlice.text.slice(text1.length)
tspans.pop()
tspans.push(makeTspan(text1, lastSlice.props, lineIdx))
tspans.push(makeTspan(text2, lastSlice.props, lineIdx + 1))
}
lineIdx++
}
return tspans
}
render() {
return (
<text {...this.getAttrProps()}>
{this.getWrappedSpans()}
</text>
)
}
}
z at ZsMBP in ~/Projects/ReactXP/reactxp/samples/TodoList (master●)
$ react-native run-android
Scanning 740 folders for symlinks in /Users/z/Projects/ReactXP/reactxp/samples/TodoList/node_modules (7ms)
JS server already running.
Building and installing the app on the device (cd android && ./gradlew installDebug)...
Could not install the app on the device, read the error above for details.
Make sure you have an Android emulator running or a device connected and have
set up your Android development environment:
https://facebook.github.io/react-native/docs/android-setup.html
这个错误的解释废话太多,还是错的, 其实手动运行下命令cd android && ./gradlew installDebug
就会发现是./android/.gradlew
这个文件没有执行权限导致的,运行一下
chmod +x ./android/.gradlew
就可以了
之前的框架是 full-stack 的,最近需要帮以前工作室的学妹弄一个简单的 h5 页面时才发现,自己居然手头没有一套靠谱的纯粹配置,如果从其他项目中剥离出来又实在提不起兴趣,于是下了官方的 create-react-app, 发现各种问题,比如
无法适应大型项目,和我理解中的只是用来写 demo, 或者简单页面的脚手架差不多。临时看了一下 styled-components, 发现这货比我想象的要高级,支持嵌套语法,auto-prefixer, 既然是 css-in-js,那么动态复用就完全不用担心了,更让我惊艳的是工具链的支持,在 atom 中,基本上必装的 language-babel 插件已经默认支持了,在 js 中也可以享受到强大的 css 提示。
于是在 create-react-app + styled-components 的组合下写起展示类页面来体验也挺不错的。
不过,没有一套自己常用的纯前端的脚手架总感觉心里不太安稳,而且转眼过去大半年了,webpack2, react-hot-loader v3 已经是正式版了,个人也积累了一些不错的库,于是便打算再折腾一个最新的脚手架。
作为一名合格的「前端配置工程师」,每半年~一年升级一次配置才能紧跟前端的潮流。。
先放代码:https://github.com/zaaack/react-starter.git
这里主要记录一下猜到的坑。。
毫无悬念,虽然之前有过成功配置 react-hot-loader 的经历,而且那时也是 v3,只不是是 v3-beta, 现在是 v3 正式版,但是还是在这里卡住了大部分时间…
其实官方的两个 demo 已经是非常友好的了,
webpack2 官方也有一个教程,不过需要注意的是 babel-preset-es2015 的参数配置有点老了,具体可以参考上面的 react-hot-loader-minimal-boilerplate
不过 react-hot-loader 还是太 hack了点,很多地方都需要加 patch,不仅仅是在 entry 中,babel presets 中也要加。开始时就是忘了加 babel presets 中的 react-hot-loader/babel
, 导致虽然 log 正常,但是却完全没反应。没有报错提示无意是最难调试的了,只能去翻源码以及在源码中加 log。
发现之后加上去了,但是还是老样子,到底是哪里有问题呢?经过反复耐心测试才发现居然是少了 babel-polyfill, 而且还不能使用 babel-transform-runtime, 虽然之前的配置中 可以通过对 transform-runtime 加 {polyfill:false} 参数使之共存,但是这个 trick 貌似在最新版中不能用了,不过没关系,可以通过 NODE_ENV 区分啊,大不了 开发环境就不加嘛。
可是这样还是不行,不过还好在反复实践中发现
虽然 webpack 中配置了 babel, 但是还是会去读取 .bablerc 文件,在翻 babel-loader 的源码时在文档中成功找到了相关依据,改了一个配置就搞定了。。此时 react-hot-loader 所有的坑都已填满,可以放心食用了。。
其实之前一直都没写过 react 测试,老实说除了一些基础 node 库之外,我还没在业务代码中写过测试呢,更不用说 UI 测试了。。所以这次就干脆把测试也加上了。React 自带了 react-dom/test-utils
,不过 API 太过冗长,Facebook 自己都不用, 参考了下阮老师的这篇, 发现很多 demo 都跑不起来了,倒不仅仅是因为接口的变动,更坑的是 bug…bug.
比如 renderIntoDocument
这个方法,最新的 react 已经去掉了返回值,就算看源码自己用 callback 实现也不行,因为我就尝试了,callback 也没有返回值了!连之前 callback 可以用的 this
也变成 null 了。。所以要么直接用 document,要么用 airbnb 的 enzyme, 考虑到写测试是一件很痛苦的事情, 而且
enzyme 的接口其实和 jquery 很类似,目测挺方便的,本着不给自己添麻烦原则,就只能牺牲一下硬盘空间了。。我的 node_modules 目录已经快撑爆了吧。。
然而,随便给 demo 代码写了点 测试,想点击一个 react-router 的 Link 实现跳转,死活没反应。在 js-dom 的官方 readme 上看见了巨大的 “不支持跳转” 的说明,好吧,这很好解决,加个 NODE_ENV=test
换成 createMemoryHistory
不就可以了,issue 中也有类似的解决方案。可以还不行!!!一样的没有任何报错,任何反应(可见良好的错误提示是多么重要)。无聊之下又开始翻源码,打 log, 可以确定事件是触发了的,于是又去看 react-router 的 Link 组件,打 log, 终于发现是 因为 Link 中为了确保是鼠标左键点击做了 event.button === 0
的判断,而 jsdom 中的 MouseEvent.button === undefined
, 并且是个老 issue 了,果断再来一发。
至于 Facebook 官方的测试框架 jest 强大的 snapshot 功能,可喜的发现 AVA 已经 内置了,使用非常方便,就不细说了,直接看代码和官方文档吧。
恩,至此所有坑已填完,可以上传 repo 了。是的,这篇文章其实不是什么分享,只是单纯的吐槽,解决这些坑其实几乎毫无价值,半年之后,可能有些修了,可能又会有新的 bug。。人生苦短,且行且珍惜,所以半年更新一下配置,又可以保持一下自己的折腾能力了。。
最后,再来安利一发自己的 react 脚手架 react-starter。
以后有时间再整个 koa 后台的 starter,graphql 的,ssr 的。。。
在工作中开发,代理技术对于开发环境是不可避免的,小到入职时配置 VPN,再到开发环境中通过代理使用线上 API,通过代理拦截 App 请求,合理的代理应用对于开发来说经常会有事半功倍的作用。这里记录一下我在工作中代理的运用。
我这里用的使用的是由阿里巴巴开源的基于 nodejs 的代理工具— anyproxy,优点是支持 https,使用 nodejs 作为配置文件,学习成本低,缺点是配置 API 看起来太老,连 promise 都不支持,大公司的开源项目不知道什么时候会挂刚上了官网,4.0 beta 已经开始支持 promise 了。
Android 5.0 以下可以使用 DroidProxy 直接修改 wifi 代理配置,但是 5.0 以上更新了安全策略,只能用开 VPN 的了。我这里用的是虽然界面很丑,但是好得能用的 Drony. (以上 APK 可以去 https://apkpure.com搜索下载)。虽然占用了 VPN,不过一般电脑上各种代理和 VPN 都是开启状态,因此手机上还是能走电脑上的代理和 VPN 的。
Drony 和 connectbot 的 ssh 端口转发冲突,导致无法代理 dns 访问电脑 vpn 的内网,localproxy chains 相关配置未测试..
/**
* /js/lib/flexrem.js
*
*/
$inital-rem-size: 100px !default;
$design-width: 375px !default;
html {
font-size: $inital-rem-size / $design-width * 320px;
}
@each $width in (320px, 360px, 400px, 414px, 480px, 500px, 650px) {
@media only screen and (min-width: #{$width}) {
html {
font-size: $inital-rem-size / $design-width * $width;
}
}
}
@function px2rem($px) {
@if unitless($px) { // 不管带不带单位都可以
$px: $px * 1px;
}
@return $px / $inital-rem-size * 1rem;
}
/**
*
* 根据屏幕宽度自动设置html的fontSize, 使rem的大小自适应
* usage:
* dui.flexrem({
* //设计稿宽度
* designWidth: <number>, initial: 375
* //rem 初始像素值,initial: 100
* //html的fontSize = (opts.initRem/opts.designWidth*winWidth)+'px'
* initRem: <number>,
* //用来计算的最大的 winWidth, initial: 640
* maxWinWidth: <number>
* //用来计算的最小的 winWidth, initial: 320
* minWinWidth: <number>,
* })
*
* 由于android webview 偶尔会在 document.load 之后识别 viewport 导致 window.innerWidth 发生变化, 这段 js 需要在 window.onload 后运行,因此还需要配合 css 使加载前页面也能正确显示
*
*
* $inital-rem-size: 100px; // 默认值
* $design-width: 375px;// 默认值
* @import '/css/card/widgets/_flexrem.scss';
*
* width: @px2rem(12)rem; => 12/100 = 0.12rem
*
*/
!(function(win, doc) {
var dui = window.dui || (window.dui = {}),
timer = null,
firstCalled = true,
defaults = {
designWidth: 375,
initRem: 100,
maxWinWidth: 640,
minWinWidth: 320,
},
evts = 'onorientationchange' in win ? ['orientationchange', 'resize'] : ['resize'];
if (dui.flexrem !== undefined) {
return console.error('flexrem.js shouldn\'t be called twice!!')
}
/**
* auto set html's fontSize to make rem flexable
* @param {object} opts
* {
* //设计稿宽度
* designWidth: <number>, initial: 375
* //rem 初始像素值,initial: 100
* //html的fontSize = (opts.initRem/opts.designWidth*winWidth)+'px'
* initRem: <number>,
* //用来计算的最大的 winWidth, initial: 960
* maxWinWidth: <number>
* }
* @return
*/
dui.flexrem = function(opts) {
if(!firstCalled) console.error('flexrem() can only be called once!');
firstCalled =false
var options = Object.assign({}, defaults, opts)
for (var i = 0; i < evts.length; i++) {
win.addEventListener(evts[i], function() {
clearTimeout(timer);
timer = setTimeout(setFontSize, 300);
}, false);
}
win.addEventListener("pageshow", function(e) {
if (e.persisted) {
clearTimeout(timer);
timer = setTimeout(setFontSize, 300);
}
}, false);
// 初始化
setFontSize();
function setFontSize() {
var winWidth = window.innerWidth || window.clientWidth;
winWidth = Math.min(winWidth, options.maxWinWidth)
winWidth = Math.max(winWidth, options.minWinWidth)
var size = (winWidth / options.designWidth) * options.initRem;
doc.documentElement.style.fontSize = size + 'px';
}
}
function toType(obj) {
return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
if (typeof Object.assign != 'function') {
Object.assign = function (target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};
}
}(window, document));
把xx.crt
文件拷贝到 /usr/local/share/ca-certificates/
然后运行
sudo update-ca-certificates
然后就可以了