Mac 和 Win 下的微信双开/多开

Win

微信的路径根据各自需要改:

@ECHO OFF
start /d "C:\Program Files (x86)\Tencent\WeChat\" WeChat.exe
start /d "C:\Program Files (x86)\Tencent\WeChat\" WeChat.exe
exit

把文件保存成 xxx.bat,双击运行即可。原理就是趁着系统还没反应过来多开几个微信实例。

如果想多开几个,把 start 那行多写几遍就可以了。

Mac

echo "nohup /Applications/WeChat.app/Contents/MacOS/WeChat >/dev/null 2>&1 &" > ~/Desktop/WeChat.command
chmod +x ~/Desktop/WeChat.command

双击桌面的WeChat.command文件即可。

Mac下还有相关的插件可以使用,比如这个 A dynamic library tweak for WeChat macOS

image-20230922112248840

ps: 这个插件还能防撤回

image-20230922131611959

Pps: 如果注入出错,可以尝试换一个终端。系统弹出允许提示有时候没法显示,就会导致注入出错。

image-20231003上午01546274


laravel nova 的一些资源和几个常见问题

最近使用 nova 比较多,整理了一些常用的资源链接和几个我遇到的问题:

移动端自适应包

这个插件可以让 3.0 及 更早的 nova 适应手机上的显示。https://github.com/gregoriohc/laravel-nova-theme-responsive

当然自动4.0官方支持响应式后就不再更新了。我目前还没有升级的需要,就一直用着3.x了。

composer require gregoriohc/laravel-nova-theme-responsive

image-20221128午前113207562

升级

可把我难住了:

compose.json里添加:

    "repositories": [
        {
            "type": "path",
            "url": "./src-nova"
        }
    ],

解压官方压缩包到目录 ./src-nova

composer update "laravel/nova @3.32" --ignore-platform-reqs

laravel nova 不显示资源

好久没用了,发现怎么不会用了,不显示资源。reddit上一个答案解释了原因: 需要关闭认证:

https://nova.laravel.com/docs/3.0/resources/authorization.html#disabling-authorization

/**
 * Determine if the given resource is authorizable.
 *
 * @return bool
 */
public static function authorizable()
{
    return false;
}

参考资料


在 Mac M1 上安装 selenium

自从主力机换成 M1 后,就很少开docker了,很多容器都没有做arm架构的镜像。我常用的 selenium 也是,可叹。最后还是裸着安装了。以前在这篇文章里折腾过本地安装《selenium 裸安装备忘》,这次也是类似的操作,在本篇文章里记录一下。

一、安装java

brew install java

image-20221117午後13156478

image-20221117午後13232702

export PATH="/opt/homebrew/opt/openjdk/bin:$PATH"
alias java="/opt/homebrew/opt/openjdk/bin/java

image-20221117午後32601808

我发现 Mac 下的PATH有问题,在 zshrc 里改的不符合想法,系统的PATH还是在前面,我担心这样会有问题,遂直接改了这个文件 /etc/paths

二、安装chromedriver

先去官网下载 Chrome 版本对应的Chromedriver:https://chromedriver.chromium.org/downloads,扔到 path 对应的目录里。这里我扔到 ~/bin 目录下

image-20221117午後70447004

Mac 下允许执行权限,设置->安全 里:

Screenshot 8

三、安装selenium

官方地址:https://www.selenium.dev/downloads/

我下载了目前最新的 4.6.0版本:

image-20221125午後45446075

然后运行:

java -jar bin/selenium-server-4.6.0.jar standalone --host 100.100.100.9 --port 14444

IP 端口根据各自的需要配置了。

image-20221117午後72428922

看到日志显示 找到driver 就说明已经运行成功了。

尝试调用,看到输出了:

image-20221125午後45927768

16:57:45.003 INFO [LocalDistributor.newSession] - Session request received by the Distributor:
 [Capabilities {browserName: chrome, chromeOptions: {args: [--no-sandbox, window-size=1080x1920, --disable-gpu, --hide-scrollbars, --disable-extensions, start-maximized, --lang=zh-cn, --accept-lang=zh-cn, --arc-disable-locale-sync, --override-language-detection, --disable-dev-shm-usage]}, platform: ANY}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [--no-sandbox, window-size=1080x1920, --disable-gpu, --hide-scrollbars, --disable-extensions, start-maximized, --lang=zh-cn, --accept-lang=zh-cn, --arc-disable-locale-sync, --override-language-detection, --disable-dev-shm-usage]}}]
