昨天下了一个软件,需要jdk8版本的,我之前开发是用的openjdk11版本的。就想找找怎么安装多个版本的,我之前知道可以知道path环境变量改变,就想找找有没有类似多版本管理的软件。 然后找到一个系统级别的update-alternatives,然后执行update-alternatives --config java,可以进行java版本的选择,我发现我之前安装过java8的jre了版本了。也没有切换,直接复制路径去执行的jar包。 然后就研究了一下update-alternatives 命令。配置文件目录为/var/lib/dpkg/alternatives/java 涉及的原理就是通过文件软链接来实现版本的切换。 ls -alh /usr/bin/java lrwxrwxrwx 1 root root 22 7月 22 2019 /usr/bin/java -> /etc/alternatives/java ls -alh /etc/alternatives/java lrwxrwxrwx 1 root root 43 7月 22 2019 /etc/alternatives/java -> /usr/lib/jvm/java-11-openjdk-amd64/bin/java 安装软件的时候会调用update-alternatives,看文档是在执行postinst 和prerm脚本的时候,自动设置的时候会根据权重选择一个版本或者软件。

Continue

先说一下pyenv的安装方式,只有两步,第一步是将github项目clone到目录,第二步是添加环境变量。所以pyenv完全可以离线安装,比如操作系统版本一致的时候,直接把装好的pyenv环境和virtualenv环境复制到目标系统就可以了。然后添加一下环境变量。 我之前安装过pyenv了,更新pyenv进入pyenv目录后,执行git pull。 然后我复制了一份新的代码,改变环境变量,切换到新pyenv目录。然后卸载之前直接安装的python版本。pyenv uninstall 3.7.3 进入.pyenv_bak,mkdir cache.将源码包放到cache目录下。 进入.pyenv_bak/plugins/python-build/share/python-build目录,编辑3.7.3文件 #require_gcc prefer_openssl11 export PYTHON_BUILD_CONFIGURE_WITH_OPENSSL=1 install_package "openssl-1.1.0j" "https://www.openssl.org/source/old/1.1.0/openssl-1.1.0j.tar.gz#31bec6c203ce1a8e93d5994f4ed304c63ccf07676118b6634edded12ad1b3246" mac_openssl --if has_broken_mac_openssl install_package "readline-8.0" "https://ftpmirror.gnu.org/readline/readline-8.0.tar.gz#e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461" mac_readline --if has_broken_mac_readline if has_tar_xz_support; then install_package "Python-3.7.3" "https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tar.xz#da60b54064d4cfcd9c26576f6df2690e62085123826cff2e667e72a91952d318" ldflags_dirs standard verify_py37 copy_python_gdb ensurepip else install_package "Python-3.7.3" "https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz#d62e3015f2f89c970ac52343976b406694931742fbde2fed8d1ce8ebb4e1f8ff" ldflags_dirs standard verify_py37 copy_python_gdb ensurepip fi 改成 install_package "Python-3.7.3" "/root/.pyenv_bak/cache/Python-3.7.3.tar.xz" ldflags_dirs standard verify_py37 copy_python_gdb ensurepip 安装 pyenv install 3.7.3 安装完成后执行pyenv virtualenvwrapper,我发现需要重新安装这个插件,不知道为什么。我之前是安装了的,可能版本问题。 然后基本就可以了。virtualenv也是可以直接复制的,所以基本可以复制分发了。

Continue