Starting ChromeDriver 107.0.5304.62 (1eec40d3a5764881c92085aaee66d25075c159aa-refs/branch-heads/5304@{#942}) on port 43558
Only local connections are allowed.
Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
ChromeDriver was started successfully.

16:57:46.590 WARN [ProtocolHandshake.createSession] - Support for Legacy Capabilities is deprecated; You are sending the following invalid capabilities: [chromeOptions, platform]; Please update to W3C Syntax: https://www.selenium.dev/blog/2022/legacy-protocol-support/

16:57:46.606 INFO [LocalNode.newSession] - Session created by the Node. Id: d0aff398d25ed2e6c16003eb81336a8b, Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 107.0.5304.110, chrome: {chromedriverVersion: 107.0.5304.62 (1eec40d3a576..., userDataDir: /var/folders/k1/qfq95df561b...}, goog:chromeOptions: {debuggerAddress: localhost:49491}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: ANY, proxy: Proxy(), se:cdp: http://localhost:49491, se:cdpVersion: 107.0.5304.110, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}

16:57:46.611 INFO [LocalDistributor.newSession] - Session created by the Distributor. Id: d0aff398d25ed2e6c16003eb81336a8b
 Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 107.0.5304.110, chrome: {chromedriverVersion: 107.0.5304.62 (1eec40d3a576..., userDataDir: /var/folders/k1/qfq95df561b...}, chromeOptions: {args: [--no-sandbox, window-size=1080x1920, --disable-gpu, --hide-scrollbars, --disable-extensions, start-maximized, --lang=zh-cn, --accept-lang=zh-cn, --arc-disable-locale-sync, --override-language-detection, --disable-dev-shm-usage]}, goog:chromeOptions: {debuggerAddress: localhost:49491}, networkConnectionEnabled: false, pageLoadStrategy: normal, platform: ANY, platformName: ANY, proxy: Proxy(), se:bidiEnabled: false, se:cdp: ws://100.100.100.9:14444/se..., se:cdpVersion: 107.0.5304.110, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:credBlob: true, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}

四、番外-容器化

这两个命令是可以跑起来了:

docker run -d -p 4444:4444 --name selenium-hub selenium/hub:latest 
docker run -d --link selenium-hub:hub -e SE_EVENT_BUS_HOST=hub -e SE_EVENT_BUS_SUBSCRIBE_PORT=4443 -e SE_EVENT_BUS_PUBLISH_PORT=4442 -p 5900:5900 --name selenium-node-chrome-vnc selenium/node-chrome:latest 

因为 arm下还没有相关的镜像,虽然容器可以运行

image-20231231142107145

image-20231231142135144

但是无法拉起chrome,用代码拉起chrome一定报错

image-20231231142327309

其实如果直接在vnc里启动chrome,也可以注意到,chrome是无法启动的:

image-20231231142419187

正常情况下应该是这个样子:

image-20231231184340328

所以如果有需要远程运行的话, 找一台x86的机器运行即可。我也是没想到,我x86的MacBook Air还能发挥余热。

docker run -d \
  --name selenium-chrome-1 \
  --restart always \
  --network bridge \
  -p 5901:5900 \
  -p 4445:4444 \
  -v /dev/shm:/dev/shm \
  selenium/standalone-chrome-debug

docker run -d \
  --name selenium-chrome-2 \
  --restart always \
  --network bridge \
  -p 5902:5900 \
  -p 4446:4444 \
  -v /dev/shm:/dev/shm \
  selenium/standalone-chrome-debug

docker run -d \
  --name selenium-chrome-3 \
  --restart always \
  --network bridge \
  -p 5903:5900 \
  -p 4447:4444 \
  -v /dev/shm:/dev/shm \
  selenium/standalone-chrome-debug

参考资料


pandas 操作 excel 备忘

以下链接是我边搜边写 pandas 代码的过程,记录一下。写完手头需求之后基本也懂了。

总结性内容:

细节操作:

我的test代码:

import pandas as pd
import yaml
import datetime

class Project():
    def __init__(self,name):
        self.name = name

    @staticmethod
    def columns():
        return {
            'name':'项目名称',
            'requestCount':'需求总数',
            "requestDoneCount":'需求完成数', 
            'percentRequestCount':'需求完成率',
            'requestKpiCount':"一个月前需求总数",
            "requestKpiDoneCount":'一个月前需求完成数',
            'percentKpiRequestCount':'一个月前需求完成率',
            'director':'主责人',
        }

    def doneFlag():
        return ("a","b","c","d","e")
    def directorOverwrite():
        return {
            "xxx平台":"无",
        }

def getProjectDict(df,now):
    ft = df[df.主责中心 == "kelu.org中心"]
    ftProjects = ft.groupby("blog")
    datetimeNow=datetime.datetime.strptime(now,"%Y%m%d")
    kpiTime=datetimeNow.replace(month=datetimeNow.month - 1).strftime("%Y-%m-%d")

    projectDict = {}

    for mainSys, sysReqs in ftProjects:
        project = Project(mainSys)
        project.requestCount = sysReqs.shape[0]
        sysReqsDone = sysReqs[sysReqs['状态'].isin(Project.doneFlag())]
        project.requestDoneCount = sysReqsDone.shape[0]
        if(project.requestCount == 0):
            project.percentRequestCount = 1
        else:
            project.percentRequestCount = round((float(project.requestDoneCount) / project.requestCount), 4)

        sysReqs['需求创建时间'] = pd.to_datetime(sysReqs['需求创建时间'])
        sysReqsKpi = sysReqs[sysReqs['需求创建时间'] < kpiTime]
        project.requestKpiCount = sysReqsKpi.shape[0]
        sysReqsKpiDone = sysReqsKpi[sysReqsKpi['状态'].isin(Project.doneFlag())]
        project.requestKpiDoneCount = sysReqsKpiDone.shape[0]
        if(project.requestKpiCount == 0):
            project.percentKpiRequestCount = 1
        else:
            project.percentKpiRequestCount = round((float(project.requestKpiDoneCount) / project.requestKpiCount), 4)

        if mainSys in Project.directorOverwrite():
            project.director = Project.directorOverwrite()[mainSys]
        else:
            for _, reqData in sysReqs.iterrows():
                project.director = reqData.主责人
                break

        project.reqs = sysReqs

        projectDict[mainSys] = vars(project)
        # print(type(projectDict[mainSys]))

    return projectDict

def exportMainSheet(projectDict):
    df=pd.DataFrame(projectDict).transpose()
    newDf=df[[
        'name',
        'requestCount',
        "requestDoneCount",
        'percentRequestCount',
        'requestKpiCount',
        'requestKpiDoneCount',
        'percentKpiRequestCount',
        'director'
        ]].sort_values(by=['percentKpiRequestCount','requestKpiCount'],ascending=False)

    # 处理输出内容
    newDf.reset_index(drop=True, inplace=True)
    newDf.index = newDf.index + 1
    newDf.loc['合计'] = newDf[['requestCount',"requestDoneCount",'requestKpiCount','requestKpiDoneCount']].sum()
    newDf.loc['合计','percentRequestCount'] = round((float(newDf.loc['合计','requestDoneCount']) / newDf.loc['合计','requestCount']), 4)
    newDf.loc['合计','percentKpiRequestCount'] = round((float(newDf.loc['合计','requestKpiDoneCount']) / newDf.loc['合计','requestKpiCount']), 4)

    newDf[u'percentRequestCount']= newDf['percentRequestCount'].apply(lambda x:format(x, '.2%'))
    newDf[u'percentKpiRequestCount']= newDf['percentKpiRequestCount'].apply(lambda x:format(x, '.2%'))

    newDf.rename(columns=Project.columns(),inplace=True)

    return newDf

def main():
    now='20221115'
    inputFilename='input'+now+'.xlsx'
    outputFilename='output'+now+'.xlsx'

    df = pd.read_excel(inputFilename,sheet_name='需求列表')
    projectDict = getProjectDict(df,now)
    # print(yaml.dump(projectDict,allow_unicode=True))

    with pd.ExcelWriter(outputFilename) as writer:
        exportMainSheet(projectDict).to_excel(writer, sheet_name="汇总")
        directorDict = {}
        for projectItem in projectDict.values():
            if(projectItem['percentRequestCount'] < 1):
                sysReqs = projectItem['reqs']
                reqsNotDone = sysReqs[~sysReqs['状态'].isin(Project.doneFlag())]
                if projectItem['director'] in directorDict:
                    reqsNotDone = pd.concat([reqsNotDone,directorDict[projectItem['director']]])
                directorDict[projectItem['director']] = reqsNotDone

        for director, reqsNotDone in directorDict.items():
            reqsNotDone.reset_index(drop=True, inplace=True)
            reqsNotDone.index = reqsNotDone.index + 1
            reqsNotDone.to_excel(writer, sheet_name=director)

if __name__=="__main__":
    main()

iterm2 给台前调度Stage Manager留出空间

今年Mac OS 更新到了 Ventura 13.0,新增了一个台前调度Stage Manager功能,如下图:

image-20221110午前104256477

我 iterm2 快捷键默认是全屏占满,这样会把左边的 stage 顶掉,不太舒服,遂需要把它的左边部分露出来。

配置方式呢如下,Preference->Profile->Default->Window,将 Columns 改成合适的值,同时把Style 改成“右侧”,如下图:

image-20231018165937180

最终实现的效果如下:

image-20221110午後54219171

我其他的配置可以参考15年的这两篇文章:https://blog.kelu.org/category/tags/iterm2.html