主要看pymain_run_filename,是文件执行pymain_open_filename,不是文件赋值fp = stdin,最后执行pymain_run_file(fp, pymain->filename, cf)。看这里应该交互和文件执行都在这一个里边的。 pymain_open_filename就是打开文件返回句柄。 pymain_run_file文件里,主要就是调用PyRun_AnyFileExFlags。下面应该与main.c没关系了,主要在Python/pythonrun.c里了. pymain_repl里调用 PyRun_AnyFileFlags,然后也是调用的PyRun_AnyFileExFlags。 PyRun_AnyFileExFlags里, Py_FdIsInteractive判断是否是交互模式,如果是调用PyRun_InteractiveLoopFlags,里边有个do,这个不看了。如果不是调用PyRun_SimpleFileExFlags, 先调用PyImport_AddModule,interp->modules里插入了__main__,对我没啥用。maybe_pyc_file判断是否是pyc文件,比较了文件后缀,MagicNumber. MAGIC_NUMBER是在Lib/importlib的_bootstrap_external.py文件里定义的,直接写在python文件里了。 如果像pyc文件,关闭文件句柄,重新打开文件,然后调用set_main_loader,再调用run_pyc_file。 如果不像pyc文件,调用PyRun_FileExFlags。 set_main_loader中通过loader_name,从importlib/_bootstrap_external中获取loader,源码为SourceFileLoader,pyc为SourcelessFileLoader,设置到__loader__ run_pyc_file,先比较MagicNumber是否匹配,然后PyMarshal_ReadLastObjectFromFile读取文件,其中的就不看了,不关心。PyEval_EvalCode应该是执行代码了,这个也不看了。 然后就完结了。 import 相关 第一篇里边的pymain_init_sys_path,调用pymain_get_importer,然后调用PyImport_GetImporter,然后调用get_path_importer,然后从path_hooks里找合适的import的方法进行导入 pymain_update_sys_path更新sys.path config_init_module_search_paths里有个Py_GetPath(,这里比较乱,调用了几次_PyPathConfig_Init,我也没仔细看。_PyPathConfig_Calculate里应该是初始化的path,没仔细看。 第三方库的搜索路径添加在initsite,导入Lib/site.py模块,执行addusersitepackages里添加的

Continue

按照上一篇的流程 Modules/main.c里, pymain_main里pymain_init里的pymain_cmdline,是解析参数的。 初始化一个_PyCmdline,暂存参数的 line464 typedef struct { wchar_t **argv; int nwarnoption; /* Number of -W options */ wchar_t **warnoptions; /* -W options */ int nenv_warnoption; /* Number of PYTHONWARNINGS options */ wchar_t **env_warnoptions; /* PYTHONWARNINGS options */ int print_help; /* -h, -? options */ int print_version; /* -V option */ int bytes_warning; /* Py_BytesWarningFlag, -b */ int debug; /* Py_DebugFlag, -b, PYTHONDEBUG */ int inspect; /* Py_InspectFlag, -i, PYTHONINSPECT */ int interactive; /* Py_InteractiveFlag, -i */ int isolated; /* Py_IsolatedFlag, -I */ int optimization_level; /* Py_OptimizeFlag, -O, PYTHONOPTIMIZE */ int dont_write_bytecode; /* Py_DontWriteBytecodeFlag, -B, PYTHONDONTWRITEBYTECODE */ int no_user_site_directory; /* Py_NoUserSiteDirectory, -I, -s, PYTHONNOUSERSITE */ int no_site_import; /* Py_NoSiteFlag, -S */ int use_unbuffered_io; /* Py_UnbufferedStdioFlag, -u, PYTHONUNBUFFERED */ int verbosity; /* Py_VerboseFlag, -v, PYTHONVERBOSE */ int quiet_flag; /* Py_QuietFlag, -q */ const char *check_hash_pycs_mode; /* --check-hash-based-pycs */ #ifdef MS_WINDOWS int legacy_windows_fs_encoding; /* Py_LegacyWindowsFSEncodingFlag, PYTHONLEGACYWINDOWSFSENCODING */ int legacy_windows_stdio; /* Py_LegacyWindowsStdioFlag, PYTHONLEGACYWINDOWSSTDIO */ #endif } _PyCmdline; 然后调用cmdline_get_global_config,设置默认参数,默认参数都在 Python/pylifecycle.c 全为0.后面的cmdline_set_global_config是设置全局值的。两个是一对 然后调用pymain_cmdline_impl,里面调用pymain_read_conf,看了一下,主要在函数pymain_parse_cmdline_impl里面。其他的就不看了。 cmdline_get_env_flags是从环境拿值设置参数的。 pymain_init_core_argv是设置-c-m俩参数 没想到比较简单,没有细看,看的这些基本能达到目的了。有需要再补充

Continue

看Makefile.pre.in文件,入口函数在Programs/python.c文件里,发现main函数。 只调用的Modules/main.c的_Py_UnixMain函数,这里面初始化了_PyMain,用来保存参数,然后调用pymain_main 先调用pymain_init,后调用pymain_run_python,最后调用pymain_free. pymain_init里,初始化_PyCoreConfig,大体看是pyvm的一些参数,先不关心。然后调用pymain_cmdline,大体看是解析参数的,不关心。pymain_init_stdio设置了stdin_is_interactive的值,这个可能有用,先记录。然后调用_Py_InitializeCore,里边调用_Py_InitializeCore_impl,里边各种初始化,不跟进去看了。 里边调用了一个_PyImport_Init,没啥,_PyImportHooks_Init,初始化了几个sys的参数,但是都是空值, sys.meta_path, sys.path_importer_cache,sys.path_hooks,这几个有用。 _Py_InitializeCore_impl最后调用了一个initimport(, sys.modules不知道在哪初始化的,可能有用,先不找了。importlib的导入,然后是_PyImportZip_Init. _PyImportZip_Init在Python/import.c里,导入zipimport,path_hooks里加入了一个zipimport.zipimporter。搞定 回到 pymain_init, 最后调用了 pymain_init_python_main 和pymain_init_sys_path. pymain_init_python_main调用_Py_InitializeMainInterpreter好像仅仅是重新设置了一下参数,这里没看懂,从自己复制了参数设置了args,有设置了一遍。没啥用先不管了。 pymain_init_sys_path这个看名字是要找的了, 第一个是zip或者目录导入,这个有用,记录一下,暂时不会用。从参数中获取sys.path的配置,最后调用pymain_update_sys_path插入到sys.path里边 pymain_run_python中,先调用pymain_header,pymain_import_readline,pymain_run_command,pymain_run_module, pymain_run_filename, pymain_repl. pymain_header,如果是交互模式,打印了版本和操作系统。可以查到版本信息在Include/patchlevel.h pymain_import_readline 为交互模式导入readline模块。pymain_run_command,直接执行的代码。pymain_run_module执行模块的. pymain_run_filename 执行文件的。 pymain_repl 解析器模式 这部分就基本看完了,下边要单独看一下,启动参数解析的地方

Continue

最近总结了两条想当然造成的麻烦,虽然问题不太大,但是值得总结。 一个是执行linux命令的时候,开始用一个算是知道的命令,执行也没问题。然后测试需要执行多遍,脑子一抽,想起一个别的更短的命令,然后也没查,想当然的猜了一下参数。结局就是教训,虽然没有什么损失,但是当时就反思了。不知道是什么造成了我的想当然。 第二个是今天,之前搞的不是我负责的java的项目,前后捋了一下。那个组负责的人来找我问我每个页面都是干什么的,前端不是我写的,跟原型出入很大,他们也不看原型。总的来说就是好像总想嘲笑我,问的我很烦,我就说把我之前给前端的文档发给他。 后来又来问我状态转换按钮的事,我想当然的说了一个就是删除请求,我没物理删除。然后他回去跟别人说了一通,回来又找我,让我在测试环境测试一下,让我证明一下,多选删除,不会删除,那个页面还会有数据。然后我竟然谨慎了,没有操作。然后他又让我新加一个删除,我试了一下,确实物理删除了。然后马上看代码,确实是物理删除。状态更新是走的更新接口。 一个主要是代码写的时间比较久了,第二个就是我之前的python项目非特殊都是软删除,所以这里以为我也写了软删除。我仔细回想,就是刚写java,边学的,直接调用删除接口确实方便,然后状态只标记是否禁用,就会好写很多。不然按之前的逻辑需要三个状态,还要单独写删除的更新接口。然后我就想当然的说了个删除是更新操作。 虽然不是大事,但是那人一直嘲讽的口气,我虽然代码没毛病,但是就这样就被他嘲讽。还套路我,说 你说的删除数据库是update操作是吧,我说是。然后又让我全选删除,让我证明一下。说白了他已经试过了,然后不说,就等你自己出丑。无论怎么说也是我先说错了,但是这人品质极差。从别的组调到这个项目,自己开始还很牛逼,好像项目离开他不行。那反过来想,你在之前的项目真的是举足轻重的地位,能让你到这里来吗。。

Continue

这几天忙着写文档,一直看的线上环境的系统。今天启动本地测试环境,发现登录不成功。排查问题发现登录成功后,之后的请求没有携带cookie。然后我就仔细看了一下登录请求的参数。 发现在chorme header头的cookie里有一个黄色的小叹号,发现问题了。 this set-cookie didn't specify a "SameSite" attribute,然后变成默认Lax。(不能复制,懒得打英文了) 然后我搜索了一下Samesite定义,有三个值,None, Lax,Strict.这个参数是防止跨站攻击用的,因为测试环境,所以最方便就是跨站调试了。 然后我搜了一下flask源码,发现有这个设置,配置了一下发现不管用。然后放弃了。 找了一下怎么关闭chrome的这个选项,虽然别的网站可能有一点风险。自己调试的时候会方便点。 chrome://flags/#same-site-by-default-cookies chrome://flags/#cookies-without-same-site-must-be-secure 这两项设置为Disabled,并重启浏览器

Continue

搞了一个像素游戏,很小的游戏。里边的文字也不多,找个像素字体太费劲,还有版权什么的信息,就想之前看过字体数据转像素矩阵的代码。搜了一下,发现直接有点阵字体,找了代码试了一下,完全可用。 我将字体转成像素矩阵后,可以直接按像素大小把字给画出来,非常方便了,就是计算稍微多一点。 HZK16字库是符合GB2312国家标准的16×16点阵字库,HZK16的GB2312-80支持的汉字有6763个,符号682个。其中一级汉字有 3755个,按声序排列,二级汉字有3008个,按偏旁部首排列。 我们在一些应用场合根本用不到这么多汉字字模,所以在应用时就可以只提取部分字体作为己用。 HZK16字库里的16×16汉字一共需要256个点来显示,也就是说需要32个字节才能达到显示一个普通汉字的目的。 我们知道一个GB2312汉字是由两个字节编码的,范围为0xA1A1~0xFEFE。A1-A9为符号区,B0-F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。 下面以汉字「我」为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。 前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到「我」在hzk16库中的位置就必须得到它的区码和位码。 区码:汉字的第一个字节-0xA0,因为汉字编码是从0xA0区开始的,所以文件最前面就是从0xA0区开始,要算出相对区码 位码:汉字的第二个字节-0xA0 这样我们就可以得到汉字在HZK16中的绝对偏移位置:offset = (94*(区码-1)+(位码-1))*32。 注解: 区码减1是因为数组是以0为开始而区号位号是以1为开始的 (94*(区号-1)+位号-1)是一个汉字字模占用的字节数 最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示) #include int main(void) { FILE* fphzk = NULL; int i, j, k, offset; int flag; unsigned char buffer[32]; unsigned char word[3] = "我"; unsigned char key[8] = { 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 }; fphzk = fopen("hzk16", "rb"); if(fphzk == NULL){ fprintf(stderr, "error hzk16\n"); return 1; } offset = (94*(unsigned int)(word[0]-0xa0-1)+(word[1]-0xa0-1))*32; fseek(fphzk, offset, SEEK_SET); fread(buffer, 1, 32, fphzk); for(k=0; k<32; k++){ printf("%02X ", buffer[k]); } for(k=0; k<16; k++){ for(j=0; j<2; j++){ for(i=0; i<8; i++){ flag = buffer[k*2+j]&key[i]; printf("%s", flag?"●":"○"); } } printf("\n"); } fclose(fphzk); fphzk = NULL; return 0; } 使用Python读取并显示的过程如下: 根据中文字符获取GB2312编码 通过GB2312编码计算该汉字在点阵字库中的区位和码位 通过区位和码位计算在点阵字库中的偏移量 基于偏移量获取该汉字的32个像素存储字节 解析像素字节获取点阵坐标信息 在对应的坐标显示信息位。如该像素点是否显示点亮 #!/usr/bin/python #encoding: utf-8 import binascii BYTE_COUNT_PER_FONT = 32 BYTE_COUNT_PER_ROW = 2 RECT_HEIGHT = 16 RECT_WIDTH = 16 KEYS = [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01] class FontRender(object): def __init__(self, font_file="hzk16s", rect_height=RECT_HEIGHT, rect_width=RECT_WIDTH, byte_count_per_row=BYTE_COUNT_PER_ROW): self.font_file = font_file self.rect_height = rect_height self.rect_width = rect_width self.byte_count_per_row = byte_count_per_row self.__init_rect_list__() def __init_rect_list__(self): self.rect_list = [] * RECT_HEIGHT for i in range(RECT_HEIGHT): self.rect_list.append([] * RECT_WIDTH) def get_font_area_index(self, txt, encoding='utf-8'): if not isinstance(txt, unicode): txt = txt.decode(encoding) gb2312 = txt.encode('gb2312') hex_str = binascii.b2a_hex(gb2312) area = eval('0x' + hex_str[:2]) - 0xA0 index = eval('0x' + hex_str[2:]) - 0xA0 return area, index def get_font_rect(self, area, index): offset = (94 * (area-1) + (index-1)) * BYTE_COUNT_PER_FONT btxt = None with open(self.font_file, "rb") as f: f.seek(offset) btxt = f.read(32) return btxt def convert_font_rect(self, font_rect, ft=1, ff=0): for k in range(len(font_rect) / self.byte_count_per_row): row_list = self.rect_list[k] for j in range(self.byte_count_per_row): for i in range(8): asc = binascii.b2a_hex(font_rect[k*2+j]) asc = eval('0x' + asc) flag = asc & KEYS[i] row_list.append(flag and ft or ff) def render_font_rect(self, rect_list=None): if not rect_list: rect_list = self.rect_list for row in rect_list: for i in row: if i: print '●', else: print '○', print def convert(self, text, ft=None, ff=None, encoding='utf-8'): if not isinstance(text, unicode): text = text.decode(encoding) for t in text: area, index = self.get_font_area_index(t) font_rect = self.get_font_rect(area, index) self.convert_font_rect(font_rect, ft=ft, ff=ff) def get_rect_info(self): return self.rect_list if '__main__' == __name__: text = u'图麟' fr = FontRender() fr.convert(text, ft='/static/*', ff=0) # print fr.get_rect_info() fr.render_font_rect()

Continue

查询语句里有个子查询,有个括号,然后就报错 unexpected token:( 发现这个异常没法查问题,就找了找跟JpaRepository子查询相关的。 有两种解决方法: 一种是@Query(value="select * from user where name like %?1" ,nativeQuery=true) 添加一个nativeQuery的参数 第二种方法是支持的是JPQL,但是我写的那个sql是不支持的。害

Continue

最近在考虑自己职业长远发展的问题,有时候想起来就会思考一会儿,也是零碎的东西。标题是个瞎起的题目,只是想起之前有个领导送了一本书,讲程序员的软技能的,好像关于职场发展的,我也没看,倒是现在可用翻出来看看了。 我觉得我做事属于很果断的了,但是发现思想上还是很多纠结的事情,而回过头想想这些纠结的事,又不值得一提,不如一步一步做来的实际。自己跟自己的思想pk了无数次,最后就是说服了自己这条路不行,然后领选一条,又是自己不喜欢的,或者又是一轮pk又不行。这个喜不喜欢也是个问题,就是应不应该选喜欢的,还是变成一个眼光看待。 我先自己定义一个: 硬技能就是属于完全技术上的技能了。这块想了很多,想去研究源码,然后自己实现简单的,自己就会去想这种东西做了没啥用,折腾了以后也不会做这方面的工作。然后其实细想,永远不做就是永远不会涉及这方面的工作。大部分都是想研究然后浅浅的研究研究,也并没有深入。广度现在变的很广,基本做啥,用啥都可以,但是从头去实现一个,不是不能做,但是一直会缺乏经验。所以这个在以后的发展很是问题。 软技能就是非技术上的技能,包括生活上的。生活上的我在培养一个运动爱好,选择了也正好是喜欢上的,就是游泳,但是这个没办法变成一个除了编程之外的技能。我之前想过的是,如果我放弃编程,我还有什么技能能维持生活呢。我可以去考一个教练证,然后去教游泳。但是总感觉自己的其他技能特别少,所以需要挖掘学习一下。 第二个是职场人与人打交道的技能,其中交流是一块,我现在更多的是发现我说话的语气,口气,存在很多问题,不知道为啥让别人很难接受。我感觉我说话直这个问题比较小,很多时候我能够考虑对方的立场,所以应该不是问题。说话直是一个表达很有效率的方式。还有一个就是表达不清楚的问题,我感觉不知道为啥,很多时候我说出来的东西别人理解错了,然后我还需要去解释,有时候还发现不知道什么词去解释。这个也许与我说话很少,很多时候想说却想不起来说什么词,,,这个只是交流的一个大问题,其他的虽然可能别人眼里不太正常,至少现在我觉得对我不会造成很大问题。 另一个交流方面的问题就是如果表现自己的问题,这个思考的比较久了。之前属于特别被动的,所以面试什么的也比较吃亏,工作上也还好,因为时间久了,总有表现的时间。这里以后需要学习一下,已经有方向,马上就开始学习了。 第三个是关于非技术技能的想法。以前只负责写代码,开发功能,拿不定的去问领导或者别人。不会去写产品文档,产品ppt。现在的项目需要很多的这种工作,可能是相比之前很多。我就有抵触的想法,感觉这种工作不会给我带来技术的提高,感觉是所有人都能做,只是做好比较难。感觉做了之后对以后的发展也没有太多帮助。这种思想想想也是极其危险,想着现在分工已经很细了,每个人应该负责自己最擅长的,但是这种你不去做永远不会去做,以后也不会知道你做的时候会遇到什么问题,学到什么东西。 第四个是关于学习硬技能和其他技能的时间问题。有时候会感觉学其他的是浪费时间,比如背单词,对看英文文档有点用,但总会有感觉在浪费时间。想看高数,总感觉看了可能白看,然后还逼的自己特别忙。如果这些时间拿来写游戏,看技术书,自己会不会有很大的提高。这块我更多的看中能不能给我的工资带来提高,却不是想的能不能给我人本身带来提高。而且不是特别的出于兴趣的出发点,所以也陷入的迷茫。这块以后还是得合理规划进度,不能想起来干这个两天,然后放下再干那个几天。

Continue